#ifndef AARTSFOREACHINCD #define AARTSFOREACHINCD #include #include #include #include #include #include #define typeof __typeof__ // ===================================================================================================== // foreach and foreach_map macro's // // Loop over any container object that has begin() and end() // example: // vector v(10,1); // foreach( x, v , x<3 ) cout << x << endl; // // remarks: // - the 3rd argument is an expression which can be used to select which elements to loop over // - the container can be a temporary object // - you can modify x inside the loop, unless v is const (it's a reference to the element inside v) // - break and continue work as expected // ===================================================================================================== template T _next( T it) { return ++it; } //#define atfirst ( it == cn2.begin() ) //#define atlast ( _next(it) == cn2.end() ) // use typeof to copy #define foreach(var, container, cond_expr... ) \ if (int flag1 = false ) {} else \ for( const typeof(container)& cn = container ; !flag1; flag1=true ) \ if (bool flag2 = false ) {} else \ for( typeof(container)& cn2 = const_cast( cn); !flag2; flag2=true )\ if (int state = 0) {} else \ for( typeof(cn2.begin()) it = cn2.begin(); it != cn2.end() && !state; ++it) \ for( typeof(*( (container).begin() ) )& var = *it ; (true,##cond_expr) && (++state) ; state=-1 ) #define enumerate(counter, var, container, cond_expr... ) \ if (int counter = 0 ) {} else \ if (bool flag1 = false ) {} else \ for( const typeof(container)& cn = container ; !flag1; flag1=true ) \ if (bool flag2 = false ) {} else \ for( typeof(container)& cn2 = const_cast( cn); !flag2; flag2=true ) \ if (int state = 0) {} else \ for( typeof(cn2.begin()) it = cn2.begin(); it != cn2.end() && !state; ++it, counter++) \ for( typeof(*( (container).begin() ) )& var = *it ; (true,##cond_expr) && (++state) ; state=-1 ) // -------------------------------------------------- // A version for maps, specify the key and the value // -------------------------------------------------- #define foreach_map( key, val, container, cond_expr... ) \ if (bool flag1 = false ) {} else \ for( const typeof(container)& cn = container ; !flag1; flag1=true ) \ if (bool flag2 = false ) {} else \ for( typeof(container)& cn2 = const_cast( cn); !flag2; flag2=true ) \ if (int state = 0 ) {} else \ for( typeof(cn2.begin()) it = cn2.begin(); it != cn2.end() && !state; ++it) \ if (bool flag3 = false) {} else for( typeof((*it).first)& key __attribute__((unused)) = (*it).first ; !flag3 ; flag3=true ) \ for( typeof((*it).second)& val = (*it).second ; (true,##cond_expr) && (++state) ; state=-1 ) // --------------------------------------------------------------------------------- // Loop only over the values of a map, igorking the keys (moving into the c++11 era ) // --------------------------------------------------------------------------------- #define foreach_value( val, container, cond_expr... ) \ for( auto& it : container ) \ if ( bool flag1 = true ) \ for( decltype(container)::mapped_type& val = it.second ; flag1 && (true,##cond_expr) ; flag1 = false ) // ---------------------------------- // A trick to loop over a map-of-maps // ---------------------------------- #define foreach_map_map( key1 , key2, val, container ) \ foreach_map( key1, inner_map, container ) foreach_map( key2, val, inner_map ) // -- foreach details-- // We use the fact that you can declare variables in if and for statemements // to declare variables. This means: no namespace polution (can use foreach // multiple times without multiple def of 'cn'). And it means we can use foreach // as start of a block! // // the const reference cn to 'container' ensures that it works for temporary objects // (which will then go out of scope and get deleted after the 'foreach' as expected) // // The const_cast is too bad, but I want to be able to modify the elements (if the // container is non-const. Reasonable type safety is still provided by the last // line of the macro, where the final 'var' is of the type of *(container).begin(), // i.e. if the container is const, so is the var (although I do not really understand this). // // Passing in a temporary works well. Just not clear what is supposed to happen when you // start changing the temporary // // the 'state' is needed to make 'break' work as expected: it should break out of // the iterator loop and not out of the for-statement that we abuse to assign *it to var. // state== 1 : there was a break or contine in the 1st loop // state== 0 : fell off block ( 0 -> 1 , state = -1 , ++state = 0 ) -> go on with next one // state== -1 : there was a break or continue in the >1st loop. #ifdef EXPERIMENT #endif //================================================================================ // Several small functions to make dealing with std::vector's easier //================================================================================ template std::vector slice(const std::vector& v, int start=0, int end=0, int incr=1) { std::vector r; if (end<=0) end = v.size() + end; if (start<0) start = v.size() + start; for (int i = start; i void add( T& a , const T& b ) { a.insert(std::end(a), std::begin(b), std::end(b)); } // A simple range function template std::vector range(T end) { std::vector r; for (T x; x< end; x++) r.push_back(x); return r; } template std::vector range(T start, T end, T inc=1) { std::vector r; for (T x = start; x< end; x+=inc) r.push_back(x); return r; } template< typename T> bool contains( const std::vector& v, const T& item ) { if ( std::find(v.begin(), v.end(), item) == v.end() ) return false; return true; } template< typename T> int index_of( const std::vector& v, const T& item ) { typename std::vector::const_iterator i = std::find (v.begin(), v.end(), item ); if (i== v.end()) return -1; return i - v.begin(); } // Sum the elements in a vector. // works with everything that has + defined (e.g. numbers, but also strings). template < typename T> typename T::value_type sum( const T& v ) { if (!v.size()) return typename T::value_type (); typename T::value_type r= *(v.begin()); bool first = true; foreach( x, v ) { if (!first) r+=x; first = false; } return r; } /*! Remove the elements from a vector for which pred is true */ template < typename C, typename F > void remove_element_if( C& container, F predicate ) { container.erase( std::remove_if(container.begin(), container.end(), predicate ), container.end() ); } /*! Remove the elements from a map for which predicate is true */ template < typename U, typename V, typename F > void remove_element_if( std::map& container, F predicate ) { for( auto iter = container.begin() ; iter != container.end() ; ) { if ( predicate(iter->second) ) iter = container.erase(iter); else ++iter; } } //sum( hits, [](hit h) { return hit.t } ) template < typename T> typename T::value_type mean( const T& v ) { typename T::value_type r = sum( v ); r /= v.size(); return r; } /*! returns true if all elements are true */ template < typename T> bool all ( const T& v ) { foreach( x, v ) if (!x) return false; return true; } /* returns true if any of the elements (are true) */ template < typename T> bool any ( const T& v ) { foreach( x, v ) if (x) return true; return false; } /* returns the minimum */ template < typename T> typename T::value_type min ( const T& v ) { typename T::value_type m = *v.begin(); foreach( x, v ) if (x < m) m=x; return m; } /* returns max baak */ template < typename T> typename T::value_type max ( const T& v ) { typename T::value_type m = *v.begin(); foreach( x, v ) if (x > m) m=x; return m; } template< typename T > std::vector< std::vector< T > > hzip ( const std::vector& v1, const std::vector& v2 ) { unsigned n = v1.size(); if ( v2.size() < n ) n = v2.size(); std::vector< std::vector< T > > r(n); for (unsigned i =0 ; i < n ; i++) { r[i].resize(2); r[i][0] = v1[i]; r[i][1] = v2[i]; } return r; } /*! Apply function to each element of a vector. */ template< typename T, typename F> auto fmap(const F& f, const std::vector & obj ) -> std::vector < decltype( f(T()) ) > { std::vector < decltype( f(T()) ) > r; r.reserve( obj.size() ); for( const auto& i : obj) r.push_back( f(i) ); return r; } //============================================================ // some map helpers //============================================================ template std::vector inline keys( const std::map& m ) { std::vector r; foreach_map( k,v,m ) { (void) v; r.push_back(k); } return r; } template std::vector inline values( const std::map& m ) { std::vector r; foreach_map( k,v,m ) { (void) k; r.push_back(v); } return r; } //============================================================ // easy sorting // =========================================================== //http://stackoverflow.com/questions/5174115/sorting-a-vector-of-objects-by-a-property-of-the-object template struct member_comparer { explicit member_comparer(M T::*p) : p_(p) { } bool operator ()(T const& lhs, T const& rhs) const { return lhs.*p_ < rhs.*p_; } private: M T::*p_; }; template member_comparer make_member_comparer(M T::*p) { return member_comparer(p); } using std::vector; template vector sort_by( vector hits, PMEM p ) { vector r = hits; std::sort( r.begin(), r.end() , make_member_comparer( p ) ); return r; } // ========================================================================= // pack macro: compile a vector from a comma-seperated list // of values. The return type is vector where is the type // of the first agurment. example: // pack(1.0,2,3,4); // ok : vector : 1.0, 2.0, 3.0, 4.0 // pack(1,2.0 ); // error since this involves vector::push_back( 2.0 ) struct stoptype {}; template struct vector_ : public std::vector { vector_ operator,(const T& x) { this->push_back(x); return *this;} std::vector operator,(stoptype x) {return *this;} explicit vector_(const std::vector& v): std::vector(v) {} explicit vector_(const T& x): std::vector(1,x) {} }; struct packseed_ { template vector_ operator,( const T& x) { return vector_(x); } }; #define pack( ... ) (packseed_(),__VA_ARGS__,stoptype()) #endif