-
Notifications
You must be signed in to change notification settings - Fork 0
Convoi handles and iterators
These macros are defined in /utils/for.h and as far as I can tell they have no counterpart in the Standard code. Google searches for key parts of the code all lead back to Extended, so it appears that they were written especially for this fork.
The 'calls' to these macros (though not this header) appear to have been introduced by Christoph Mallon in the monster commit #b120fdc ([SVN](svn://tron.homeunix.org/simutrans/simutrans/trunk@5312 8aca7d54-2c30-db11-9de9-000461428c89)) (it might be a series or it might be that GitLens is struggling to differentiate branches). The macros themselves were introduced by Herr Mallon in commits #4edea71 and #96829aa. These were also commits from the SVN bridge, so they must have been for Standard. And they were indeed into utils/for.h
, so I am not sure where Standard moved them to (or how it replaced them).
Happily, this is one of the best-documented parts of the Simutrans code:
/* FOR(type, elem, container)
* FORX(type, elem, container, step)
*
* Iterate over container, which has type type, and optionally do step on every iteration.
* The current element is put into elem.
* elem can be
* - a plain variable name (x), which makes a copy of the element
* - a const copy (const x)
* - a reference (& x) or
* - a const reference (const& x).
*
* This simplifies the usual pattern
* for (vector<int>::iterator i = container.begin(), end = container.end(); i != end; ++i) {
* int& elem = *i;
* ...
* }
* to
* FOR(vector<int>, & elem, container) {
* ...
* }
*
* FORT()/FORTX() need to be used, if type is a dependent name.
*/
We can clearly see that the three parameters passed to FOR
are almost totally unrelated to the three statements required by C++'s for
syntax.
VSCode finds 573 references in 119 files, plus many more "inactive references", which appear to me to also be normal uses of these macros.
FOR (TYPE, ELEM, CONTAINER) SOURCE
FOR (vector_tpl<bridge_desc_t const*>, const i, matching§) bauer/brueckenbauer.cc#L167
FOR (vector_tpl<fabrik_t*>, const f, welt->get_fab_list()) bauer/fabrikbauer.cc#L82
FOR (vector_tpl<building_desc_t const*>, const desc, station_building ) bauer/hausbauer.cc#L326
FOR (road_network_plan_t, i, road_tiles) boden/grund.cc#L2423 §§
FOR (minivec_tpl<uint8>, const catg_index,line.is_bound() ? line->get_goods_catg_index():cnv->get_goods_catg_index()) gui/components/gui_line_network.cc#L266
FOR (slist_tpl<ware_t>, const ware, v->get_cargo(0)) gui/convoi_detail_t.cc#L1237
FOR (vector_tpl<convoihandle_t>, const cnv, welt->convoys()) gui/convoi_frame.cc#L225 <--USEFUL
FOR (vector_tpl<convoihandle_t>, const cnv, welt->convoys()) simhalt.cc#L5411 §§§
FOR (vector_tpl<convoihandle_t>, & i, line_managed_convoys) simline.cc#L670
FOR (vector_tpl<convoihandle_t>, const i, line_managed_convoys) simline.cc#L725
FOR (vector_tpl<convoihandle_t>, const i, line_managed_convoys) simline.cc#L787 Arrow operator
FOR (vector_tpl<convoihandle_t>, const i, line_managed_convoys) simline.cc#L899 Dot operator
FOR (vector_tpl<convoihandle_t>, const i, line_managed_convoys) simline.cc#L975
FOR (vector_tpl<convoihandle_t>, const cnv, welt->convoys()) gui/money_frame.cc#L925 Checks owner/player
§matching
needs further investigation. Is it a member function of vector_tpl
or specific to bridge_desc_t
??
§§ Another day, investigate whether this functin grund_t::fixup_road_network_plan
is connected with Extended's square cities, as it appears to delete diagonal roads.
§§§ Comment: iterate over all convoys
In contrast to FOR
, this is one of the worst documented parts of the codebase. The only 'comment' is the copyright notice. There is no convoihandle.cc
and the functional part of convoihandle_t.h
consists of 3 lines:
#include "tpl/quickstone_tpl.h"
class convoi_t;
typedef quickstone_tpl<convoi_t> convoihandle_t;
So convoihandle_t
is a type of the quickstone
template implementation for convoi_t
. Looking at that class in VSCode helpfully brings up simconvoi.h#L68
which says "Convoys can be referenced by handles, see halthandle_t". Unfortunately halthandle_t.h
is identical to convoihandle_t
apart from from the syllable halt
replace the syllables convoi
. But in simhalt.h#L118
's `haltestelle_t we find a private static member ??object:
/// List of all halts in the game.
static vector_tpl<halthandle_t> alle_haltestellen;
There doesn't seem to be a convoi_t
equivalent, though simconvoi.h
is a large file and I might have missed it or something has been lost in translation. However, I did discover (L872)
/**
* The handle for ourselves. In Anlehnung an 'this' aber mit
* allen checks beim Zugriff.
*/
convoihandle_t self;
EN: Based on 'this' but with all checks when accessing.
Time to summon our courage and look at quickstone_tpl
.
In tpl/quickstone_tpl.h
, "[a]n implementation of the tombstone pointer checking method. It uses a table of pointers and indices into that table to implement the tombstone system." A tombstone "is a structure that acts as an intermediary between a pointer and its target .... The pointer – sometimes called the handle – points only at tombstones and never to its actual target".
So we have:
handle → tombstone → convoi_t convoi object
The tombstone must be a pointer for this method to work (and in Simutrans appears to be contained in the private static member array declared by static T ** data
). But in principle the handle can be "an index or a pointer into a global array of tombstones (my emphasis). The relevant line in quickstone_tpl.h
is currently L45 as follows:
/**
* The index in the table for this handle.
* (only this variable is actually saved, since the rest is static!)
*/
uint16 entry;
So in Simutrans, the handle is a uint16. But is this handle the same as the convoi ID number displayed to the user? Because that would be easier for my purpose.
L173 appears to be the start of a constructor:
// creates handle with id, fails if already taken
quickstone_tpl(T* p, uint16 id)
Need to check where this is used and what is passed as id
. I wonder whether the typedef
in convoihandle_t.h
means that this can be called as convoihandle_t()
?
In simconvoi.cc#L3943
ff., we have this:
// we want persistent convoihandles so we can keep dialogues open in network games
if( file->is_loading() ) {
if( file->is_version_less(112, 3) ) {
self = convoihandle_t( this );
}
else {
uint16 id;
file->rdwr_short( id );
self = convoihandle_t( this, id );
}
}
else if( file->is_version_atleast(112, 3) ) {
uint16 id = self.get_id();
file->rdwr_short( id );
}
So in recent versions is seems that this is called to save and load the convoihandle (making them consistent between server and client in network games). There is a similar usage in gui\convoi_info_t.cc
's convoi_info_t::rdwr()
and other rdwr()
functions. Trawling through all 76 references didn't turn up any other uses.
There is a public member function to get the handle (L248):
* @return the index into the tombstone table. May be used as
* an ID for the referenced object.
*/
inline uint16 get_id() const { return entry; }
This function is called in convoi_t::sync_step() to create the second convoy debug sum, as discussed here.. And voilá, we we have confirmation that the debug sum is created using the convoihandle_t id
, which proves that the id
indices listed in the tombstone are the same as the "internal IDs" displayed by the UI and included by default in the convoy name strings that players see!
Be aware that the dot and arrow operators are both overloaded.