Files
MagicSetEditor2/src/util/for_each.hpp
T
twanvl 4a6e10ad93 Support for extra card fields in stylesheets;
Fixed some bugs:
 - Missing choice images can crash mse.
 - The wrong style is used for making preview choice images on style panel.
FOR_EACH(x, *y.z) should now work without parentheses on linux as well.

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@389 0fc631ac-6414-0410-93d0-97cfa31319b6
2007-05-18 21:26:21 +00:00

215 lines
11 KiB
C++

//+----------------------------------------------------------------------------+
//| 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<const type_info &ref_type_info> struct TypeOf {};
/// The type of a value
#define TYPEOF(Value) TypeOf<typeid(Value)>::type
/// The type of an iterator
#define TYPEOF_IT(Value) TypeOf<typeid(Value)>::iterator
/// The type of a const iterator
#define TYPEOF_CIT(Value) TypeOf<typeid(Value)>::const_iterator
/// The type of a reverse iterator
#define TYPEOF_RIT(Value) TypeOf<typeid(Value)>::reverse_iterator
/// The type of a const reverse iterator
#define TYPEOF_CRIT(Value) TypeOf<typeid(Value)>::const_reverse_iterator
/// The type of a reference
#define TYPEOF_REF(Value) TypeOf<typeid(Value)>::reference
/// The type of a const reference
#define TYPEOF_CREF(Value) TypeOf<typeid(Value)>::const_reference
/// Declare typeof magic for a specific type
#define DECLARE_TYPEOF(T) \
template<> struct TypeOf<typeid(T)> { \
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<typeid(T)> { \
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<typeid(T)> { \
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<a COMMA b>);
* instead of
* DECLARE_TYPEOF(pair<a,b>);
*/
#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<TypeIt,bool> 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<std::pair<TypeIt1,TypeIt2>, 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