Skip to main content
Topic: Iterating function macros for vectors, etc. (Read 4966 times) previous topic - next topic

Iterating function macros for vectors, etc.

Following the recent synchronisation of all of the collection cl****es' function syntax, I have written some very simple function macros to make code for iterating through vectors a little easier. They are written as function macros not methods of the collection cl****es because of the need to specify a specific index for each iteration. They enable the following code:

Code: [Select]
for(unsigned short i=0;  i<last_built.get_count();  i++  ) {
grund_t* gr = welt->lookup(last_built[i]);
...

to be replaced with code like this:

Code: [Select]
ITERATE(last_built,i)
{
grund_t* gr = welt->lookup(last_built[i]);
...

The function macros work with any collection cl**** that has two properties: (1) a "get_count()" method, that returns a 1 based index representing the number of elements currently contained in the collection; and (2) an overloaded [] operator allowing access to individual elements using a 0 based index. Here is the code for the function macro, which should be inserted at the top of the file of every collection cl**** with those properties:

Code: [Select]
#ifndef ITERATE
#define ITERATE(collection,i) for(uint16 i = 0; i < collection.get_count(); i++)
#endif

#ifndef ITERATE_PTR
#define ITERATE_PTR(collection,i) for(uint16 i = 0; i < collection->get_count(); i++)
#endif

If it would be helpful, I could try to make up a patch file against the standard version of Simutrans (they are currently integrated into Simutrans-Experimental) for easy integration into the trunk. These macros are helpful in that: (1) they reduce the time that it takes to write iteration loops for vector type collections; and (2) they reduce the possibility of errors such as the following:

Code: [Select]
for(unsigned short i = last_built.get_count();  i <= 0;  i--  ) {
grund_t* gr = welt->lookup(last_built[i]);
...

Any comments would be appreciated :-)
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Re: Iterating function macros for vectors, etc.

Reply #1
just curious: would that be possible with templates instead of macros?
Parsley, sage, rosemary, and maggikraut.

Re: Iterating function macros for vectors, etc.

Reply #2
I think you have to put the first arguments into brackets for more safety:
Code: [Select]
#ifndef ITERATE
#define ITERATE(collection,i) for(uint16 i = 0; i < (collection).get_count(); i++)
#endif

#ifndef ITERATE_PTR
#define ITERATE_PTR(collection,i) for(uint16 i = 0; i < (collection)->get_count(); i++)
#endif

Maybe you could also backup the count of the vector like this (but I think there's no easy way to avoid conflicts of the max-variable):
Code: [Select]
#define ITERATE(collection,i) uint16 max = (collection).get_count(); for(uint16 i = 0; i < max; i++)

I think, I wouldn't like it. A for-loop is more readable than such a macro.

Re: Iterating function macros for vectors, etc.

Reply #3
Then you could use the std-like iterator templates in there anyway. That way you could easily switch between vectors and lists. Moreover they are save for deletion etc. which macros are not.

You could then make an iterator macro that automatically iterates either list or vectors.

Re: Iterating function macros for vectors, etc.

Reply #4
Gerw,

would there ever be a situation in which something not in brackets could be p****ed to the macro that (1) works if it is in brackets; and (2) does not work if it is not? I cannot immediately imagine such a case, as the macro is defined only for template cl****es, where there would just be the name of the template object p****ed, but perhaps you have thought of something that I have not...?

As to the saving of the count variable, that is not a bad idea, although it does cause safety problems. Not so much that "max" might conflict with something, as one could choose a keyword that is very unlikely to do so (such as "MACRO_ITERATOR_COLLECTION_TOTAL_COUNT_SIZE"), but that, if the operation involves a deletion of one of the elements, the change in the count of the collection would not be registered, and an out of range error would be produced as for loop would try to access an element beyond its range.

Dwachs and Prissi,

the reason that templates are not used is because it would not produce the same result; one would not be able easily to access
Code: [Select]
collection[i]->some_function();

(for example) with so few lines of code. One would have to use, as Prissi suggests, an iterator; but I find iterators cumbersome to code, and, as I understand things, are slower to execute, since they require additional function calls and objects, whereas a straight for loop is very simple and accesses the collection directly. Having first to declare an iterator and then advance it is more work both to code and execute than a simple loop, especially, in the case of coding time, where it is given a function macro.

I had the idea for this macro from the foreach keyword in C#, the functionality of which this macro is designed to emulate as much as a C++ function macro sensibly can. In C#, one can write something like this:

Code: [Select]
foreach(object i in collection)
{
         i.some_function();
}

The idea is that the ITERATE macro allows a very similar result: compare the above to this example:

Code: [Select]
ITERATE(i,collection)
{
           collection[i]->some_function();
}

The readability comes in part from the similarity to C#'s foreach keyword.

But I'm interested in Prissi's suggestion of an iterator macro; might I ask: how would that work exactly?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Re: Iterating function macros for vectors, etc.

Reply #5
you can have a foreach macro with an iterator.

#define FOREACH(typ,basis,iter) for (typ::iterator iter = basis.begin(); iter != basis.end();  ++iter)

and you access i-> or (*i). all desired operators.

This works FOREACH(slist_tpl<fabrik_t *>, fablist, fab ) als well as for FOREACH(vector_tpl<fabrik_t *>, fablist, fab )

One could also think to have and end_iter=basis.end() define once and then iterate without rechecking each time; but this way it is saver.

However, I strongly suggest not using macros for lasy typing un such cases. This easily causes errors that are hard to catch later.


Re: Iterating function macros for vectors, etc.

Reply #7
Prissi,

that could work for iterators - but would lose the speed advantage of a for loop. Interesting, though.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Re: Iterating function macros for vectors, etc.

Reply #8
Those iterators are as fast as the normal for loop, since the just return pointers and compare pointers. Since the std uses also such iterators, compiler are nowadays very much trimmed to optimize those.

And the boost macro works only on std and not on simutrans marcos I think. (Apart from the fact that boost is a pain to set up on some achritectures and makes compilation more difficult for many people.)

Re: Iterating function macros for vectors, etc.

Reply #9
Ahh, interesting - I always thought that iterators were slower. Don't they require more memory because they create a special iterator object? If they really are just as fast, your FOREACH macro is very interesting indeed.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Re: Iterating function macros for vectors, etc.

Reply #10
would there ever be a situation in which something not in brackets could be p****ed to the macro that (1) works if it is in brackets; and (2) does not work if it is not?
Maybe some fancy constructs like
Code: [Select]
ITERATE_PTR(collection+4,i)
where collection is a pointer to an array of vectors.

Re: Iterating function macros for vectors, etc.

Reply #11
Couldn't one just write

Code: [Select]
ITERATE_PTR((collection+4),i)

?
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Re: Iterating function macros for vectors, etc.

Reply #12
Of course. But it's safer (and more programmer friendly) when you add the brackets to the macro definition.

Re: Iterating function macros for vectors, etc.

Reply #13
Ahh, yes, I see. The change suggested will be incorporated into the next version of Simutrans-Experimental.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.