//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make Magic (tm) cards | //| Copyright: (C) 2001 - 2007 Twan van Laarhoven | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ #ifndef HEADER_UTIL_FOR_EACH #define HEADER_UTIL_FOR_EACH /** @file util/for_each.hpp * * @brief Macros to simplify looping over collections. * * This header contains some evil template and macro hackery. */ // ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Typeof magic #ifdef __GNUC__ // GCC has a buildin typeof function, so it doesn't need (as much) hacks #define DECLARE_TYPEOF(T) #define DECLARE_TYPEOF_NO_REV(T) #define DECLARE_TYPEOF_CONST(T) #define DECLARE_TYPEOF_COLLECTION(T) #define TYPEOF(Value) __typeof(Value) #define TYPEOF_IT(Value) __typeof((Value).begin()) #define TYPEOF_CIT(Value) __typeof((Value).begin()) #define TYPEOF_RIT(Value) __typeof((Value).rbegin()) #define TYPEOF_CRIT(Value) __typeof((Value).rbegin()) #define TYPEOF_REF(Value) __typeof(*(Value).begin())& #define TYPEOF_CREF(Value) __typeof(*(Value).begin())& #else /// Helper for typeof tricks template struct TypeOf {}; /// The type of a value #define TYPEOF(Value) TypeOf::type /// The type of an iterator #define TYPEOF_IT(Value) TypeOf::iterator /// The type of a const iterator #define TYPEOF_CIT(Value) TypeOf::const_iterator /// The type of a reverse iterator #define TYPEOF_RIT(Value) TypeOf::reverse_iterator /// The type of a const reverse iterator #define TYPEOF_CRIT(Value) TypeOf::const_reverse_iterator /// The type of a reference #define TYPEOF_REF(Value) TypeOf::reference /// The type of a const reference #define TYPEOF_CREF(Value) TypeOf::const_reference /// Declare typeof magic for a specific type #define DECLARE_TYPEOF(T) \ template<> struct TypeOf { \ typedef T type; \ typedef T::iterator iterator; \ typedef T::const_iterator const_iterator; \ typedef T::reverse_iterator reverse_iterator; \ typedef T::const_reverse_iterator const_reverse_iterator; \ typedef T::reference reference; \ typedef T::const_reference const_reference; \ } /// Declare typeof magic for a specific type that doesn't support reverse iterators #define DECLARE_TYPEOF_NO_REV(T) \ template<> struct TypeOf { \ typedef T type; \ typedef T::iterator iterator; \ typedef T::const_iterator const_iterator; \ typedef T::reference reference; \ typedef T::const_reference const_reference; \ } /// Declare typeof magic for a specific type, using const iterators #define DECLARE_TYPEOF_CONST(T) \ template<> struct TypeOf { \ typedef T type; \ typedef T::const_iterator iterator; \ typedef T::const_iterator const_iterator; \ typedef T::const_reverse_iterator reverse_iterator; \ typedef T::const_reverse_iterator const_reverse_iterator; \ typedef T::const_reference reference; \ typedef T::const_reference const_reference; \ } /// Declare typeof magic for a specific std::vector type #define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector< T >); \ DECLARE_TYPEOF_CONST(set< T >) #endif /// Use for template classes /** i.e. * DECLARE_TYPEOF(pair); * instead of * DECLARE_TYPEOF(pair); */ #define COMMA , // ----------------------------------------------------------------------------- : Looping macros with iterators /// Iterate over a collection, using an iterator it of type Type /** Usage: FOR_EACH_IT_T(Type,it,collect) { body-of-loop } */ #define FOR_EACH_IT_T(Type,Iterator,Collection) \ for(Type Iterator = (Collection).begin() ; \ Iterator != (Collection).end() ; \ ++Iterator) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Usage: FOR_EACH_IT(it,collect) { body-of-loop } */ #define FOR_EACH_IT(Iterator,Collection) \ FOR_EACH_IT_T(TYPEOF_IT(Collection), Iterator, Collection) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Uses a const_iterator * Usage: FOR_EACH_IT(it,collect) { body-of-loop } */ #define FOR_EACH_CONST_IT(Iterator,Collection) \ FOR_EACH_IT_T(TYPEOF_CIT(Collection), Iterator, Collection) /// Iterate over a collection in whos type must be declared with DECLARE_TYPEOF /** Iterates using a reverse_iterator * Usage: FOR_EACH_REVERSE_IT(it,collect) { body-of-loop } */ #define FOR_EACH_REVERSE_IT(Iterator,Collection) \ for(TYPEOF_RIT(Collection) \ Iterator = (Collection).rbegin() ; \ Iterator != (Collection).rend() ; \ ++Iterator) // ----------------------------------------------------------------------------- : Looping macros /// Iterate over a collection, with an iterator of type TypeIt, and elements of type TypeElem /** Usage: FOR_EACH_T(TypeIt,TypeElem,e,collect,begin,end) { body-of-loop } * * We need a hack to be able to declare a local variable without needing braces. * To do this we use a nested for loop that is only executed once, and which is optimized away. * To terminate this loop we need an extra bool, which we set to false after the first iteration. */ #define FOR_EACH_T(TypeIt,TypeElem,Elem,Collection, begin, end) \ for(std::pair Elem##_IT((Collection).begin(), true) ; \ Elem##_IT.second && Elem##_IT.first != (Collection).end() ; \ ++Elem##_IT.first, Elem##_IT.second = !Elem##_IT.second) \ for(TypeElem Elem = *Elem##_IT.first ; \ Elem##_IT.second ; \ Elem##_IT.second = false) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Usage: FOR_EACH(e,collect) { body-of-loop } */ #define FOR_EACH(Elem,Collection) \ FOR_EACH_T(TYPEOF_IT(Collection), TYPEOF_REF(Collection), Elem, Collection, begin, end) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Uses a const iterator * Usage: FOR_EACH_CONST(e,collect) { body-of-loop } */ #define FOR_EACH_CONST(Elem,Collection) \ FOR_EACH_T(TYPEOF_CIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, begin, end) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Iterates using a reverse_iterator * Usage: FOR_EACH_REVERSE(e,collect) { body-of-loop } */ #define FOR_EACH_REVERSE(Elem,Collection) \ FOR_EACH_T(TYPEOF_RIT(Collection), TYPEOF_REF(Collection), Elem, Collection, rbegin, rend) /// Iterate over a collection whos type must be declared with DECLARE_TYPEOF /** Iterates using a const_reverse_iterator * Usage: FOR_EACH_CONST_REVERSE(e,collect) { body-of-loop } */ #define FOR_EACH_CONST_REVERSE(Elem,Collection) \ FOR_EACH_T(TYPEOF_CRIT(Collection), TYPEOF_CREF(Collection), Elem, Collection, rbegin, rend) /// Iterate over two collection in parallel /** Usage: FOR_EACH_2_T(TypeIt1,TypeElem1,e1,collect1,TypeIt2,TypeElem2,e2,collect2) { body-of-loop } * * Note: This has got to be one of the craziest pieces of code I have ever written :) * It is just an extension of the idea of FOR_EACH_T. */ #define FOR_EACH_2_T(TypeIt1,TypeElem1,Elem1,Coll1,TypeIt2,TypeElem2,Elem2,Coll2) \ for(std::pair, bool> \ Elem1##_IT(make_pair((Coll1).begin(), (Coll2).begin()), true) ; \ Elem1##_IT.first.first != (Coll1).end() && \ Elem1##_IT.first.second != (Coll2).end() ; \ ++Elem1##_IT.first.first, ++Elem1##_IT.first.second, \ Elem1##_IT.second = true) \ for(TypeElem1 Elem1 = *Elem1##_IT.first.first ; \ Elem1##_IT.second ; \ Elem1##_IT.second = false) \ for(TypeElem2 Elem2 = *Elem1##_IT.first.second ; \ Elem1##_IT.second ; \ Elem1##_IT.second = false) /// Iterate over two collections in parallel, their type must be declared with DECLARE_TYPEOF. /** Usage: FOR_EACH_2(e1,collect1, e2,collect2) { body-of-loop } */ #define FOR_EACH_2(Elem1,Collection1, Elem2,Collection2) \ FOR_EACH_2_T(TYPEOF_IT(Collection1), TYPEOF_REF(Collection1), Elem1, Collection1, \ TYPEOF_IT(Collection2), TYPEOF_REF(Collection2), Elem2, Collection2) /// Iterate over two constants collections in parallel, their type must be declared with DECLARE_TYPEOF. /** Usage: FOR_EACH_2_CONST(e1,collect1, e2,collect2) { body-of-loop } */ #define FOR_EACH_2_CONST(Elem1,Collection1, Elem2,Collection2) \ FOR_EACH_2_T(TYPEOF_CIT(Collection1), TYPEOF_CREF(Collection1), Elem1, Collection1, \ TYPEOF_CIT(Collection2), TYPEOF_CREF(Collection2), Elem2, Collection2) // ----------------------------------------------------------------------------- : EOF #endif