C++11: improve moving and forwarding of iterators
this becomes more relevant now, since the actual MutationMessage iterators are implemented in terms of a shared_ptr to IterSource. Thus, when building processing pipelines, we most definitively want to move that smart-ptr into the destination, since this avoids touching the shared count and thus avoids generating unnecessary memory barriers.
This commit is contained in:
parent
4a2384e242
commit
d4ac2d78e2
7 changed files with 184 additions and 78 deletions
|
|
@ -12,7 +12,7 @@ language and compiler support wasn't ready for what we consider _state of the cr
|
|||
amended deficiencies by rolling our own helper facilities, with a little help from Boost.
|
||||
Thus there was no urge for us to adopt the new language standard; we could simply wait for
|
||||
the compiler support to mature. In spring 2014, finally, we were able to switch our codebase
|
||||
to C++11 with minimal effort.footnote[since 8/2015 -- after the switch to Debian/Jessie
|
||||
to C++11 with minimal effort.footnote:[since 8/2015 -- after the switch to Debian/Jessie
|
||||
as a »reference platform«, we even compile with `-std=gnu++14`]
|
||||
Following this switch, we're now able to reap the benefits of
|
||||
this approach; we may now gradually replace our sometimes clunky helpers and workarounds
|
||||
|
|
@ -112,7 +112,9 @@ were thinking since ages; it is more like an official affirmation of that style
|
|||
********************************************************************************************
|
||||
The core idea is that at times you need to 'move' a value due to a change of ownership. Now,
|
||||
the explicit support for 'move semantics' allows to decouple this 'conceptual move' from actually
|
||||
moving memory contents on the raw implementation level. The whole idea behind C++ seems to be
|
||||
moving memory contents on the raw implementation level. If we use a _rvalue reference on a signature,_
|
||||
we express that an entiy is or can be moved on a conceptual level; typically the actual implementation
|
||||
of this moving is _delegated_ and done by ``someone else''. The whole idea behind C++ seems to be
|
||||
allowing people to think on a conceptual level, while 'retaining' awareness of the gory details
|
||||
below the hood. Such is achieved by 'removing' the need to worry about details, confident that
|
||||
there is a way to deal with those concerns in an orthogonal fashion.
|
||||
|
|
@ -137,6 +139,40 @@ CAUTION: as soon as there is an explicitly defined copy operation, or even just
|
|||
compromise decision of the C++ committee -- instead of either breaking no code at all or
|
||||
boldly breaking code, they settled upon ``somewhat'' breaking existing code...
|
||||
|
||||
Perfect forwarding
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
The ``perfect forwarding'' technique is how we actually pass on and delegate move semantics.
|
||||
In conjunction with variadic templates, this technique promises to obsolete a lot of template trickery
|
||||
when it comes to implementing custom containers, allocators or similar kinds of managing wrappers.
|
||||
|
||||
.a typical example
|
||||
[source,c]
|
||||
--------------------------------------------------------------------------
|
||||
template<class TY, typename...ARGS>
|
||||
TY&
|
||||
create (ARGS&& ...args)
|
||||
{
|
||||
return *new(&buf_) TY {std::forward<ARGS> (args)...};
|
||||
}
|
||||
--------------------------------------------------------------------------
|
||||
The result is a `create()` function with the ability to _forward_ an arbitrary number of arguments
|
||||
of arbitrary type to the constructor of type `TY`. Note the following details
|
||||
|
||||
- the template parameter `ARGS&&` leads to deducing the actual parameters _sans_ rvalue reference
|
||||
- we pass each argument through `std::forward<ARGS>`. This is necessary to overcome the basic limitation
|
||||
that a rvalue reference can only bind to _something unnamed_. This is a safety feature; moving destroys
|
||||
the contents at the source location. Thus if we really want to move something known by name (like e.g.
|
||||
the function arguments in this example), we need to indicate so by an explicit call.
|
||||
- `std::forward` needs an explicit type parameter to be able to deduce the right target type in any case
|
||||
- note how we're allowed to ``wrap'' a function call around the unpacking of the _argument pack_ (`args`):
|
||||
the three dots `...` are _outside_ the parenthesis, and thus the `std::forward` is applied to each of
|
||||
the arguments individually
|
||||
|
||||
NOTE: forwarding calls can be chained, but at some point you get to acutally _consuming_ the value passed through.
|
||||
To support the maximum flexibility at this point, you typically need to write two flavours of the receiving
|
||||
function or constructor: one version taking a rvalue reference, and one version taking `const&`. Moving is
|
||||
_destructive_, while the `const&` variant deals with all those cases where we copy without affecting the
|
||||
source object.
|
||||
|
||||
|
||||
|
||||
|
|
@ -159,13 +195,11 @@ September 2014::
|
|||
requirement level_ soon.
|
||||
August 2015::
|
||||
our »reference system« (platform) is Debian/Jessie from now on.
|
||||
We have switched to **C++14** and use (even require) GCC-4.9 or CLang 3.5 -- we can expect solid support
|
||||
for all C++11 features and most C++14 features.
|
||||
We have switched to **C\+\+14** and use (even require) GCC-4.9 or CLang 3.5 -- we can expect solid support
|
||||
for all C\+\+11 features and most C++14 features.
|
||||
|
||||
Perfect forwarding
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
The ``perfect forwarding'' technique in conjunction with variadic templates promises to obsolete a lot of
|
||||
template trickery when it comes to implementing custom containers, allocators or similar kinds of managing wrappers.
|
||||
Unfortunately, we ran into nasty problems with both GCC-4.7 and CLang 3.0 here, when chaining several forwarding calls.
|
||||
|
||||
- the new _reference collapsing rules_ seem to be unreliably still. Note that even the standard library uses an
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ namespace diff{
|
|||
|
||||
|
||||
DiffMessage() = default;
|
||||
// default copy operations acceptable
|
||||
|
||||
/**
|
||||
* DiffMessage builder:
|
||||
|
|
@ -132,8 +133,8 @@ namespace diff{
|
|||
* @note source iterator is copied into a heap allocated IterSource
|
||||
*/
|
||||
template<class IT>
|
||||
DiffMessage(IT ii, enable_if< can_IterForEach<IT>, void*> =nullptr)
|
||||
: _FrontEnd{iter_source::wrapIter(ii)}
|
||||
DiffMessage(IT&& ii, enable_if< can_IterForEach<IT>, void*> =nullptr)
|
||||
: _FrontEnd{iter_source::wrapIter (std::forward<IT>(ii))}
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
|
@ -142,8 +143,8 @@ namespace diff{
|
|||
* @warning like with any classical iterators, the container must stay alive and accessible
|
||||
*/
|
||||
template<class CON>
|
||||
DiffMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
|
||||
,__not_<can_IterForEach<CON>>>, void*> =nullptr)
|
||||
DiffMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
|
||||
,__not_<can_IterForEach<CON>>>, void*> =nullptr)
|
||||
: _FrontEnd{iter_source::eachEntry(container)}
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -381,9 +381,9 @@ namespace diff{
|
|||
}
|
||||
|
||||
friend ChildDataIter
|
||||
childData (Rec::scopeIter const& scopeIter)
|
||||
childData (Rec::scopeIter&& scopeIter)
|
||||
{
|
||||
return ChildDataIter{ scopeIter
|
||||
return ChildDataIter{ std::forward<Rec::scopeIter>(scopeIter)
|
||||
, [](GenNode const& child) ->DataCap const&
|
||||
{
|
||||
return child.data;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ namespace util {
|
|||
|
||||
using lib::meta::can_IterForEach;
|
||||
using std::string;
|
||||
using std::forward;
|
||||
using std::move;
|
||||
|
||||
|
||||
|
|
@ -127,12 +128,12 @@ namespace util {
|
|||
* @see FormatHelper_test::checkStringify()
|
||||
*/
|
||||
template<class IT>
|
||||
inline lib::TransformIter<IT, string>
|
||||
stringify (IT const& src)
|
||||
inline auto
|
||||
stringify (IT&& src)
|
||||
{
|
||||
using Val = typename IT::value_type;
|
||||
using Val = typename std::remove_reference<IT>::type::value_type;
|
||||
|
||||
return lib::transformIterator(src, util::toString<Val>);
|
||||
return lib::transformIterator(forward<IT>(src), util::toString<Val>);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@
|
|||
#include "lib/iter-adapter.hpp"
|
||||
#include "lib/itertools.hpp"
|
||||
|
||||
#include <boost/type_traits/remove_const.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -64,6 +65,7 @@ namespace lib {
|
|||
|
||||
using std::string;
|
||||
using std::shared_ptr;
|
||||
using std::forward;
|
||||
|
||||
|
||||
|
||||
|
|
@ -255,6 +257,10 @@ namespace lib {
|
|||
WrappedLumieraIter (IT const& orig)
|
||||
: src_(orig)
|
||||
{ }
|
||||
|
||||
WrappedLumieraIter (IT&& orig)
|
||||
: src_(forward<IT>(orig))
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -268,55 +274,58 @@ namespace lib {
|
|||
template<class CON>
|
||||
struct _SeqT
|
||||
{
|
||||
typedef typename CON::iterator::value_type Val;
|
||||
typedef typename IterSource<Val>::iterator Iter;
|
||||
using Val = typename CON::iterator::value_type;
|
||||
using Iter = typename IterSource<Val>::iterator;
|
||||
};
|
||||
|
||||
template<class IT>
|
||||
struct _RangeT
|
||||
{
|
||||
typedef typename IT::value_type Val;
|
||||
typedef typename IterSource<Val>::iterator Iter;
|
||||
using Val = typename IT::value_type;
|
||||
using Iter = typename IterSource<Val>::iterator;
|
||||
};
|
||||
|
||||
template<class MAP>
|
||||
struct _MapT
|
||||
{
|
||||
typedef typename MAP::key_type Key;
|
||||
typedef typename MAP::value_type::second_type Val;
|
||||
typedef typename IterSource<Key>::iterator KeyIter;
|
||||
typedef typename IterSource<Val>::iterator ValIter;
|
||||
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
|
||||
{
|
||||
typedef typename IT::value_type Val;
|
||||
typedef typename IterSource<Val>::iterator Iter;
|
||||
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
|
||||
{
|
||||
typedef typename lib::meta::_Fun<FUN>::Ret ResVal;
|
||||
typedef TransformIter<IT,ResVal> TransIter;
|
||||
typedef typename IterSource<ResVal>::iterator Iter;
|
||||
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
|
||||
{
|
||||
typedef typename IT::value_type PairType;
|
||||
typedef typename PairType::second_type ValType;
|
||||
typedef typename PairType::first_type ConstKeyType;
|
||||
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
|
||||
typedef typename boost::remove_const<ConstKeyType>::type KeyType;
|
||||
using KeyType = typename std::remove_const<ConstKeyType>::type;
|
||||
|
||||
typedef TransformIter<IT,KeyType> KeyIter;
|
||||
typedef TransformIter<IT,ValType> ValIter;
|
||||
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;}
|
||||
|
|
@ -325,16 +334,16 @@ namespace lib {
|
|||
|
||||
template<class IT>
|
||||
typename _PairIterT<IT>::KeyIter
|
||||
takePairFirst (IT const& source)
|
||||
takePairFirst (IT&& source)
|
||||
{
|
||||
return transformIterator(source, _PairIterT<IT>::takeFirst );
|
||||
return transformIterator(forward<IT>(source), _PairIterT<IT>::takeFirst );
|
||||
}
|
||||
|
||||
template<class IT>
|
||||
typename _PairIterT<IT>::ValIter
|
||||
takePairSecond (IT const& source)
|
||||
takePairSecond (IT&& source)
|
||||
{
|
||||
return transformIterator(source, _PairIterT<IT>::takeSecond );
|
||||
return transformIterator(forward<IT>(source), _PairIterT<IT>::takeSecond );
|
||||
}
|
||||
|
||||
} //(END) type helpers...
|
||||
|
|
@ -346,11 +355,12 @@ namespace lib {
|
|||
*/
|
||||
template<class IT>
|
||||
typename _IterT<IT>::Iter
|
||||
wrapIter (IT const& source)
|
||||
wrapIter (IT&& source)
|
||||
{
|
||||
typedef typename _IterT<IT>::Val ValType;
|
||||
using Src = typename _IterT<IT>::Src;
|
||||
using Val = typename _IterT<IT>::Val;
|
||||
|
||||
return IterSource<ValType>::build (new WrappedLumieraIter<IT> (source));
|
||||
return IterSource<Val>::build (new WrappedLumieraIter<Src> (forward<IT>(source)));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -365,14 +375,14 @@ namespace lib {
|
|||
*/
|
||||
template<class IT, class FUN>
|
||||
typename _TransformIterT<IT,FUN>::Iter
|
||||
transform (IT const& source, FUN processingFunc)
|
||||
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 (source, processingFunc)));
|
||||
transformIterator (forward<IT>(source), processingFunc)));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -383,7 +393,7 @@ namespace lib {
|
|||
typename _MapT<MAP>::KeyIter
|
||||
eachMapKey (MAP& map)
|
||||
{
|
||||
typedef RangeIter<typename MAP::iterator> Range;
|
||||
using Range = RangeIter<typename MAP::iterator>;
|
||||
|
||||
Range contents (map.begin(), map.end());
|
||||
return wrapIter (takePairFirst (contents));
|
||||
|
|
@ -397,7 +407,7 @@ namespace lib {
|
|||
typename _MapT<MAP>::ValIter
|
||||
eachMapVal (MAP& map)
|
||||
{
|
||||
typedef RangeIter<typename MAP::iterator> Range;
|
||||
using Range = RangeIter<typename MAP::iterator>;
|
||||
|
||||
Range contents (map.begin(), map.end());
|
||||
return wrapIter (takePairSecond(contents));
|
||||
|
|
@ -413,7 +423,7 @@ namespace lib {
|
|||
typename _MapT<MAP>::KeyIter
|
||||
eachDistinctKey (MAP& map)
|
||||
{
|
||||
typedef RangeIter<typename MAP::iterator> Range;
|
||||
using Range = RangeIter<typename MAP::iterator>;
|
||||
|
||||
Range contents (map.begin(), map.end());
|
||||
return wrapIter (filterRepetitions (takePairFirst(contents)));
|
||||
|
|
@ -428,8 +438,8 @@ namespace lib {
|
|||
typename _MapT<MAP>::ValIter
|
||||
eachValForKey (MAP& map, typename _MapT<MAP>::Key key)
|
||||
{
|
||||
typedef typename MAP::iterator Pos;
|
||||
typedef RangeIter<Pos> Range;
|
||||
using Pos = typename MAP::iterator;
|
||||
using Range = RangeIter<Pos>;
|
||||
|
||||
std::pair<Pos,Pos> valuesForKey = map.equal_range(key);
|
||||
Range contents (valuesForKey.first, valuesForKey.second);
|
||||
|
|
@ -447,8 +457,8 @@ namespace lib {
|
|||
typename _SeqT<CON>::Iter
|
||||
eachEntry (CON& container)
|
||||
{
|
||||
typedef typename _SeqT<CON>::Val ValType;
|
||||
typedef RangeIter<typename CON::iterator> Range;
|
||||
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));
|
||||
|
|
@ -462,8 +472,8 @@ namespace lib {
|
|||
typename _RangeT<IT>::Iter
|
||||
eachEntry (IT const& begin, IT const& end)
|
||||
{
|
||||
typedef typename _RangeT<IT>::Val ValType;
|
||||
typedef RangeIter<IT> Range;
|
||||
using ValType = typename _RangeT<IT>::Val;
|
||||
using Range = RangeIter<IT>;
|
||||
|
||||
Range contents (begin, end);
|
||||
return IterSource<ValType>::build (new WrappedLumieraIter<Range>(contents));
|
||||
|
|
|
|||
|
|
@ -74,11 +74,13 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
using std::forward;
|
||||
using std::function;
|
||||
using util::unConst;
|
||||
|
||||
|
|
@ -102,8 +104,11 @@ namespace lib {
|
|||
{
|
||||
IT source_;
|
||||
|
||||
IdentityCore (IT&& orig)
|
||||
: source_{forward<IT>(orig)}
|
||||
{ }
|
||||
IdentityCore (IT const& orig)
|
||||
: source_(orig)
|
||||
: source_{orig}
|
||||
{ }
|
||||
|
||||
IT&
|
||||
|
|
@ -184,8 +189,8 @@ namespace lib {
|
|||
typedef typename CORE::value_type value_type;
|
||||
|
||||
|
||||
IterTool (CORE const& setup)
|
||||
: core_(setup)
|
||||
IterTool (CORE&& setup)
|
||||
: core_{std::move(setup)}
|
||||
{
|
||||
hasData();
|
||||
}
|
||||
|
|
@ -268,8 +273,8 @@ namespace lib {
|
|||
struct FilterCore
|
||||
: IdentityCore<IT>
|
||||
{
|
||||
typedef IdentityCore<IT> Raw;
|
||||
typedef typename IT::reference Val;
|
||||
using Raw = IdentityCore<IT>;
|
||||
using Val = typename IT::reference;
|
||||
|
||||
|
||||
function<bool(Val)> predicate_;
|
||||
|
|
@ -302,12 +307,20 @@ namespace lib {
|
|||
|
||||
|
||||
template<typename PRED>
|
||||
FilterCore (IT const& source, PRED prediDef)
|
||||
: Raw(source)
|
||||
FilterCore (IT&& source, PRED prediDef)
|
||||
: Raw{forward<IT>(source)}
|
||||
, predicate_(prediDef) // induces a signature check
|
||||
, cached_(false) // not yet cached
|
||||
, isOK_() // some value
|
||||
{ }
|
||||
|
||||
template<typename PRED>
|
||||
FilterCore (IT const& source, PRED prediDef)
|
||||
: Raw{source}
|
||||
, predicate_(prediDef)
|
||||
, cached_(false)
|
||||
, isOK_()
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -326,12 +339,17 @@ namespace lib {
|
|||
|
||||
|
||||
FilterIter ()
|
||||
: _Impl(FilterCore<IT>(IT(), acceptAll))
|
||||
: _Impl{FilterCore<IT>(IT(), acceptAll)}
|
||||
{ }
|
||||
|
||||
template<typename PRED>
|
||||
FilterIter (IT const& src, PRED filterPredicate)
|
||||
: _Impl(_Filter(src,filterPredicate))
|
||||
: _Impl{_Filter(src, filterPredicate)}
|
||||
{ }
|
||||
|
||||
template<typename PRED>
|
||||
FilterIter (IT&& src, PRED filterPredicate)
|
||||
: _Impl{_Filter(forward<IT>(src), filterPredicate)}
|
||||
{ }
|
||||
|
||||
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (FilterIter)
|
||||
|
|
@ -344,10 +362,18 @@ namespace lib {
|
|||
* @return Iterator filtering contents of the source
|
||||
*/
|
||||
template<class IT, typename PRED>
|
||||
inline FilterIter<IT>
|
||||
inline auto
|
||||
filterIterator (IT const& src, PRED filterPredicate)
|
||||
{
|
||||
return FilterIter<IT>(src,filterPredicate);
|
||||
return FilterIter<IT>{src, filterPredicate};
|
||||
}
|
||||
|
||||
template<class IT, typename PRED>
|
||||
inline auto
|
||||
filterIterator (IT&& src, PRED filterPredicate)
|
||||
{
|
||||
using SrcIT = typename std::remove_reference<IT>::type;
|
||||
return FilterIter<SrcIT>{forward<SrcIT>(src), filterPredicate};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -378,8 +404,8 @@ namespace lib {
|
|||
class ExtensibleFilterIter
|
||||
: public FilterIter<IT>
|
||||
{
|
||||
typedef FilterCore<IT> _Filter;
|
||||
typedef typename _Filter::Val Val;
|
||||
using _Filter = FilterCore<IT>;
|
||||
using Val = typename _Filter::Val;
|
||||
|
||||
void
|
||||
reEvaluate()
|
||||
|
|
@ -391,13 +417,17 @@ namespace lib {
|
|||
public:
|
||||
ExtensibleFilterIter() { }
|
||||
|
||||
template<typename PRED>
|
||||
ExtensibleFilterIter (IT&& src, PRED initialFilterPredicate)
|
||||
: FilterIter<IT>{forward<IT>(src), initialFilterPredicate}
|
||||
{ }
|
||||
template<typename PRED>
|
||||
ExtensibleFilterIter (IT const& src, PRED initialFilterPredicate)
|
||||
: FilterIter<IT>(src, initialFilterPredicate)
|
||||
: FilterIter<IT>{src, initialFilterPredicate}
|
||||
{ }
|
||||
|
||||
ExtensibleFilterIter (IT const& src)
|
||||
: ExtensibleFilterIter(src, FilterIter<IT>::acceptAll)
|
||||
ExtensibleFilterIter (IT&& src)
|
||||
: ExtensibleFilterIter{forward<IT>(src), FilterIter<IT>::acceptAll}
|
||||
{ }
|
||||
|
||||
// standard copy operations acceptable
|
||||
|
|
@ -570,6 +600,14 @@ namespace lib {
|
|||
, treated_()
|
||||
{ }
|
||||
|
||||
template<typename FUN>
|
||||
TransformingCore (IT&& orig, FUN processor)
|
||||
: trafo_(processor) // induces a signature check
|
||||
, source_(forward<IT> (orig))
|
||||
{
|
||||
processItem();
|
||||
}
|
||||
|
||||
template<typename FUN>
|
||||
TransformingCore (IT const& orig, FUN processor)
|
||||
: trafo_(processor) // induces a signature check
|
||||
|
|
@ -612,8 +650,8 @@ namespace lib {
|
|||
class TransformIter
|
||||
: public IterTool<TransformingCore<IT,VAL>>
|
||||
{
|
||||
typedef TransformingCore<IT,VAL> _Trafo;
|
||||
typedef IterTool<_Trafo> _IteratorImpl;
|
||||
using _Trafo = TransformingCore<IT,VAL>;
|
||||
using _IteratorImpl = IterTool<_Trafo> ;
|
||||
|
||||
public:
|
||||
TransformIter ()
|
||||
|
|
@ -621,8 +659,12 @@ namespace lib {
|
|||
{ }
|
||||
|
||||
template<typename FUN>
|
||||
TransformIter (IT&& src, FUN trafoFunc)
|
||||
: _IteratorImpl{_Trafo(forward<IT>(src), trafoFunc)}
|
||||
{ }
|
||||
template<typename FUN>
|
||||
TransformIter (IT const& src, FUN trafoFunc)
|
||||
: _IteratorImpl(_Trafo(src,trafoFunc))
|
||||
: _IteratorImpl{_Trafo(src, trafoFunc)}
|
||||
{ }
|
||||
|
||||
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (TransformIter)
|
||||
|
|
@ -642,7 +684,16 @@ namespace lib {
|
|||
transformIterator (IT const& src, FUN processingFunc)
|
||||
{
|
||||
using OutVal = typename lib::meta::_Fun<FUN>::Ret;
|
||||
return TransformIter<IT,OutVal>(src,processingFunc);
|
||||
return TransformIter<IT,OutVal>{src,processingFunc};
|
||||
}
|
||||
|
||||
template<class IT, typename FUN>
|
||||
inline auto
|
||||
transformIterator (IT&& src, FUN processingFunc)
|
||||
{
|
||||
using SrcIT = typename std::remove_reference<IT>::type;
|
||||
using OutVal = typename lib::meta::_Fun<FUN>::Ret;
|
||||
return TransformIter<SrcIT,OutVal>{forward<SrcIT>(src), processingFunc};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -687,11 +738,20 @@ namespace lib {
|
|||
/** filters away repeated values
|
||||
* emitted by source iterator */
|
||||
template<class IT>
|
||||
inline FilterIter<IT>
|
||||
inline auto
|
||||
filterRepetitions (IT const& source)
|
||||
{
|
||||
typedef typename IT::value_type Val;
|
||||
return filterIterator(source, SkipRepetition<Val>() );
|
||||
using Val = typename IT::value_type;
|
||||
return filterIterator (source, SkipRepetition<Val>());
|
||||
}
|
||||
|
||||
template<class IT>
|
||||
inline auto
|
||||
filterRepetitions (IT&& source)
|
||||
{
|
||||
using SrcIT = typename std::remove_reference<IT>::type;
|
||||
using Val = typename SrcIT::value_type;
|
||||
return filterIterator (forward<SrcIT>(source), SkipRepetition<Val>() );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ namespace session {
|
|||
|
||||
/* == access for self-test == */
|
||||
|
||||
typedef lib::IterSource<PID>::iterator IDIter;
|
||||
using IDIter = lib::IterSource<PID>::iterator;
|
||||
|
||||
PlacementMO* _root_4check () { return root_.get(); }
|
||||
PlacementMO* _element_4check (ID id){ return base_entry(id).element.get();}
|
||||
|
|
|
|||
Loading…
Reference in a new issue