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)
352 lines
11 KiB
C++
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*/
|