celestar@5650: /* $Id$ */ celestar@5650: celestar@5650: #ifndef HELPERS_HPP celestar@5650: #define HELPERS_HPP celestar@5650: celestar@5650: /** @file helpers.hpp */ celestar@5650: #include "macros.h" celestar@5650: celestar@5650: #ifdef __cplusplus celestar@5650: celestar@5650: /** When allocating using malloc/calloc in C++ it is usually needed to cast the return value celestar@5650: * from void* to the proper pointer type. Another alternative would be MallocT<> as follows */ celestar@5650: template FORCEINLINE bool MallocT(T** t_ptr, size_t num_elements) celestar@5650: { celestar@5650: *t_ptr = (T*)malloc(num_elements * sizeof(T)); celestar@5650: return (*t_ptr != NULL); celestar@5650: } celestar@5650: /** When allocating using malloc/calloc in C++ it is usually needed to cast the return value celestar@5650: * from void* to the proper pointer type. Another alternative would be MallocT<> as follows */ celestar@5650: template FORCEINLINE bool CallocT(T** t_ptr, size_t num_elements) celestar@5650: { celestar@5650: *t_ptr = (T*)calloc(num_elements, sizeof(T)); celestar@5650: return (*t_ptr != NULL); celestar@5650: } celestar@5650: /** When allocating using malloc/calloc in C++ it is usually needed to cast the return value celestar@5650: * from void* to the proper pointer type. Another alternative would be MallocT<> as follows */ celestar@5650: template FORCEINLINE bool ReallocT(T** t_ptr, size_t num_elements) celestar@5650: { celestar@5650: *t_ptr = (T*)realloc(*t_ptr, num_elements * sizeof(T)); celestar@5650: return (*t_ptr != NULL); celestar@5650: } celestar@5650: celestar@5650: /** type safe swap operation */ celestar@5650: template void SwapT(T *a, T *b); celestar@5650: celestar@5650: template FORCEINLINE void SwapT(T *a, T *b) celestar@5650: { celestar@5650: T t = *a; celestar@5650: *a = *b; celestar@5650: *b = t; celestar@5650: } celestar@5650: celestar@5650: celestar@5650: /** returns the absolute value of (scalar) variable. @note assumes variable to be signed */ celestar@5650: template static inline T myabs(T a) { return a < (T)0 ? -a : a; } celestar@5650: /** returns the (absolute) difference between two (scalar) variables */ celestar@5650: template static inline T delta(T a, T b) { return a < b ? b - a : a - b; } celestar@5650: celestar@5650: /** Some enums need to have allowed incrementing (i.e. StationClassID) */ celestar@5650: #define DECLARE_POSTFIX_INCREMENT(type) \ celestar@5650: FORCEINLINE type operator ++(type& e, int) \ celestar@5650: { \ celestar@5650: type e_org = e; \ celestar@5650: e = (type)((int)e + 1); \ celestar@5650: return e_org; \ celestar@5650: } \ celestar@5650: FORCEINLINE type operator --(type& e, int) \ celestar@5650: { \ celestar@5650: type e_org = e; \ celestar@5650: e = (type)((int)e - 1); \ celestar@5650: return e_org; \ celestar@5650: } celestar@5650: celestar@5650: celestar@5650: celestar@5650: /** Operators to allow to work with enum as with type safe bit set in C++ */ celestar@5650: # define DECLARE_ENUM_AS_BIT_SET(mask_t) \ celestar@5650: FORCEINLINE mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((int)m1 | m2);} \ celestar@5650: FORCEINLINE mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((int)m1 & m2);} \ celestar@5650: FORCEINLINE mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((int)m1 ^ m2);} \ celestar@5650: FORCEINLINE mask_t& operator |= (mask_t& m1, mask_t m2) {m1 = m1 | m2; return m1;} \ celestar@5650: FORCEINLINE mask_t& operator &= (mask_t& m1, mask_t m2) {m1 = m1 & m2; return m1;} \ celestar@5650: FORCEINLINE mask_t& operator ^= (mask_t& m1, mask_t m2) {m1 = m1 ^ m2; return m1;} \ celestar@5650: FORCEINLINE mask_t operator ~(mask_t m) {return (mask_t)(~(int)m);} celestar@5650: celestar@5650: /** probably redundant enum combining operators (as we have conversion functions) celestar@5650: * but the old code is full of such arithmetics */ celestar@5650: # define DECLARE_ENUM_AS_BIT_INDEX(idx_t, mask_t) \ celestar@5650: FORCEINLINE mask_t operator << (int m, idx_t i) {return (mask_t)(m << (int)i);} \ celestar@5650: FORCEINLINE mask_t operator << (mask_t m, int i) {return (mask_t)(((int)m) << i);} \ celestar@5650: FORCEINLINE mask_t operator >> (mask_t m, int i) {return (mask_t)(((int)m) >> i);} celestar@5650: celestar@5650: celestar@5650: /** Informative template class exposing basic enumeration properties used by several celestar@5650: * other templates below. Here we have only forward declaration. For each enum type celestar@5650: * we will create specialization derived from MakeEnumPropsT<>. */ celestar@5650: template struct EnumPropsT; celestar@5650: celestar@5650: /** Helper template class that makes basic properties of given enumeration type visible celestar@5650: * from outsize. It is used as base class of several EnumPropsT specializations each celestar@5650: * dedicated to one of commonly used enumeration types. */ celestar@5650: template celestar@5650: struct MakeEnumPropsT { celestar@5650: typedef Tenum_t type; ///< enum type (i.e. Trackdir) celestar@5650: typedef Tstorage_t storage; ///< storage type (i.e. byte) celestar@5650: static const Tenum_t begin = Tbegin; ///< lowest valid value (i.e. TRACKDIR_BEGIN) celestar@5650: static const Tenum_t end = Tend; ///< one after the last valid value (i.e. TRACKDIR_END) celestar@5650: static const Tenum_t invalid = Tinvalid; ///< what value is used as invalid value (i.e. INVALID_TRACKDIR) celestar@5650: }; celestar@5650: celestar@5650: celestar@5650: celestar@5650: /** In some cases we use byte or uint16 to store values that are defined as enum. It is celestar@5650: * necessary in order to control the sizeof() such values. Some compilers make enum celestar@5650: * the same size as int (4 or 8 bytes instead of 1 or 2). As a consequence the strict celestar@5650: * compiler type-checking causes errors like: celestar@5650: * 'HasPowerOnRail' : cannot convert parameter 1 from 'byte' to 'RailType' when celestar@5650: * u->u.rail.railtype is passed as argument or type RailType. In such cases it is better celestar@5650: * to teach the compiler that u->u.rail.railtype is to be treated as RailType. */ celestar@5650: template struct TinyEnumT; celestar@5650: celestar@5650: /** The general declaration of TinyEnumT<> (above) */ celestar@5650: template struct TinyEnumT celestar@5650: { celestar@5650: typedef Tenum_t enum_type; ///< expose our enumeration type (i.e. Trackdir) to outside celestar@5650: typedef EnumPropsT Props; ///< make easier access to our enumeration propeties celestar@5650: typedef typename Props::storage storage_type; ///< small storage type celestar@5650: static const enum_type begin = Props::begin; ///< enum beginning (i.e. TRACKDIR_BEGIN) celestar@5650: static const enum_type end = Props::end; ///< enum end (i.e. TRACKDIR_END) celestar@5650: static const enum_type invalid = Props::invalid;///< invalid value (i.e. INVALID_TRACKDIR) celestar@5650: celestar@5650: storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form celestar@5650: celestar@5650: /** Cast operator - invoked then the value is assigned to the Tenum_t type */ celestar@5650: FORCEINLINE operator enum_type () const celestar@5650: { celestar@5650: return (enum_type)m_val; celestar@5650: } celestar@5650: celestar@5650: /** Assignment operator (from Tenum_t type) */ celestar@5650: FORCEINLINE TinyEnumT& operator = (enum_type e) celestar@5650: { celestar@5650: m_val = (storage_type)e; return *this; celestar@5650: } celestar@5650: celestar@5650: /** postfix ++ operator on tiny type */ celestar@5650: FORCEINLINE TinyEnumT& operator ++ (int) celestar@5650: { celestar@5650: if (++m_val >= end) m_val -= (storage_type)(end - begin); celestar@5650: return *this; celestar@5650: } celestar@5650: }; celestar@5650: celestar@5650: template FORCEINLINE void SwapT(TinyEnumT *a, TinyEnumT *b) celestar@5650: { celestar@5650: SwapT(&a->m_val, &b->m_val); celestar@5650: } celestar@5650: celestar@5650: template FORCEINLINE T ClrBitT(T t, int bit_index) celestar@5650: { celestar@5650: int val = t; celestar@5650: CLRBIT(val, bit_index); celestar@5650: return (T)val; celestar@5650: } celestar@5650: celestar@5650: template FORCEINLINE T SetBitT(T t, int bit_index) celestar@5650: { celestar@5650: int val = t; celestar@5650: SETBIT(val, bit_index); celestar@5650: return (T)val; celestar@5650: } celestar@5650: celestar@5650: template FORCEINLINE T ToggleBitT(T t, int bit_index) celestar@5650: { celestar@5650: int val = t; celestar@5650: TOGGLEBIT(val, bit_index); celestar@5650: return (T)val; celestar@5650: } celestar@5650: celestar@5650: #else // __cplusplus celestar@5650: celestar@5650: #define DECLARE_POSTFIX_INCREMENT(E) celestar@5650: #define DECLARE_ENUM_AS_BIT_SET(E) celestar@5650: #define DECLARE_ENUM_AS_BIT_INDEX(E1,E2) celestar@5650: celestar@5650: #endif // __cplusplus celestar@5650: celestar@5650: #endif /* HELPERS_HPP */