somewhat tricky modification of for-each, allowing inline calls

This commit is contained in:
Fischlurch 2010-01-07 03:10:02 +01:00
parent 226ed37e30
commit 3525b77126
2 changed files with 195 additions and 34 deletions

View file

@ -31,15 +31,150 @@
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_arithmetic.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/utility/enable_if.hpp>
#include <string>
//Forward declarations for the Unwrap helper....
namespace boost{
template<class X> class reference_wrapper;
}
namespace std {
namespace tr1 {
template<class X> class reference_wrapper;
template<class X> class shared_ptr;
}}
namespace lumiera{
template<class X, class B> class P;
}
namespace mobject{
template<class X, class B> 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<typename X>
struct Unwrap
{
typedef X Type;
static X&
extract (X const& x)
{
return const_cast<X&> (x);
}
};
template<typename X>
struct Unwrap<X*>
{
typedef X Type;
static X&
extract (const X* ptr)
{
ASSERT (ptr);
return const_cast<X&> (*ptr);
}
};
template<typename X>
struct Unwrap<boost::reference_wrapper<X> >
{
typedef X Type;
static X&
extract (boost::reference_wrapper<X> wrapped)
{
return wrapped;
}
};
template<typename X>
struct Unwrap<std::tr1::reference_wrapper<X> >
{
typedef X Type;
static X&
extract (std::tr1::reference_wrapper<X> wrapped)
{
return wrapped;
}
};
template<typename X>
struct Unwrap<std::tr1::shared_ptr<X> >
{
typedef X Type;
static X&
extract (std::tr1::shared_ptr<X> ptr)
{
ASSERT (ptr);
return *ptr;
}
};
template<typename X, class B>
struct Unwrap<lumiera::P<X, B> >
{
typedef X Type;
static X&
extract (lumiera::P<X,B> ptr)
{
ASSERT (ptr);
return *ptr;
}
};
template<typename X, class B>
struct Unwrap<mobject::Placement<X, B> >
{
typedef X Type;
static X&
extract (mobject::Placement<X,B> placement)
{
ASSERT (placement.isValid());
return *placement;
}
};
/** convenience shortcut: unwrapping free function */
template<typename X>
typename Unwrap<X>::Type&
unwrap (X const& wrapped)
{
return Unwrap<X>::extract(wrapped);
}
/** Helper for type analysis: tries to strip all kinds of type adornments */
template<typename X>
struct Strip
{
typedef typename boost::remove_cv<X> ::type TypeUnconst;
typedef typename boost::remove_reference<TypeUnconst>::type TypeReferred;
typedef typename boost::remove_pointer<TypeReferred> ::type TypePointee;
typedef typename boost::remove_cv<TypePointee> ::type TypePlain;
typedef typename Unwrap<TypePlain> ::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<typename T>
class can_STL_ForEach
{
typedef typename Strip<T>::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<T>::value
&& HasFunSig_begin<T>::value
&& HasFunSig_end<T>::value
enum { value = HasNested_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::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<T>::value
&& HasFunSig_begin<T>::value
&& HasFunSig_end<T>::value
enum { value = HasNested_const_iterator<Type>::value
&& HasFunSig_begin<Type>::value
&& HasFunSig_end<Type>::value
};
};
@ -120,16 +257,17 @@ namespace meta {
template<typename T>
class can_IterForEach
{
typedef typename Strip<T>::Type Type;
META_DETECT_NESTED(value_type);
META_DETECT_OPERATOR_DEREF();
META_DETECT_OPERATOR_INC();
public:
enum{ value = boost::is_convertible<T, bool>::value
&& HasNested_value_type<T>::value
&& HasOperator_deref<T>::value
&& HasOperator_inc<T>::value
enum{ value = boost::is_convertible<Type, bool>::value
&& HasNested_value_type<Type>::value
&& HasOperator_deref<Type>::value
&& HasOperator_inc<Type>::value
};
};

View file

@ -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 <b>const is stripped</b> 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 <b>stripped silently</b>, 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 <typename Container
,typename FUN
>
inline typename disable_if< can_IterForEach<Container>,
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<IT>,
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<Container>,
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<IT>,
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<Container>,
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<IT>,
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<bool> (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<bool> (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<bool> (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<bool> (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<bool> (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<bool> (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<bool> (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<bool> (function, bind1, bind2, bind3, bind4));
}