From 46e573efb730691dee8ee9e721fb267607d1d2c1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 5 Jun 2015 18:52:56 +0200 Subject: [PATCH] includes: split out rarely used PtrDerefIter this allows us to avoid a boost include otherwise dragged in through the widely used iter-adapter.hpp --- src/lib/iter-adapter-ptr-deref.hpp | 586 +--------------------------- src/lib/iter-adapter-stl.hpp | 2 +- src/lib/iter-adapter.hpp | 281 +------------ src/lib/scoped-ptrvect.hpp | 2 +- tests/library/iter-adapter-test.cpp | 15 +- 5 files changed, 35 insertions(+), 851 deletions(-) diff --git a/src/lib/iter-adapter-ptr-deref.hpp b/src/lib/iter-adapter-ptr-deref.hpp index ef3332ddd..7d76ec811 100644 --- a/src/lib/iter-adapter-ptr-deref.hpp +++ b/src/lib/iter-adapter-ptr-deref.hpp @@ -1,8 +1,8 @@ /* - ITER-ADAPTER-PTR-DEREF.hpp - helpers for building simple forward iterators + ITER-ADAPTER-PTR-DEREF.hpp - wrapping iterator to dereference pointers automatically Copyright (C) Lumiera.org - 2009, Hermann Vosseler + 2015, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -20,478 +20,39 @@ */ -/** @file iter-adapter.hpp - ** Helper template(s) for creating lumiera forward iterators. - ** These are the foundation to build up iterator like types from scratch. - ** Usually, these templates will be created and provided by a custom - ** container type and accessed by the client through a typedef name - ** "iterator" (similar to the usage within the STL). For more advanced - ** usage, the providing container might want to subclass these iterators, - ** e.g. to provide an additional, specialised API. + +/** @file iter-adapter-ptr-deref.hpp + ** Extension adapter for Lumiera Forward Iterators to dereference + ** any pointer values automatically. Sometimes, the iteration of some + ** container naturally just yields pointers to contained values. But, + ** from a viewpoint of interface design, we'd prefer the iterator to + ** expose direct references (NULL values can be excluded). This helper + ** template does precisely this: it wraps up any other entity conforming + ** to the »Lumiera Forward Iterator« concept and, on access, automatically + ** dereferences the exposed pointer. ** - ** Depending on the concrete situation, several flavours are provided: - ** - the IterAdapter retains an active callback connection to the - ** controlling container, thus allowing arbitrary complex behaviour. - ** - the IterStateWrapper uses a variation of that approach, where the - ** representation of the current state is embedded as an state value - ** element right into the iterator instance. - ** - the RangeIter allows just to expose a range of elements defined - ** by a STL-like pair of "start" and "end" iterators - ** - often, objects are managed internally by pointers, while allowing - ** the clients to use direct references; to support this usage scenario, - ** PtrDerefIter wraps an existing iterator, while dereferencing any value - ** automatically on access. - ** - for some (very specific) usage situations we intend to explore the - ** contents of a stable and unmodifiable data structure through pointers. - ** The AddressExposingIter wraps another Lumiera Forward Iterator and - ** exposes addresses -- assuming the used source iterator is exposing - ** references to pre-existing storage locations (not temporaries). - ** - ** There are many further ways of yielding a Lumiera forward iterator. - ** For example, lib::IterSource builds a "iterable" source of data elements, - ** while hiding the actual container or generator implementation behind a - ** vtable call. Besides, there are adapters for the most common usages - ** with STL containers, and such iterators can also be combined and - ** extended with the help of itertools.hpp - ** - ** Basically every class in compliance with our specific iterator concept - ** can be used as a building block within this framework. - ** - ** - ** \par Lumiera forward iterator concept - ** - ** Similar to the STL, instead of using a common "Iterator" base class, - ** we rather define a common set of functions and behaviour which can - ** be expected from any such iterator. These rules are similar to STL's - ** "forward iterator", with the addition of an bool check to detect - ** iteration end. The latter is inspired by the \c hasNext() function - ** found in many current languages supporting iterators. In a similar - ** vein (inspired from functional programming), we deliberately don't - ** support the various extended iterator concepts from STL and boost - ** (random access iterators, output iterators, arithmetics, difference - ** between iterators and the like). According to this concept, - ** an iterator is a promise for pulling values, - ** and nothing beyond that. - ** - ** - Any Lumiera forward iterator can be in a "exhausted" (invalid) state, - ** which can be checked by the bool conversion. Especially, any instance - ** created by the default ctor is always fixed to that state. This - ** state is final and can't be reset, meaning that any iterator is - ** a disposable one-way-off object. - ** - iterators are copyable and equality comparable - ** - when an iterator is \em not in the exhausted state, it may be - ** \em dereferenced to yield the "current" value. - ** - moreover, iterators may be incremented until exhaustion. + ** In addition, the reversed operation is also supported through another + ** helper template: to take the address of any value exposed by the given + ** underlying iterator ** ** @see iter-adapter-test.cpp + ** @see iter-adapter.hpp basic iterator adapters ** @see itertools.hpp - ** @see IterSource (completely opaque iterator) - ** @see iter-type-binding.hpp ** */ -#ifndef LIB_ITER-ADAPTER-PTR-DEREF_H -#define LIB_ITER-ADAPTER-PTR-DEREF_H +#ifndef LIB_ITER_ADAPTER_PTR_DEREF_H +#define LIB_ITER_ADAPTER_PTR_DEREF_H -#include "lib/error.hpp" -#include "lib/bool-checkable.hpp" -#include "lib/iter-type-binding.hpp" +#include "lib/iter-adapter.hpp" #include namespace lib { - - namespace { // internal helpers - void - _throwIterExhausted() - { - throw lumiera::error::Invalid ("Can't iterate further", - lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); - } - } - - - - /** - * Adapter for building an implementation of the lumiera forward iterator concept. - * The "current position" is represented as an opaque element (usually a nested iterator), - * with callbacks into the controlling container instance to manage this position. - * This allows to influence and customise the iteration process to a large extent. - * Basically such an IterAdapter behaves like the similar concept from STL, but - * - it is not just a disguised pointer (meaning, it's more expensive) - * - it checks validity on every operation and may throw - * - it has a distinct back-link to the source container - * - the source container needs to provide hasNext() and iterNext() free functions. - * - we may need friendship to implement those extension points on the container - * - the end-of-iteration can be detected by bool check - * @note it is possible to "hide" a smart-ptr within the CON template parameter. - * - * \par Stipulations - * - POS refers to the current position within the data source of this iterator. - * -# it should be default constructible - * -# it should be copy constructible - * -# when IterAdapter is supposed to be assignable, then POS should be - * -# it should provide embedded typedefs for pointer, reference and value_type, - * or alternatively resolve these types through specialisation of iter::TypeBinding. - * -# it should be convertible to the pointer type it declares - * -# dereferencing should yield a type that is convertible to the reference type - * - CON points to the data source of this iterator (typically a data container type) - * We store a pointer-like backlink to invoke a special iteration control API: - * -# \c checkPoint yields true iff the source has yet more result values to yield - * -# \c iterNext advances the POS to the next element - * - * @see scoped-ptrvect.hpp usage example - * @see iter-type-binding.hpp - * @see iter-adaptor-test.cpp - */ - template - class IterAdapter - : public lib::BoolCheckable > - { - CON source_; - mutable POS pos_; - - public: - typedef typename iter::TypeBinding::pointer pointer; - typedef typename iter::TypeBinding::reference reference; - typedef typename iter::TypeBinding::value_type value_type; - - IterAdapter (CON src, POS const& startpos) - : source_(src) - , pos_(startpos) - { - check(); - } - - IterAdapter () - : source_() - , pos_() - { } - - - /* === lumiera forward iterator concept === */ - - reference - operator*() const - { - _maybe_throw(); - return *pos_; - } - - pointer - operator->() const - { - _maybe_throw(); - return pos_; - } - - IterAdapter& - operator++() - { - _maybe_throw(); - iterate(); - return *this; - } - - bool - isValid () const - { - return check(); - } - - bool - empty () const - { - return !isValid(); - } - - - protected: /* === iteration control interface === */ - - /** ask the controlling container if this position is valid. - * @note this function is called before any operation, - * thus the container may adjust the position value, - * for example setting it to a "stop iteration" mark. - */ - bool - check() const - { - return source_ && checkPoint (source_,pos_); // extension point: free function checkPoint(...) - } - - /** ask the controlling container to yield the next position. - * The call is dispatched only if the current position is valid; - * any new position reached will typically be validated prior - * to any further access, through invocation of #check. - */ - void - iterate() - { - if (check()) - iterNext (source_,pos_); // extension point: free function iterNext(...) - } - - - private: - void - _maybe_throw() const - { - if (!isValid()) - _throwIterExhausted(); - } - - /// comparison is allowed to access impl iterator - template - friend bool operator== (IterAdapter const&, IterAdapter const&); - }; - - - /// Supporting equality comparisons... - template - bool operator== (IterAdapter const& il, IterAdapter const& ir) { return il.pos_ == ir.pos_; } - - template - bool operator!= (IterAdapter const& il, IterAdapter const& ir) { return !(il == ir); } - - - - - /** - * Another Lumiera Forward Iterator building block, based on incorporating a state type - * right into the iterator. Contrast this to IterAdapter, which refers to a managing - * container behind the scenes. Here, all of the state is assumed to live in the - * custom type embedded into this iterator, accessed and manipulated through - * a set of free functions, picked up through ADL. - * - * \par Assumptions when building iterators based on IterStateWrapper - * There is a custom state representation type ST. - * - default constructible - * - this default state represents the \em bottom (invalid) state. - * - copyable, because iterators are passed by value - * - this type needs to provide an iteration control API through free functions - * -# \c checkPoint establishes if the given state element represents a valid state - * -# \c iterNext evolves this state by one step (sideeffect) - * -# \c yield realises the given state, yielding an element of result type T - * - * @see IterExplorer an iterator monad built on top of IterStateWrapper - * @see iter-explorer-test.hpp - * @see iter-adaptor-test.cpp - */ - template - class IterStateWrapper - : public lib::BoolCheckable > - { - ST core_; - - public: - typedef T* pointer; - typedef T& reference; - typedef T value_type; - - IterStateWrapper (ST const& initialState) - : core_(initialState) - { - checkPoint (core_); // extension point: checkPoint - } - - IterStateWrapper () - : core_() - { } - - - /* === lumiera forward iterator concept === */ - - reference - operator*() const - { - __throw_if_empty(); - return yield (core_); // extension point: yield - } - - pointer - operator->() const - { - __throw_if_empty(); - return & yield(core_); // extension point: yield - } - - IterStateWrapper& - operator++() - { - __throw_if_empty(); - iterNext (core_); // extension point: iterNext - return *this; - } - - bool - isValid () const - { - return checkPoint(core_); // extension point: checkPoint - } - - bool - empty () const - { - return !isValid(); - } - - protected: - - /** allow derived classes to - * access state representation */ - ST & - stateCore() - { - return core_; - } - - void - __throw_if_empty() const - { - if (!isValid()) - _throwIterExhausted(); - } - - - /// comparison is allowed to access state implementation core - template - friend bool operator== (IterStateWrapper const&, IterStateWrapper const&); - }; - - - - /// Supporting equality comparisons of equivalent iterators (same state type)... - template - bool operator== (IterStateWrapper const& il, IterStateWrapper const& ir) - { - return (il.empty() && ir.empty()) - || (il.isValid() && ir.isValid() && il.core_ == ir.core_); - } - - template - bool operator!= (IterStateWrapper const& il, IterStateWrapper const& ir) - { - return ! (il == ir); - } - - - - - - - - - /** - * Accessing a STL element range through a Lumiera forward iterator, - * An instance of this iterator adapter is completely self-contained - * and allows to iterate once over the range of elements, until - * \c pos==end . Thus, a custom container may expose a range of - * elements of an embedded STL container, without controlling - * the details of the iteration (as is possible using the - * more generic IterAdapter). - */ - template - class RangeIter - : public lib::BoolCheckable > - { - IT p_; - IT e_; - - public: - typedef typename iter::TypeBinding::pointer pointer; - typedef typename iter::TypeBinding::reference reference; - typedef typename iter::TypeBinding::value_type value_type; - - RangeIter (IT const& start, IT const& end) - : p_(start) - , e_(end) - { } - - RangeIter () - : p_() - , e_() - { } - - - /** allow copy, - * when the underlying iterators - * are compatible or convertible */ - template - RangeIter (I2 const& oIter) - : p_(oIter.getPos()) - , e_(oIter.getEnd()) - { } - - - /* === lumiera forward iterator concept === */ - - reference - operator*() const - { - _maybe_throw(); - return *p_; - } - - pointer - operator->() const - { - _maybe_throw(); - return &(*p_); - } - - RangeIter& - operator++() - { - _maybe_throw(); - ++p_; - return *this; - } - - bool - isValid () const - { - return (p_!= IT()) && (p_ != e_); - } - - bool - empty () const - { - return !isValid(); - } - - - /** access wrapped STL iterator */ - const IT& getPos() const { return p_; } - const IT& getEnd() const { return e_; } - - - private: - - void - _maybe_throw() const - { - if (!isValid()) - _throwIterExhausted(); - } - }; - - - - /// Supporting equality comparisons... - template - bool operator== (RangeIter const& il, RangeIter const& ir) { return (!il && !ir) || (il.getPos() == ir.getPos()); } - - template - bool operator!= (RangeIter const& il, RangeIter const& ir) { return !(il == ir); } - - - - - namespace { /** helper to remove pointer, @@ -514,41 +75,8 @@ namespace lib { } - /** - * Helper for type rewritings: - * get the element type for an iterator like entity - */ - template - struct IterType; - template class Iter, class TY, class CON> - struct IterType > - { - typedef CON Container; - typedef TY ElemType; - - template - struct SimilarIter ///< rebind to a similarly structured Iterator with value type T2 - { - typedef Iter Type; - }; - }; - - template - struct IterType > - : IterType - { - template - struct SimilarIter ///< rebind to rewritten Iterator wrapped into RangeIter - { - typedef typename IterType::template SimilarIter::Type WrappedIter; - typedef RangeIter Type; - }; - }; - - - - /** + /** * wrapper for an existing Iterator type, * automatically dereferencing the output of the former. * For this to work, the "source" iterator is expected @@ -802,77 +330,5 @@ namespace lib { - /** wrapper to declare exposed values const */ - template - class ConstIter - : public lib::BoolCheckable > - { - IT i_; ///< nested source iterator - - - public: - typedef const typename IT::value_type value_type; - typedef const typename IT::pointer pointer; - typedef const typename IT::reference reference; - - ConstIter (IT srcIter) - : i_(srcIter) - { } - - - - - /* === lumiera forward iterator concept === */ - - reference - operator*() const - { - return *i_; - } - - pointer - operator->() const - { - return i_.operator->(); - } - - ConstIter& - operator++() - { - ++i_; - return *this; - } - - bool - isValid () const - { - return bool(i_); - } - - bool - empty () const - { - return !isValid(); - } - - - /** access the wrapped implementation iterator */ - IT const& - getBase() const - { - return i_; - } - }; - - - /// Supporting equality comparisons... - template - bool operator== (ConstIter const& il, ConstIter const& ir) { return il.getBase() == ir.getBase(); } - - template - bool operator!= (ConstIter const& il, ConstIter const& ir) { return !(il == ir); } - - - }// namespace lib -#endif /*LIB_ITER-ADAPTER-PTR-DEREF_H*/ +#endif /*LIB_ITER_ADAPTER_PTR_DEREF_H*/ diff --git a/src/lib/iter-adapter-stl.hpp b/src/lib/iter-adapter-stl.hpp index 703216e53..7941974f3 100644 --- a/src/lib/iter-adapter-stl.hpp +++ b/src/lib/iter-adapter-stl.hpp @@ -42,7 +42,7 @@ #include "lib/iter-adapter.hpp" - +#include "lib/iter-adapter-ptr-deref.hpp" diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 2c05650d0..69d5407fd 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -37,6 +37,9 @@ ** element right into the iterator instance. ** - the RangeIter allows just to expose a range of elements defined ** by a STL-like pair of "start" and "end" iterators + ** + ** Some more specific use cases are provided in the extension header + ** iter-adapter-ptr-deref.hpp ** - often, objects are managed internally by pointers, while allowing ** the clients to use direct references; to support this usage scenario, ** PtrDerefIter wraps an existing iterator, while dereferencing any value @@ -99,8 +102,6 @@ #include "lib/bool-checkable.hpp" #include "lib/iter-type-binding.hpp" -#include - namespace lib { @@ -507,28 +508,6 @@ namespace lib { - namespace { - - /** helper to remove pointer, - * while retaining const */ - template - struct RemovePtr { typedef T Type; }; - - template - struct RemovePtr { typedef T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - template - struct RemovePtr { typedef const T Type; }; - - } - - /** * Helper for type rewritings: * get the element type for an iterator like entity @@ -563,260 +542,6 @@ namespace lib { - /** - * wrapper for an existing Iterator type, - * automatically dereferencing the output of the former. - * For this to work, the "source" iterator is expected - * to be declared on \em pointers rather than on values. - * @note bool checkable if and only if source is... - */ - template - class PtrDerefIter - : public lib::BoolCheckable > - { - IT i_; ///< nested source iterator - - - public: - typedef typename IT::value_type pointer; - typedef typename RemovePtr::Type value_type; - typedef value_type& reference; - - // for use with STL algorithms - typedef void difference_type; - typedef std::forward_iterator_tag iterator_category; - - - // the purpose of the following typedefs is to ease building a correct "const iterator" - - typedef typename boost::remove_const::type ValueTypeBase; // value_type without const - - typedef typename IterType::template SimilarIter< ValueTypeBase* * >::Type WrappedIterType; - typedef typename IterType::template SimilarIter::Type WrappedConstIterType; - - typedef PtrDerefIter IterType; - typedef PtrDerefIter ConstIterType; - - - - /** PtrDerefIter is always created - * by wrapping an existing iterator. - */ - explicit - PtrDerefIter (IT srcIter) - : i_(srcIter) - { } - - - /** allow copy initialisation also when - * the wrapped iterator is based on some variation of a pointer. - * Especially, this includes initialisation of the "const variant" - * from the "normal variant" of PtrDerefIter. Actually, we need to convert - * in this case by brute force, because indeed (const TY *)* is not assignable - * from (TY *)* -- just we know that our intention is to dereference both levels - * of pointers, and then the resulting conversion is correct. - * @note in case IT == WrappedIterType, this is just a redefinition of the - * default copy ctor. In all other cases, this is an additional - * ctor besides the default copy ctor */ - PtrDerefIter (PtrDerefIter const& oIter) - : i_(reinterpret_cast (oIter.getBase())) - { } - - PtrDerefIter& - operator= (PtrDerefIter const& ref) - { - i_ = reinterpret_cast (ref.getBase()); - return *this; - } - - - /** explicit builder to allow creating a const variant from the basic srcIter type. - * Again, the reason necessitating this "backdoor" is that we want to swallow one level - * of indirection. Generally speaking `const T **` is not the same as `T * const *`, - * but in our specific case the API ensures that a `PtrDerefIter` - * only exposes const elements. - */ - static PtrDerefIter - build_by_cast (WrappedIterType const& srcIter) - { - return PtrDerefIter (reinterpret_cast (srcIter)); - } - - static PtrDerefIter - nil() - { - return PtrDerefIter (IT()); - } - - - - - - - /* === lumiera forward iterator concept === */ - - reference - operator*() const - { - return *(*i_); - } - - pointer - operator->() const - { - return *i_; - } - - PtrDerefIter& - operator++() - { - ++i_; - return *this; - } - - bool - isValid () const - { - return bool(i_); - } - - bool - empty () const - { - return !isValid(); - } - - - /** access the wrapped implementation iterator */ - IT const& - getBase() const - { - return i_; - } - }; - - - /// Supporting equality comparisons... - template - bool operator== (PtrDerefIter const& il, PtrDerefIter const& ir) { return il.getBase() == ir.getBase(); } - - template - bool operator!= (PtrDerefIter const& il, PtrDerefIter const& ir) { return !(il == ir); } - - - - - - /** - * wrapper for an existing Iterator type to expose the address of each value yielded. - * Typically this can be used to build visitation sequences based on values living - * within a stable data structure (e.g. unmodifiable STL vector) - * @warning use of this wrapper might lead to taking the address of temporaries. - * The continued existence of the exposed storage locations must be guaranteed. - * @note bool checkable if and only if source is... - */ - template - class AddressExposingIter - : public lib::BoolCheckable > - { - typedef typename IT::pointer _Ptr; - - IT i_; ///< nested source iterator - - mutable _Ptr currPtr_; - - - void - takeAddress() - { - if (i_.isValid()) - currPtr_ = & (*i_); - else - currPtr_ = 0; - } - - - public: - typedef typename IT::pointer const* pointer; - typedef typename IT::pointer const& reference; - typedef typename IT::pointer const value_type; - - - /** AddressExposingIter is always created - * by wrapping an existing iterator. - */ - explicit - AddressExposingIter (IT srcIter) - : i_(srcIter) - { - takeAddress(); - } - - - - - - /* === lumiera forward iterator concept === */ - - /** @return address of the source iteraor's current result - * @warning exposing a reference to an internal pointer for sake of compatibility. - * Clients must not store that reference, but rather use it to initialise - * a copy. The internal pointer exposed here will be changed on increment. - */ - reference - operator*() const - { - return currPtr_; - } - - _Ptr - operator->() const - { - return currPtr_; - } - - AddressExposingIter& - operator++() - { - ++i_; - takeAddress(); - return *this; - } - - bool - isValid () const - { - return bool(i_); - } - - bool - empty () const - { - return !isValid(); - } - - - /** access the wrapped implementation iterator */ - IT const& - getBase() const - { - return i_; - } - }; - - - /// Supporting equality comparisons... - template - bool operator== (AddressExposingIter const& il, AddressExposingIter const& ir) { return il.getBase() == ir.getBase(); } - - template - bool operator!= (AddressExposingIter const& il, AddressExposingIter const& ir) { return !(il == ir); } - - - - - - /** wrapper to declare exposed values const */ template class ConstIter diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp index 241ada393..c4373620a 100644 --- a/src/lib/scoped-ptrvect.hpp +++ b/src/lib/scoped-ptrvect.hpp @@ -48,7 +48,7 @@ #include "include/logging.h" -#include "lib/iter-adapter.hpp" +#include "lib/iter-adapter-ptr-deref.hpp" #include "lib/error.hpp" #include "lib/util.hpp" diff --git a/tests/library/iter-adapter-test.cpp b/tests/library/iter-adapter-test.cpp index fc5324b7d..2f40f3f70 100644 --- a/tests/library/iter-adapter-test.cpp +++ b/tests/library/iter-adapter-test.cpp @@ -27,6 +27,7 @@ #include "lib/util-foreach.hpp" #include "lib/iter-adapter.hpp" +#include "lib/iter-adapter-ptr-deref.hpp" #include #include @@ -139,10 +140,12 @@ namespace test{ } /** Implementation of Iteration-logic: detect iteration end. - * @note the problem here is that this implementation chooses - * to use two representations of "bottom" (end, invalid). - * The reason is, we want the default-constructed IterAdapter - * also be the "bottom" value. Thus, when we detect the + * @note the problem here is that this implementation chooses to use + * two representations of ⟂ ("bottom", end, invalid). The reason is, + * we want the default-constructed IterAdapter also be the ⟂ value. + * This is in accordance with the »Lumiera Forward Iterator« concept, + * which requires the default constructed iterator to mark the iteration + * end and to evaluate to \c bool(false). Thus, when we detect the * iteration end by internal logic (\c numberz_.end() ), we * immediately transform this into the official "bottom" */ @@ -151,11 +154,11 @@ namespace test{ checkPoint (const TestContainer* src, ITER& pos) { REQUIRE (src); - if ((pos != ITER(0)) && (pos != src->numberz_.end())) + if ((pos != ITER()) && (pos != src->numberz_.end())) return true; else { - pos = ITER(0); + pos = ITER(); return false; } } };