From 3525b771260c566d7aa5f8dcd83454feacce3b95 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 7 Jan 2010 03:10:02 +0100 Subject: [PATCH] somewhat tricky modification of for-each, allowing inline calls --- src/lib/meta/trait.hpp | 158 ++++++++++++++++++++++++++++++++++++--- src/lib/util-foreach.hpp | 71 ++++++++++++------ 2 files changed, 195 insertions(+), 34 deletions(-) diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index 1852068a9..2ead08e85 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -31,15 +31,150 @@ #include #include +#include +#include +#include #include #include +//Forward declarations for the Unwrap helper.... +namespace boost{ + template class reference_wrapper; +} +namespace std { +namespace tr1 { + template class reference_wrapper; + template class shared_ptr; +}} +namespace lumiera{ + template class P; +} +namespace mobject{ + template class Placement; +} + namespace lib { namespace meta { + /** + * Helper for type analysis: + * tries to extract a base type from various wrappers. + * Additionally allows to extract/deref the wrapped element + */ + template + struct Unwrap + { + typedef X Type; + + static X& + extract (X const& x) + { + return const_cast (x); + } + }; + + template + struct Unwrap + { + typedef X Type; + + static X& + extract (const X* ptr) + { + ASSERT (ptr); + return const_cast (*ptr); + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (boost::reference_wrapper wrapped) + { + return wrapped; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (std::tr1::reference_wrapper wrapped) + { + return wrapped; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (std::tr1::shared_ptr ptr) + { + ASSERT (ptr); + return *ptr; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (lumiera::P ptr) + { + ASSERT (ptr); + return *ptr; + } + }; + + template + struct Unwrap > + { + typedef X Type; + + static X& + extract (mobject::Placement placement) + { + ASSERT (placement.isValid()); + return *placement; + } + }; + + /** convenience shortcut: unwrapping free function */ + template + typename Unwrap::Type& + unwrap (X const& wrapped) + { + return Unwrap::extract(wrapped); + } + + + + /** Helper for type analysis: tries to strip all kinds of type adornments */ + template + struct Strip + { + typedef typename boost::remove_cv ::type TypeUnconst; + typedef typename boost::remove_reference::type TypeReferred; + typedef typename boost::remove_pointer ::type TypePointee; + typedef typename boost::remove_cv ::type TypePlain; + + typedef typename Unwrap ::Type Type; + }; + + /** Trait template for detecting if a type can be converted to string. * For example, this allows to write specialisations with the help of * boost::enable_if @@ -79,15 +214,17 @@ namespace meta { template class can_STL_ForEach { + typedef typename Strip::Type Type; + struct is_iterable { META_DETECT_NESTED(iterator); META_DETECT_FUNCTION(typename X::iterator, begin,(void)); META_DETECT_FUNCTION(typename X::iterator, end ,(void)); - enum { value = HasNested_iterator::value - && HasFunSig_begin::value - && HasFunSig_end::value + enum { value = HasNested_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value }; }; @@ -97,9 +234,9 @@ namespace meta { META_DETECT_FUNCTION(typename X::const_iterator, begin,(void) const); META_DETECT_FUNCTION(typename X::const_iterator, end ,(void) const); - enum { value = HasNested_const_iterator::value - && HasFunSig_begin::value - && HasFunSig_end::value + enum { value = HasNested_const_iterator::value + && HasFunSig_begin::value + && HasFunSig_end::value }; }; @@ -120,16 +257,17 @@ namespace meta { template class can_IterForEach { + typedef typename Strip::Type Type; META_DETECT_NESTED(value_type); META_DETECT_OPERATOR_DEREF(); META_DETECT_OPERATOR_INC(); public: - enum{ value = boost::is_convertible::value - && HasNested_value_type::value - && HasOperator_deref::value - && HasOperator_inc::value + enum{ value = boost::is_convertible::value + && HasNested_value_type::value + && HasOperator_deref::value + && HasOperator_inc::value }; }; diff --git a/src/lib/util-foreach.hpp b/src/lib/util-foreach.hpp index 692328372..bfb6f9514 100644 --- a/src/lib/util-foreach.hpp +++ b/src/lib/util-foreach.hpp @@ -23,8 +23,8 @@ /** @file util-foreach.hpp ** Perform operations "for each element" of a collection. - ** This header defines various flavours of these active iteration functions, which all take - ** a functor and invoke it in some way over the collection's elements. + ** This header defines various flavours of these active iteration functions, + ** which all take a functor and invoke it in some way over the collection's elements. ** - basic constructs ** - for_each ** - and_all (all quantisation) @@ -34,6 +34,15 @@ ** - "Lumiera Forward Iterator" instance to yield all the elements of the collection ** - support for on-the-fly binding up to 4 arguments of the functor ** + ** @warning in the standard case (STL container) the collection to operate on is + ** taken by \c const& -- but the const is stripped silently. + ** + ** Thus, within the iteration, the function passed in can \em modify the original collection. + ** If you pass in a ref to a temporary, the compiler won't complain. Moreover, several kinds + ** of wrappers are also stripped silently, including reference_wrapper, shared_ptr and + ** lumiera::P. The rationale for this non-standard behaviour is to allow convenient writing + ** of in-line iteration, where even the collection to iterate is yielded by function call. + ** ** @see util-foreach-test.cpp ** */ @@ -95,18 +104,24 @@ namespace util { /* === specialisations for STL containers and Lumiera Forward Iterators === */ /** operating on all elements of a STL container. + * @note the container is taken by \c const& and + * the \c const is \em stripped before iteration. * @note this case is the default and kicks in * \em unless we detect a Lumiera iterator. - * The handling is different for and_all + * The handling is different for \c and_all */ template inline typename disable_if< can_IterForEach, FUN >::type - for_each (Container& c, FUN doIt) + for_each (Container const& coll, FUN doIt) { - return std::for_each (c.begin(),c.end(), doIt); + using lib::meta::unwrap; + + return std::for_each (unwrap(coll).begin() + ,unwrap(coll).end() + , doIt); } @@ -116,7 +131,7 @@ namespace util { > inline typename enable_if< can_IterForEach, FUN >::type - for_each (IT& ii, FUN doIt) + for_each (IT const& ii, FUN doIt) { return std::for_each (ii, IT(), doIt); } @@ -129,9 +144,13 @@ namespace util { > inline typename enable_if< can_STL_ForEach, bool >::type - and_all (Container& coll, FUN predicate) + and_all (Container const& coll, FUN predicate) { - return and_all (coll.begin(),coll.end(), predicate); + using lib::meta::unwrap; + + return and_all (unwrap(coll).begin() + ,unwrap(coll).end() + , predicate); } @@ -140,7 +159,7 @@ namespace util { > inline typename enable_if< can_IterForEach, bool >::type - and_all (IT& ii, FUN predicate) + and_all (IT const& ii, FUN predicate) { return and_all (ii, IT(), predicate); } @@ -152,9 +171,13 @@ namespace util { > inline typename enable_if< can_STL_ForEach, bool >::type - has_any (Container& coll, FUN predicate) + has_any (Container const& coll, FUN predicate) { - return has_any (coll.begin(),coll.end(), predicate); + using lib::meta::unwrap; + + return has_any (unwrap(coll).begin() + ,unwrap(coll).end() + , predicate); } @@ -163,7 +186,7 @@ namespace util { > inline typename enable_if< can_IterForEach, bool >::type - has_any (IT& ii, FUN predicate) + has_any (IT const& ii, FUN predicate) { return has_any (ii, IT(), predicate); } @@ -178,7 +201,7 @@ namespace util { , typename P1 > inline void //________________________________ - for_each (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + for_each (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument { for_each (elements, std::tr1::bind (function, bind1)); } @@ -189,7 +212,7 @@ namespace util { , typename P2 > inline void //________________________________ - for_each (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments { for_each (elements, std::tr1::bind (function, bind1, bind2)); } @@ -201,7 +224,7 @@ namespace util { , typename P3 > inline void //________________________________ - for_each (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments { for_each (elements, std::tr1::bind (function, bind1, bind2, bind3)); } @@ -214,7 +237,7 @@ namespace util { , typename P4 > inline void //________________________________ - for_each (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments { for_each (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); } @@ -227,7 +250,7 @@ namespace util { , typename P1 > inline bool //________________________________ - and_all (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + and_all (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument { return and_all (elements, std::tr1::bind (function, bind1)); } @@ -238,7 +261,7 @@ namespace util { , typename P2 > inline bool //________________________________ - and_all (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments { return and_all (elements, std::tr1::bind (function, bind1, bind2)); } @@ -250,7 +273,7 @@ namespace util { , typename P3 > inline bool //________________________________ - and_all (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments { return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3)); } @@ -263,7 +286,7 @@ namespace util { , typename P4 > inline bool //________________________________ - and_all (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + and_all (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments { return and_all (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); } @@ -276,7 +299,7 @@ namespace util { , typename P1 > inline bool //________________________________ - has_any (CON& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument + has_any (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument { return has_any (elements, std::tr1::bind (function, bind1)); } @@ -287,7 +310,7 @@ namespace util { , typename P2 > inline bool //________________________________ - has_any (CON& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments { return has_any (elements, std::tr1::bind (function, bind1, bind2)); } @@ -299,7 +322,7 @@ namespace util { , typename P3 > inline bool //________________________________ - has_any (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments { return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3)); } @@ -312,7 +335,7 @@ namespace util { , typename P4 > inline bool //________________________________ - has_any (CON& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments + has_any (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments { return has_any (elements, std::tr1::bind (function, bind1, bind2, bind3, bind4)); }