2012-05-14 05:24:16 +02:00
|
|
|
/*
|
|
|
|
|
ITER-EXPLORER.hpp - building blocks for iterator evaluation strategies
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2012, 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 iter-explorer.hpp
|
|
|
|
|
** Helper template(s) for establishing various evaluation strategies for hierarchical data structures.
|
|
|
|
|
** Based on the <b>Lumiera Forward Iterators</b> concept and using the basic IterAdaptor templates,
|
|
|
|
|
** these components allow to implement typical evaluation strategies, like e.g. depth-first or
|
|
|
|
|
** breadth-first exploration of a hierarchical structure. Since the access to this structure is
|
|
|
|
|
** abstracted through the underlying iterator, what we effectively get is a functional datastructure.
|
2012-05-23 04:06:24 +02:00
|
|
|
** The implementation is based on the IterStateWrapper, which is one of the basic helper templates
|
2012-05-14 05:24:16 +02:00
|
|
|
** provided by iter-adapter.hpp.
|
|
|
|
|
**
|
|
|
|
|
** @see IterExplorer_test.cpp
|
|
|
|
|
** @see iter-adapter.hpp
|
|
|
|
|
** @see itertools.hpp
|
|
|
|
|
** @see IterSource (completely opaque iterator)
|
|
|
|
|
**
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_ITER_EXPLORER_H
|
|
|
|
|
#define LIB_ITER_EXPLORER_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
//#include "lib/bool-checkable.hpp"
|
2012-05-23 04:06:24 +02:00
|
|
|
#include "lib/meta/function.hpp"
|
2012-05-14 05:24:16 +02:00
|
|
|
#include "lib/iter-adapter.hpp"
|
|
|
|
|
|
|
|
|
|
//#include <boost/type_traits/remove_const.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
2012-05-23 04:06:24 +02:00
|
|
|
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // internal helpers
|
2012-05-23 04:06:24 +02:00
|
|
|
|
|
|
|
|
using std::tr1::function;
|
|
|
|
|
using meta::FunctionSignature;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper to dissect an arbitrary function signature,
|
|
|
|
|
* irrespective if the parameter is given as function reference,
|
|
|
|
|
* function pointer, member function pointer or functor object.
|
|
|
|
|
* The base case assumes a (language) function reference.
|
|
|
|
|
*/
|
|
|
|
|
template<typename SIG>
|
|
|
|
|
struct _Fun
|
|
|
|
|
{
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
|
|
|
|
};
|
|
|
|
|
/** Specialisation for using a function pointer */
|
|
|
|
|
template<typename SIG>
|
|
|
|
|
struct _Fun<SIG*>
|
|
|
|
|
{
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
|
|
|
|
};
|
|
|
|
|
/** Specialisation for passing a functor */
|
|
|
|
|
template<typename SIG>
|
|
|
|
|
struct _Fun<function<SIG> >
|
|
|
|
|
{
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
|
|
|
|
|
typedef typename FunctionSignature<function<SIG> >::Args Args;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-05-14 05:24:16 +02:00
|
|
|
}
|
2012-05-23 04:06:24 +02:00
|
|
|
|
|
|
|
|
namespace iter_explorer {
|
|
|
|
|
|
|
|
|
|
template<class FUN>
|
|
|
|
|
class DefaultCombinator;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2012-05-23 04:06:24 +02:00
|
|
|
* Adapter for using an Iterator in the way of a Monad
|
|
|
|
|
* This allows to "bind" or "flatMap" a functor, thereby creating
|
|
|
|
|
* a derived version of the iterator, yielding the (flattened) combination
|
|
|
|
|
* of all the results generated by this bound functor. The rationale is
|
|
|
|
|
* to apply some exploration or expansion pattern on the elements of the
|
|
|
|
|
* source sequence (source iterator) -- while completely separating out
|
|
|
|
|
* the \em mechanics how to treat and combine individual elements.
|
|
|
|
|
*
|
|
|
|
|
* \par implementation approach
|
|
|
|
|
* IterExplorer is a thin wrapper, based on IterStateWrapper; thus the assumption
|
|
|
|
|
* is for the actual elements to be generated by a "state core", which is embedded
|
|
|
|
|
* right into each instance. To provide the monad bind operator \c >>= , we need
|
|
|
|
|
* the help of a strategy template, the so called \em Combinator. This strategy
|
|
|
|
|
* contains the details how to combine the results of various iterators and
|
|
|
|
|
* to join them together into a single new IterExplorer instance. Thus, obviously
|
|
|
|
|
* this Combinator strategy template relies on additional knowledge about the
|
|
|
|
|
* source iterator's implementation. Such is unavoidable, since C++ isn't a
|
|
|
|
|
* functional programming language.
|
|
|
|
|
*
|
|
|
|
|
* When invoking the bind (flat map) operator, a suitably represented \em functor
|
|
|
|
|
* is embedded into an instance of the Combinator template. The resulting object
|
|
|
|
|
* becomes the state core of the new IterExplorer object returned as result.
|
|
|
|
|
* So the result \em is an iterator, but -- when "pulled" -- it will in turn
|
|
|
|
|
* pull from the source iterator and feed the provided elements through the
|
|
|
|
|
* \em exploration functor, which this way has been \em bound into the resulting
|
|
|
|
|
* monad. The purpose of the Combinator strategy is to join together various
|
|
|
|
|
* resulting iterators, thereby "flattening" one level of "monad packaging"
|
|
|
|
|
* (hence the name "flat map operator").
|
|
|
|
|
*
|
|
|
|
|
* @remarks figuring out what happens here just from the code might lead to confusion.
|
|
|
|
|
* You really need to grasp the monad concept first, which is a design pattern
|
|
|
|
|
* commonly used in functional programming. For the practical purpose in question
|
|
|
|
|
* here, you might consider it a "programmable semicolon": it links together a
|
|
|
|
|
* chain of operations detailed elsewhere, and provided in a dynamic fashion
|
|
|
|
|
* (as functor at runtime). More specifically, these operations will expand
|
|
|
|
|
* and explore a dynamic source data set on the fly. Notably this allows
|
|
|
|
|
* us to handle such an "exploration" on-the-fly, without the need to
|
|
|
|
|
* allocate heap memory to store intermediary results, but also without
|
|
|
|
|
* using the stack and recursive programming.
|
2012-05-14 05:24:16 +02:00
|
|
|
*/
|
2012-05-23 04:06:24 +02:00
|
|
|
template<class SRC
|
|
|
|
|
,template<class> class _COM_ = iter_explorer::DefaultCombinator
|
|
|
|
|
>
|
2012-05-14 05:24:16 +02:00
|
|
|
class IterExplorer
|
2012-05-23 04:06:24 +02:00
|
|
|
: public IterStateWrapper<typename SRC::value_type, SRC>
|
2012-05-14 05:24:16 +02:00
|
|
|
{
|
2012-05-23 04:06:24 +02:00
|
|
|
|
|
|
|
|
typedef typename SRC::value_type value_type;
|
|
|
|
|
typedef typename SRC::reference reference;
|
|
|
|
|
|
|
|
|
|
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
public:
|
2012-05-23 04:06:24 +02:00
|
|
|
/** wrap an iterator like state representation
|
|
|
|
|
* to build it into a monad. The resulting entity
|
|
|
|
|
* is both an iterator yielding the elements generated
|
|
|
|
|
* by the core, and it provides the (monad) bind operator.
|
|
|
|
|
*/
|
|
|
|
|
explicit
|
|
|
|
|
IterExplorer (SRC const& iterStateCore)
|
|
|
|
|
: IterStateWrapper<value_type, SRC> (iterStateCore)
|
|
|
|
|
{ }
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
|
2012-05-23 04:06:24 +02:00
|
|
|
/** monad bind ("flat map") operator */
|
|
|
|
|
template<class FUN>
|
|
|
|
|
IterExplorer<_COM_<FUN>, _COM_>
|
|
|
|
|
operator >>= (FUN explorer)
|
|
|
|
|
{
|
|
|
|
|
typedef _COM_<FUN> Combinator;
|
|
|
|
|
|
|
|
|
|
return IterExplorer(
|
|
|
|
|
Combinator(explorer)
|
|
|
|
|
.startWith( explorer(accessFirstElement()))
|
|
|
|
|
.followUp (accessRemainingElements()));
|
|
|
|
|
}
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
2012-05-23 04:06:24 +02:00
|
|
|
|
|
|
|
|
reference
|
|
|
|
|
accessFirstElement()
|
|
|
|
|
{
|
|
|
|
|
return this->operator* ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IterExplorer&
|
|
|
|
|
accessRemainingElements()
|
|
|
|
|
{
|
|
|
|
|
this->operator++ ();
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2012-05-14 05:24:16 +02:00
|
|
|
};
|
2012-05-23 04:06:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace iter_explorer { ///< predefined policies and configurations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* a generic "Combinator strategy" for IterExplorer.
|
|
|
|
|
* This fallback solution just assumes that the source is a
|
|
|
|
|
* Lumiera Forward Iterator -- consequently we need to do heap
|
|
|
|
|
* allocations behind the scenes, as the size and structure of
|
|
|
|
|
* the expansion results is determined at runtime.
|
|
|
|
|
* @note the whole purpose of IterExplorer is to be more efficient
|
|
|
|
|
* then this fallback, thus requiring more specific Combinator
|
|
|
|
|
* strategies, able to exploit specific knowledge of the
|
|
|
|
|
* source iterator's implementation.
|
|
|
|
|
*/
|
|
|
|
|
template<class FUN>
|
|
|
|
|
class DefaultCombinator
|
|
|
|
|
{
|
|
|
|
|
typedef typename _Fun<FUN>::Ret ResultIter;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
typedef typename ResultIter::value_type value_type;
|
|
|
|
|
typedef typename ResultIter::reference reference;
|
|
|
|
|
typedef typename ResultIter::pointer pointer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DefaultCombinator(FUN explorer)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("representation of the sequence of partial results");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DefaultCombinator &
|
|
|
|
|
startWith (ResultIter firstExplorationResult)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("DefaultCombinator: yield first result");
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class SRC>
|
|
|
|
|
DefaultCombinator&
|
|
|
|
|
followUp (SRC followUpSourceElements)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("DefaultCombinator: follow up iteration");
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* === Iteration control API for IterStateWrapper== */
|
|
|
|
|
|
|
|
|
|
friend bool
|
|
|
|
|
checkPoint (DefaultCombinator const& sequence)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("how to determine exhausted state on the combined results");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend reference
|
|
|
|
|
yield (DefaultCombinator const& sequence)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("how to yield a result from the combined iterator");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend void
|
|
|
|
|
iterNext (DefaultCombinator & sequence)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED ("increment the source iterator and switch to the next partial result sequence if necessary");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper template to bootstrap a chain of IterExplorers.
|
|
|
|
|
* This is a "state corer", which basically just wraps a given
|
|
|
|
|
* source iterator and provides the necessary free functions
|
|
|
|
|
* (iteration control API) to use this as iteration state
|
|
|
|
|
* within IterExplorer.
|
|
|
|
|
* @note to ease building such an initial version of the Iterator Monad,
|
|
|
|
|
* use the free function \link #exploreIter \endlink
|
|
|
|
|
*/
|
|
|
|
|
template<class IT>
|
|
|
|
|
class WrappedSequence
|
|
|
|
|
: public IT
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
WrappedSequence()
|
|
|
|
|
: IT()
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
WrappedSequence(IT const& srcIter)
|
|
|
|
|
: IT(srcIter)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* === Iteration control API for IterStateWrapper == */
|
|
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
|
checkPoint (WrappedSequence const& sequence)
|
|
|
|
|
{
|
|
|
|
|
return bool(sequence);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline typename IT::reference
|
|
|
|
|
yield (WrappedSequence const& sequence)
|
|
|
|
|
{
|
|
|
|
|
return *sequence;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
iterNext (WrappedSequence & sequence)
|
|
|
|
|
{
|
|
|
|
|
++sequence;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}//(End) namespace iter_explorer : predefined policies and configurations
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class IT>
|
|
|
|
|
IterExplorer<iter_explorer::WrappedSequence<IT> >
|
|
|
|
|
exploreIter (IT const& srcSeq)
|
|
|
|
|
{
|
|
|
|
|
return IterExplorer<iter_explorer::WrappedSequence<IT> > (srcSeq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-05-14 05:24:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace lib
|
|
|
|
|
#endif
|