* Lumiera source code always was copyrighted by individual contributors * there is no entity "Lumiera.org" which holds any copyrights * Lumiera source code is provided under the GPL Version 2+ == Explanations == Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above. For this to become legally effective, the ''File COPYING in the root directory is sufficient.'' The licensing header in each file is not strictly necessary, yet considered good practice; attaching a licence notice increases the likeliness that this information is retained in case someone extracts individual code files. However, it is not by the presence of some text, that legally binding licensing terms become effective; rather the fact matters that a given piece of code was provably copyrighted and published under a license. Even reformatting the code, renaming some variables or deleting parts of the code will not alter this legal situation, but rather creates a derivative work, which is likewise covered by the GPL! The most relevant information in the file header is the notice regarding the time of the first individual copyright claim. By virtue of this initial copyright, the first author is entitled to choose the terms of licensing. All further modifications are permitted and covered by the License. The specific wording or format of the copyright header is not legally relevant, as long as the intention to publish under the GPL remains clear. The extended wording was based on a recommendation by the FSF. It can be shortened, because the full terms of the license are provided alongside the distribution, in the file COPYING.
504 lines
16 KiB
C++
504 lines
16 KiB
C++
/*
|
||
ITER-SOURCE.hpp - an interface to build an opaque iterator-based data source
|
||
|
||
Copyright (C)
|
||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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. See the file COPYING for further details.
|
||
|
||
*/
|
||
|
||
/** @file iter-source.hpp
|
||
** Extension module to build an opaque data source, accessible as
|
||
** <i>Lumiera Forward Iterator</i>. It is based on combining an IterAdapter
|
||
** with classical polymorphism; here, the data source, which is addressed
|
||
** by IderAdapter through the "iteration control API", is abstracted behind
|
||
** an interface (with virtual functions). Together this allows to build
|
||
** a simple data source type, without needing to disclose details of
|
||
** the implementation.
|
||
**
|
||
** @todo the design used for the "iteration control API" is misaligned
|
||
** with the purpose of this adapter. Rather, it should be shaped
|
||
** similar to IterStateWrapper with three control functions //////////////////////////////////////TICKET #1125
|
||
**
|
||
** # Standard Adapters
|
||
** As a complement, this header contains a generic implementation
|
||
** of the IterSource interface by wrapping an existing Lumiera Forward Iterator.
|
||
** Using this WrappedLumieraIter, the details of this wrapped source iterator
|
||
** remain opaque. To ease the use of this adapter, a selection of free functions
|
||
** is provided, allowing to build opaque "all elements" or "all keys" iterators
|
||
** for various STL containers.
|
||
**
|
||
** @see iter-adapter.hpp
|
||
** @see itertool.hpp
|
||
** @see iter-source-test.cpp
|
||
**
|
||
*/
|
||
|
||
|
||
#ifndef LIB_ITER_SOURCE_H
|
||
#define LIB_ITER_SOURCE_H
|
||
|
||
|
||
#include "lib/meta/util.hpp"
|
||
#include "lib/iter-adapter.hpp"
|
||
#include "lib/itertools.hpp"
|
||
#include "lib/nocopy.hpp"
|
||
|
||
#include <type_traits>
|
||
#include <utility>
|
||
#include <string>
|
||
#include <memory>
|
||
|
||
|
||
|
||
|
||
namespace lib {
|
||
|
||
using std::string;
|
||
using std::shared_ptr;
|
||
using std::forward;
|
||
|
||
|
||
|
||
/**
|
||
* Iteration source interface to abstract a data source,
|
||
* which then can be accessed through IterAdapter as a frontend,
|
||
* allowing to pull individual elements until exhaustion.
|
||
*
|
||
* This base class is empty and makes no assumptions regarding
|
||
* identity, instantiation and copying.
|
||
*
|
||
* @see PlacementIndex::Table#_eachEntry_4check usage example
|
||
* @see iter-source-test.cpp
|
||
*/
|
||
template<typename TY>
|
||
class IterSource
|
||
{
|
||
|
||
protected: /* == data source API to implement == */
|
||
|
||
typedef TY* Pos;
|
||
typedef shared_ptr<IterSource> DataHandle;
|
||
|
||
///////////////////////////////////////////////TICKET #1125 : this API should use three control functions, similar to IterStateWrapper
|
||
/** iteration start: prepare the first element.
|
||
* may return NULL in case of empty data source
|
||
*/
|
||
virtual Pos firstResult () =0;
|
||
|
||
/** iteration step: switch on to the next element.
|
||
* The pos pointer should be set to NULL to report
|
||
* iteration end
|
||
*/
|
||
virtual void nextResult(Pos& pos) =0;
|
||
|
||
/** disconnect the data source / iteration frontend.
|
||
* Depending on the way the IterSource got created
|
||
* this \em might (or might not) be followed by
|
||
* destroying the data source.
|
||
* @note must not throw
|
||
*/
|
||
virtual void disconnect () { }
|
||
|
||
|
||
|
||
public:
|
||
virtual ~IterSource() { }; ///< is ABC
|
||
|
||
virtual
|
||
operator string() const ///< subclasses may offer diagnostics
|
||
{
|
||
return "IterSource<" + lib::meta::typeStr<TY>()+ ">";
|
||
}
|
||
|
||
|
||
/* == Iteration control API for IterAdapter frontend == */
|
||
|
||
friend bool ////////////////////////////////////////TICKET #1125 : this API should use three control functions, similar to IterStateWrapper
|
||
checkPoint (DataHandle const&, Pos const& pos)
|
||
{
|
||
return bool(pos);
|
||
}
|
||
|
||
friend void
|
||
iterNext (DataHandle& source, Pos& pos)
|
||
{
|
||
ASSERT (source);
|
||
source->nextResult(pos);
|
||
}
|
||
|
||
|
||
/* == public builder API to create instances == */
|
||
|
||
struct iterator
|
||
: IterAdapter<Pos, DataHandle>
|
||
{ ////////////////////////////////////////////////////TICKET #1125 : should be build on top of IterStateWrapper rather than IterAdapter!
|
||
using _I = IterAdapter<Pos, DataHandle>;
|
||
using _I::IterAdapter;
|
||
|
||
operator string() const {return _I::source()? string(*_I::source()) : "⟂"; }
|
||
};
|
||
|
||
/** build an iterator frontend for the given source,
|
||
* @note the source is allocated separately and
|
||
* \em not owned by the iterator frontend
|
||
*/
|
||
static iterator
|
||
build (IterSource& sourceImpl)
|
||
{
|
||
return std::move(
|
||
startIteration (DataHandle{&sourceImpl, &detach_without_destroy}));
|
||
}
|
||
|
||
/** build an iterator frontend, thereby managing
|
||
* the given heap allocated source object instance.
|
||
* @note we take ownership and destroy the source
|
||
* when the last copy of the created iterator
|
||
* goes out of scope.
|
||
*/
|
||
static iterator
|
||
build (IterSource* sourceImplObject)
|
||
{
|
||
return std::move(
|
||
startIteration (DataHandle{sourceImplObject, &destroy_managed_source}));
|
||
}
|
||
|
||
static iterator EMPTY_SOURCE;
|
||
|
||
using value_type = TY;
|
||
using reference = TY&;
|
||
using pointer = TY*;
|
||
|
||
|
||
|
||
private:
|
||
static iterator
|
||
startIteration (DataHandle sourceHandle)
|
||
{
|
||
REQUIRE (sourceHandle);
|
||
Pos first = sourceHandle->firstResult();
|
||
return {move(sourceHandle), first};
|
||
}
|
||
|
||
|
||
static void
|
||
detach_without_destroy (IterSource * source)
|
||
{
|
||
WARN_IF (!source, library, "IterSource deleter called with NULL source pointer");
|
||
if (source)
|
||
source->disconnect();
|
||
}
|
||
|
||
static void
|
||
destroy_managed_source (IterSource * source)
|
||
{
|
||
WARN_IF (!source, library, "IterSource deleter called with NULL source pointer");
|
||
if (source)
|
||
{
|
||
source->disconnect();
|
||
delete source;
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
/** storage for the empty data-source constant */
|
||
template<typename TY>
|
||
typename IterSource<TY>::iterator IterSource<TY>::EMPTY_SOURCE = iterator();
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
* Standard implementation of the IterSource interface:
|
||
* a wrapped "Lumiera Forward Iterator". Usually, such a wrapper instance
|
||
* is passed to one of the IterSource's builder functions, thereby
|
||
* erasing the specific type information of the template parameter IT
|
||
*/
|
||
template<class IT, class ISO = IterSource<typename meta::ValueTypeBinding<IT>::value_type>>
|
||
class WrappedLumieraIter
|
||
: public ISO
|
||
, util::NonCopyable
|
||
{
|
||
IT src_;
|
||
|
||
protected:
|
||
using Pos = typename ISO::Pos;
|
||
|
||
Pos ////////////////////////////////////////////////////TICKET #1125 : this API should use three control functions, similar to IterStateWrapper
|
||
firstResult ()
|
||
{
|
||
if (!src_)
|
||
return 0;
|
||
else
|
||
return & *src_;
|
||
}
|
||
|
||
void
|
||
nextResult (Pos& pos)
|
||
{
|
||
if (!pos) return;
|
||
if (src_) ++src_;
|
||
if (src_)
|
||
pos = & *src_;
|
||
else
|
||
pos = 0;
|
||
}
|
||
|
||
|
||
|
||
public:
|
||
WrappedLumieraIter (IT const& orig)
|
||
: src_(orig)
|
||
{ }
|
||
|
||
WrappedLumieraIter (IT&& orig)
|
||
: src_(forward<IT>(orig))
|
||
{ }
|
||
|
||
|
||
protected:
|
||
IT& wrappedIter() { return src_; }
|
||
IT const& wrappedIter() const { return src_; }
|
||
};
|
||
|
||
|
||
|
||
|
||
/* === pre-defined Adapters for frequently used Containers === */
|
||
|
||
namespace iter_source {
|
||
namespace { // traits and helpers...
|
||
|
||
template<class CON>
|
||
struct _SeqT
|
||
{
|
||
using Val = typename CON::iterator::value_type;
|
||
using Iter = typename IterSource<Val>::iterator;
|
||
};
|
||
|
||
template<class IT>
|
||
struct _RangeT
|
||
{
|
||
using Val = typename IT::value_type;
|
||
using Iter = typename IterSource<Val>::iterator;
|
||
};
|
||
|
||
template<class MAP>
|
||
struct _MapT
|
||
{
|
||
using Key = typename MAP::key_type;
|
||
using Val = typename MAP::value_type::second_type;
|
||
using KeyIter = typename IterSource<Key>::iterator;
|
||
using ValIter = typename IterSource<Val>::iterator;
|
||
};
|
||
|
||
|
||
template<class IT>
|
||
struct _IterT
|
||
{
|
||
using Src = typename std::remove_reference<IT>::type;
|
||
using Val = typename Src::value_type;
|
||
using Iter = typename IterSource<Val>::iterator;
|
||
};
|
||
|
||
template<class IT, class FUN>
|
||
struct _TransformIterT
|
||
{
|
||
using Src = typename std::remove_reference<IT>::type;
|
||
using ResVal = typename lib::meta::_Fun<FUN>::Ret;
|
||
using TransIter = TransformIter<Src, ResVal>;
|
||
using Iter = typename IterSource<ResVal>::iterator;
|
||
};
|
||
|
||
template<class IT>
|
||
struct _PairIterT
|
||
{
|
||
using Src = typename std::remove_reference<IT>::type;
|
||
using PairType = typename Src::value_type;
|
||
using ValType = typename PairType::second_type;
|
||
using ConstKeyType = typename PairType::first_type;
|
||
|
||
// since we're returning the keys always by value,
|
||
// we can strip the const added by the STL map types
|
||
using KeyType = typename std::remove_const<ConstKeyType>::type;
|
||
|
||
typedef TransformIter<Src, KeyType> KeyIter;
|
||
typedef TransformIter<Src, ValType> ValIter;
|
||
|
||
static KeyType takeFirst (PairType const& pair) { return pair.first; }
|
||
static ValType takeSecond(PairType const& pair) { return pair.second;}
|
||
};
|
||
|
||
|
||
template<class IT>
|
||
typename _PairIterT<IT>::KeyIter
|
||
takePairFirst (IT&& source)
|
||
{
|
||
return transformIterator(forward<IT>(source), _PairIterT<IT>::takeFirst );
|
||
}
|
||
|
||
template<class IT>
|
||
typename _PairIterT<IT>::ValIter
|
||
takePairSecond (IT&& source)
|
||
{
|
||
return transformIterator(forward<IT>(source), _PairIterT<IT>::takeSecond );
|
||
}
|
||
|
||
} //(END) type helpers...
|
||
|
||
|
||
|
||
/** wraps a given Lumiera Forward Iterator,
|
||
* exposing just a IterSource based frontend.
|
||
*/
|
||
template<class IT>
|
||
typename _IterT<IT>::Iter
|
||
wrapIter (IT&& source)
|
||
{
|
||
using Src = typename _IterT<IT>::Src;
|
||
using Val = typename _IterT<IT>::Val;
|
||
|
||
return IterSource<Val>::build (new WrappedLumieraIter<Src> (forward<IT>(source)));
|
||
}
|
||
|
||
|
||
/** an IterSource frontend to return just a single value once.
|
||
* @warning behind the scenes, a heap allocation is managed by shared_ptr,
|
||
* to maintain a copy of the wrapped element. When passing a reference,
|
||
* only a reference will be wrapped, but a heap allocation happens nonetheless
|
||
*/
|
||
template<typename VAL>
|
||
auto
|
||
singleVal (VAL&& something)
|
||
{
|
||
using Src = decltype(singleValIterator (forward<VAL>(something)));
|
||
using Val = typename _IterT<Src>::Val;
|
||
|
||
return IterSource<Val>::build (new WrappedLumieraIter<Src>{singleValIterator (forward<VAL>(something))});
|
||
}
|
||
|
||
|
||
/** pipes a given Lumiera Forward Iterator through
|
||
* a transformation function and wraps the resulting
|
||
* transforming Iterator, exposing just an IterSource.
|
||
* This convenience shortcut can be used to build a
|
||
* processing chain; the resulting IterSource will
|
||
* hide any detail types involved.
|
||
* @note as with any IterSource, there is one virtual
|
||
* function call for every fetched element.
|
||
*/
|
||
template<class IT, class FUN>
|
||
typename _TransformIterT<IT,FUN>::Iter
|
||
transform (IT&& source, FUN processingFunc)
|
||
{
|
||
typedef typename _TransformIterT<IT,FUN>::ResVal ValType;
|
||
typedef typename _TransformIterT<IT,FUN>::TransIter TransIT;
|
||
|
||
return IterSource<ValType>::build (
|
||
new WrappedLumieraIter<TransIT> (
|
||
transformIterator (forward<IT>(source), processingFunc)));
|
||
}
|
||
|
||
|
||
/** @return a Lumiera Forward Iterator to yield
|
||
* all the keys of the given Map or Hashtable
|
||
*/
|
||
template<class MAP>
|
||
typename _MapT<MAP>::KeyIter
|
||
eachMapKey (MAP& map)
|
||
{
|
||
using Range = RangeIter<typename MAP::iterator>;
|
||
|
||
Range contents (map.begin(), map.end());
|
||
return wrapIter (takePairFirst (contents));
|
||
}
|
||
|
||
|
||
/** @return a Lumiera Forward Iterator to yield
|
||
* all the values of the given Map or Hashtable
|
||
*/
|
||
template<class MAP>
|
||
typename _MapT<MAP>::ValIter
|
||
eachMapVal (MAP& map)
|
||
{
|
||
using Range = RangeIter<typename MAP::iterator>;
|
||
|
||
Range contents (map.begin(), map.end());
|
||
return wrapIter (takePairSecond(contents));
|
||
}
|
||
|
||
|
||
/** @return a Lumiera Forward Iterator to yield
|
||
* all \em distinct keys of a Multimap
|
||
* @warning we do a full table scan to find
|
||
* the distinct keys
|
||
*/
|
||
template<class MAP>
|
||
typename _MapT<MAP>::KeyIter
|
||
eachDistinctKey (MAP& map)
|
||
{
|
||
using Range = RangeIter<typename MAP::iterator>;
|
||
|
||
Range contents (map.begin(), map.end());
|
||
return wrapIter (filterRepetitions (takePairFirst(contents)));
|
||
}
|
||
|
||
|
||
/** @return a Lumiera Forward Iterator to yield all values
|
||
* associated to the given key within this Map or Multimap
|
||
* @note obviously in case of a Map we'll get at most one result.
|
||
*/
|
||
template<class MAP>
|
||
typename _MapT<MAP>::ValIter
|
||
eachValForKey (MAP& map, typename _MapT<MAP>::Key key)
|
||
{
|
||
using Pos = typename MAP::iterator;
|
||
using Range = RangeIter<Pos>;
|
||
|
||
std::pair<Pos,Pos> valuesForKey = map.equal_range(key);
|
||
Range contents (valuesForKey.first, valuesForKey.second);
|
||
return wrapIter (takePairSecond(contents));
|
||
}
|
||
|
||
|
||
/** @param container a STL-like container, providing
|
||
* - a typedef \c iterator
|
||
* - functions \c begin() and \c end()
|
||
* @return a Lumiera Forward Iterator yielding all values
|
||
* starting with \c begin and excluding \c end .
|
||
*/
|
||
template<class CON>
|
||
typename _SeqT<CON>::Iter
|
||
eachEntry (CON& container)
|
||
{
|
||
using ValType = typename _SeqT<CON>::Val;
|
||
using Range = RangeIter<typename CON::iterator>;
|
||
|
||
Range contents (container.begin(), container.end());
|
||
return IterSource<ValType>::build (new WrappedLumieraIter<Range>(contents));
|
||
}
|
||
|
||
|
||
/** @return a Lumiera Forward Iterator to yield all values
|
||
* defined by a classical Iterator range.
|
||
*/
|
||
template<class IT>
|
||
typename _RangeT<IT>::Iter
|
||
eachEntry (IT const& begin, IT const& end)
|
||
{
|
||
using ValType = typename _RangeT<IT>::Val;
|
||
using Range = RangeIter<IT>;
|
||
|
||
Range contents (begin, end);
|
||
return IterSource<ValType>::build (new WrappedLumieraIter<Range>(contents));
|
||
}
|
||
|
||
|
||
}} // namespace lib::iter_source
|
||
#endif
|