lumiera_/src/lib/util-foreach.hpp
Ichthyostega 09e7e1f8f5 WIP: pondering diff representation variants
Actually I arried at the conclusion, that the *receiving* of
a diff representation is actually a typical double-dispatch situation.
This leads to the attempt to come up with a specialised visitor
as standard pattern to handle and apply a diff. Obviously,
we do not want the classical GoF-Visitor, but (yes, we had
that discussion allready) -- well in terms of runtime cost,
we have to deal with at least two indirections anyway;
so now I'm exploring the idea to implement one of these
indirections through a functor object, which at the same time
acts as "Tag" in the diff representation language (instead
of using an enum as tag)
2014-11-10 04:00:39 +01:00

352 lines
11 KiB
C++

/*
UTIL-FOREACH.hpp - helpers for doing something for each element
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @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.
** - basic constructs
** - for_each
** - and_all (all quantisation)
** - has_any (existence quantisation)
** - kinds of collection
** - STL collections and anything which has an iterator, \c begin() and \c end()
** - "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
**
*/
#ifndef UTIL_FOREACH_H
#define UTIL_FOREACH_H
#include "lib/util.hpp"
#include "lib/meta/trait.hpp"
#include <boost/utility/enable_if.hpp>
#include <functional>
#include <algorithm>
namespace util {
using boost::enable_if;
using boost::disable_if;
using lib::meta::can_STL_ForEach;
using lib::meta::can_IterForEach;
/** All quantification: check if all elements of a collection
* satisfy the given predicate. Actually a short-circuit
* evaluation is performed.
*/
template <typename IT, typename FUN>
inline bool
and_all (IT i, IT end, FUN predicate)
{
for ( ; i!=end; ++i )
if (!predicate(*i))
return false;
return true;
}
/** Existential quantification: check if any element
* of a collection satisfies the given predicate.
* Actually, a short-circuit evaluation is performed.
*/
template <typename IT, typename FUN>
inline bool
has_any (IT i, IT end, FUN predicate)
{
for ( ; i!=end; ++i )
if (predicate(*i))
return true;
return false;
}
/* === specialisations for STL containers and Lumiera Forward Iterators === */
/** operate on all elements of a STL container.
* @note the container is taken by \c const& and
* the \c const is \em stripped before iteration.
* @todo reconsider if using rvalue references covers
* the "inline iteration" use case sufficiently,
* so that we can get rid of the unwrapping and
* thus get back to strict const correctness.
* @note this case is the default and kicks in
* \em unless we detect a Lumiera iterator.
* 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 const& coll, FUN doIt)
{
using lib::meta::unwrap;
return std::for_each (unwrap(coll).begin()
,unwrap(coll).end()
, doIt);
}
/** operate on a Lumiera Forward Iterator until exhaustion. */
template <typename IT
,typename FUN
>
inline typename enable_if< can_IterForEach<IT>,
FUN >::type
for_each (IT const& ii, FUN doIt)
{
return std::for_each (ii, IT(), doIt);
}
template <typename Container
,typename FUN
>
inline typename enable_if< can_STL_ForEach<Container>,
bool >::type
and_all (Container const& coll, FUN predicate)
{
using lib::meta::unwrap;
return and_all (unwrap(coll).begin()
,unwrap(coll).end()
, predicate);
}
template <typename IT
,typename FUN
>
inline typename enable_if< can_IterForEach<IT>,
bool >::type
and_all (IT const& ii, FUN predicate)
{
return and_all (ii, IT(), predicate);
}
template <typename Container
,typename FUN
>
inline typename enable_if< can_STL_ForEach<Container>,
bool >::type
has_any (Container const& coll, FUN predicate)
{
using lib::meta::unwrap;
return has_any (unwrap(coll).begin()
,unwrap(coll).end()
, predicate);
}
template <typename IT
,typename FUN
>
inline typename enable_if< can_IterForEach<IT>,
bool >::type
has_any (IT const& ii, FUN predicate)
{
return has_any (ii, IT(), predicate);
}
/* === allow creating argument binders on-the-fly === */
template < typename CON, typename FUN
, typename P1
>
inline void //________________________________
for_each (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument
{
for_each (elements, std::bind (function, bind1));
}
template < typename CON, typename FUN
, typename P1
, typename P2
>
inline void //________________________________
for_each (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments
{
for_each (elements, std::bind (function, bind1, bind2));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
>
inline void //________________________________
for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments
{
for_each (elements, std::bind (function, bind1, bind2, bind3));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
, typename P4
>
inline void //________________________________
for_each (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3, P4 bind4) ///< Accept binding for 4 Arguments
{
for_each (elements, std::bind (function, bind1, bind2, bind3, bind4));
}
template < typename CON, typename FUN
, typename P1
>
inline bool //________________________________
and_all (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument
{
return and_all (elements, std::bind<bool> (function, bind1));
}
template < typename CON, typename FUN
, typename P1
, typename P2
>
inline bool //________________________________
and_all (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments
{
return and_all (elements, std::bind<bool> (function, bind1, bind2));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
>
inline bool //________________________________
and_all (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments
{
return and_all (elements, std::bind<bool> (function, bind1, bind2, bind3));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
, typename P4
>
inline bool //________________________________
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::bind<bool> (function, bind1, bind2, bind3, bind4));
}
template < typename CON, typename FUN
, typename P1
>
inline bool //________________________________
has_any (CON const& elements, FUN function, P1 bind1) ///< Accept binding for 1 Argument
{
return has_any (elements, std::bind<bool> (function, bind1));
}
template < typename CON, typename FUN
, typename P1
, typename P2
>
inline bool //________________________________
has_any (CON const& elements, FUN function, P1 bind1, P2 bind2) ///< Accept binding for 2 Arguments
{
return has_any (elements, std::bind<bool> (function, bind1, bind2));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
>
inline bool //________________________________
has_any (CON const& elements, FUN function, P1 bind1, P2 bind2, P3 bind3) ///< Accept binding for 3 Arguments
{
return has_any (elements, std::bind<bool> (function, bind1, bind2, bind3));
}
template < typename CON, typename FUN
, typename P1
, typename P2
, typename P3
, typename P4
>
inline bool //________________________________
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::bind<bool> (function, bind1, bind2, bind3, bind4));
}
} // namespace util
#endif /*UTIL_FOREACH_H*/