From 1397e144c133acb946996e83cfe8f9b759587cdb Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Fri, 25 Apr 2003 04:51:32 +0000 Subject: [PATCH] added a bunch for the specialized adaptors, also filled out the facade and adaptor sections [SVN r1181] --- doc/facade-and-adaptor.rst | 585 +++++++++++++++++++++++++++++++++---- doc/new-iter-concepts.rst | 4 +- 2 files changed, 524 insertions(+), 65 deletions(-) diff --git a/doc/facade-and-adaptor.rst b/doc/facade-and-adaptor.rst index 211a079..e82d8df 100755 --- a/doc/facade-and-adaptor.rst +++ b/doc/facade-and-adaptor.rst @@ -6,7 +6,7 @@ :Contact: dave@boost-consulting.com, jsiek@osl.iu.edu, witt@ive.uni-hannover.de :organization: `Boost Consulting`_, Indiana University `Open Systems Lab`_, University of Hanover `Institute for Transport Railway Operation and Construction`_ :date: $Date$ - +:Number: N1476=03-0059 :copyright: Copyright Dave Abrahams, Jeremy Siek, and Thomas Witt 2003. All rights reserved .. _`Boost Consulting`: http://www.boost-consulting.com @@ -14,7 +14,7 @@ .. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de :abstract: We propose a set of class templates that help programmers - build standard-conforming iterators and to build iterators + build standard-conforming iterators and iterators that adapt other iterators. .. contents:: Table of Contents @@ -121,12 +121,12 @@ Iterator Concepts. Interoperability ================ -The question of iterator interoperability is poorly adressed in the current standard. -There are currently two defect reports that are concerned with interoperability -issues. +The question of iterator interoperability is poorly adressed in the +current standard. There are currently two defect reports that are +concerned with interoperability issues. Issue `179`_ concerns the fact that mutable container iterator types -are only required to be convertible the corresponding constant +are only required to be convertible to the corresponding constant iterator types, but objects of these types are not required to interoperate in comparison or subtraction expressions. This situation is tedious in practice and out of line with the way built in types @@ -161,7 +161,8 @@ identified the following core behaviors for iterators: In addition to the behaviors listed above, the core interface elements include the associated types exposed through iterator traits: -``value_type``, ``reference``, ``pointer``, and ``iterator_category``. +``value_type``, ``reference``, ``pointer``, ``difference_type``, and +``iterator_category``. Iterator facade uses the Curiously Recurring Template Pattern (CRTP) [Cop95]_ so that the user can specifiy the behaviour of @@ -222,43 +223,47 @@ interoperable with X. | | |>= c``. | | +----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ -.. Should we add a comment that a zero overhead implementation of iterator_facade +.. Should we add a comment that a zero overhead implementation of iterator_facade is possible with proper inlining? +.. Would this be a good place to talk about constructors? -JGS + Iterator Core Access ==================== ``iterator_facade`` and the operator implementations need to be able -to access the core interface member functions in the derived class. -Making the core interface member funtions public would expose an -implementation detail to the user. This proposal frees the public -interface of the derived iterator type from any implementation detail. +to access the core member functions in the derived class. Making the +core member funtions public would expose an implementation detail to +the user. This proposal frees the public interface of the derived +iterator type from any implementation detail. -Preventing direct access to the core interface has two advantages. -First, there is no possibility for the user to accidently use a member -function of the iterator when a member of the value_type was intended. -This has been an issue with smart pointer implementations in the past. -The second and main advantage is that library implementers can freely -exchange a hand-rolled iterator implementation for one based on -``iterator_facade`` without fear of breaking code that was accessing -the public core interface directly. +Preventing direct access to the core member functions has two +advantages. First, there is no possibility for the user to accidently +use a member function of the iterator when a member of the value_type +was intended. This has been an issue with smart pointer +implementations in the past. The second and main advantage is that +library implementers can freely exchange a hand-rolled iterator +implementation for one based on ``iterator_facade`` without fear of +breaking code that was accessing the public core member functions +directly. -In a naive implementation, keeping the derived class' core interface -private would require it to grant friendship to ``iterator_facade`` -and each of the seven operators. In order to reduce the burden of -limiting access, this proposal provides ``iterator_core_access``, a -class that acts as a gateway to the core interface in the derived -iterator class. The author of the derived class only needs to grant -friendship to ``iterator_core_access`` to make his core interface -available to the library. +In a naive implementation, keeping the derived class' core member +functions private would require it to grant friendship to +``iterator_facade`` and each of the seven operators. In order to +reduce the burden of limiting access, this proposal provides +``iterator_core_access``, a class that acts as a gateway to the core +member functions in the derived iterator class. The author of the +derived class only needs to grant friendship to +``iterator_core_access`` to make his core member functions available +to the library. ``iterator_core_access`` would be typically implemented as an empty class containing only static member functions which invoke the -iterator core interface. There is, however, no need to standardize the -gateway protocol. +iterator core member functions. There is, however, no need to +standardize the gateway protocol. It is important to note that ``iterator_core_access`` does not open a -safety loophole, as every function in the core interface preserves the +safety loophole, as every core member function preserves the invariants of the iterator. Iterator Adaptor @@ -279,7 +284,11 @@ instance of the ``Base`` type, which it stores as a member. The user of ``iterator_adaptor`` creates a class derived from an instantiation of ``iterator_adaptor`` and then selectively overrides some of the core operations by implementing the (non-virtual) member -functions described in the table above. +functions described in the table above. The ``Base`` type +need not meet the full requirements for an iterator. It need +only support the operations that are not overriden by the +users derived class. + .. In addition, the derived class will typically need to define some constructors. @@ -321,8 +330,8 @@ which were easily implemented using ``iterator_adaptor``: Based on examples in the Boost library, users have generated many new adaptors, among them a permutation adaptor which applies some -permutation to a RandomAccessIterator, and a strided adaptor, which -adapts a RandomAccessIterator by multiplying its unit of motion by a +permutation to a Random Access Iterator, and a strided adaptor, which +adapts a Random Access Iterator by multiplying its unit of motion by a constant factor. In addition, the Boost Graph Library (BGL) uses iterator adaptors to adapt other graph libraries, such as LEDA [10] and Stanford GraphBase [8], to the BGL interface (which requires C++ @@ -332,51 +341,95 @@ Standard compliant iterators). Proposed Text =============== +Header ```` synopsis [lib.iterator.helper.synopsis] +======================================================================= +.. How's that for a name for the header? -JGS +.. Also, below I changed "not_specified" to the user-centric "use_default" -JGS :: - struct not_specified { }; + struct use_default { }; struct iterator_core_access { /* implementation detail */ }; template < class Derived - , class Value = not_specified - , class Category = not_specified - , class Reference = not_specified - , class Pointer = not_specified - , class Difference = not_specified + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default > class iterator_facade; template < class Derived , class Base - , class Value = not_specified - , class Category = not_specified - , class Reference = not_specified - , class Pointer = not_specified - , class Difference = not_specified + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default > class iterator_adaptor; + template < + class Iterator + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default + > + class indirect_iterator; - + template + class reverse_iterator; + + template + class transform_iterator; + + template + class filter_iterator; + + template < + class Incrementable, + class Category = use_default, + class Difference = use_default + > + class counting_iterator + + template + class function_output_iterator; -``iterator_facade`` -=================== + +Iterator facade [lib.iterator.facade] +===================================== + +The iterator requirements define a rich interface, containing many +redundant operators, so that using iterators is convenient. The +``iterator_facade`` class template makes it easier to create iterators +by implementing the rich interface of standard iterators in terms of a +few core functions. The user of ``iterator_facade`` derives his +iterator class from an instantiation of ``iterator_facade`` and +defines member functions implementing the core behaviors. + + + +Template class ``iterator_facade`` +---------------------------------- :: template < class Derived - , class Value = not_specified - , class Category = not_specified - , class Reference = not_specified - , class Pointer = not_specified - , class Difference = not_specified + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default > class iterator_facade { public: @@ -387,8 +440,8 @@ Standard compliant iterators). typedef ... iterator_category; reference operator*() const; - operator->() const; - operator[](difference_type n) const; + /* see details */ operator->() const; + /* see details */ operator[](difference_type n) const; Derived& operator++(); Derived operator++(int); Derived& operator--(); @@ -456,6 +509,63 @@ Standard compliant iterators). .. nothing + +``iterator_facade`` requirements +-------------------------------- + +The ``Derived`` template parameter must be the class deriving from +``iterator_facade``. + +.. We need to describe how the defaults work and what + the typedefs come out to. -JGS + + +The following table describes the requirements on the type deriving +from the ``iterator_facade``. The expressions listed in the table are +required to be valid depending on the category of the derived iterator +type. + +In the table below, ``X`` is the derived iterator type, ``a`` is an +object of type ``X``, ``b`` and ``c`` are objects of type ``const X``, +``n`` is an object of ``X::difference_type``, ``y`` is a constant +object of a single pass iterator type interoperable with X, and ``z`` +is a constant object of a random access traversal iterator type +interoperable with X. + ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| Expression | Return Type | Assertion/Note/Precondition/Postcondition | Required to implement Iterator Concept(s) | +| | | | | ++========================================+========================================+=================================================+===========================================+ +| ``c.dereference()`` | ``X::reference`` | | Readable Iterator, Writable Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``c.equal(b)`` | convertible to bool |true iff ``b`` and ``c`` are equivalent. | Single Pass Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``c.equal(y)`` | convertible to bool |true iff ``c`` and ``y`` refer to the same | Single Pass Iterator | +| | |position. Implements ``c == y`` and ``c != y``. | | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``a.advance(n)`` | unused | | Random Access Traversal Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``a.increment()`` | unused | | Incrementable Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``a.decrement()`` | unused | | Bidirectional Traversal Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``c.distance_to(b)`` | convertible to X::difference_type | equivalent to ``distance(c, b)`` | Random Access Traversal Iterator | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ +| ``c.distance_to(z)`` | convertible to X::difference_type |equivalent to ``distance(c, z)``. Implements ``c| Random Access Traversal Iterator | +| | |- z``, ``c < z``, ``c <= z``, ``c > z``, and ``c | | +| | |>= c``. | | ++----------------------------------------+----------------------------------------+-------------------------------------------------+-------------------------------------------+ + + +.. We should explain more about how the + functions in the interface of iterator_facade + are there conditionally. -JGS + + +``iterator_facade`` operations +------------------------------ + + ``reference operator*() const;`` :Returns: ``static_cast(this)->dereference();`` @@ -544,19 +654,50 @@ Standard compliant iterators). :Complexity: -``iterator_adaptor`` -==================== +Iterator adaptor [lib.iterator.adaptor] +======================================= + +A common pattern of iterator construction is the adaptation of one +iterator to form a new one. The functionality of an iterator is +composed of four orthogonal aspects: traversal, indirection, equality +comparison and distance measurement. Adapting an old iterator to +create a new one often saves work because one can reuse one aspect of +functionality while redefining the other. For example, the Standard +provides ``reverse_iterator``, which adapts any Bidirectional Iterator +by inverting its direction of traversal. + +The ``iterator_adaptor`` class template fulfills the need for +constructing adaptors. Instantiations of ``iterator_adaptor`` serve +as a base classes for new iterators, providing the default behaviour +of forwarding all operations to the underlying iterator. The deriving +class can selectively replace these features in the derived iterator +class. + +The ``iterator_adaptor`` class template adapts a ``Base`` type to +create a new iterator ("base" here means the type being adapted) . +The ``iterator_adaptor`` forwards all operations to an instance of the +``Base`` type, which it stores as a member. The user of +``iterator_adaptor`` creates a class derived from an instantiation of +``iterator_adaptor`` and then selectively overrides some of the core +operations by implementing the (non-virtual) member functions +described in [lib.iterator.facade]. The ``Base`` type need not meet +the full requirements for an iterator. It need only support the +operations that are not overriden by the users derived class. + + +Template class ``iterator_adaptor`` +----------------------------------- :: template < class Derived , class Base - , class Value = not_specified - , class Category = not_specified - , class Reference = not_specified - , class Pointer = not_specified - , class Difference = not_specified + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default > class iterator_adaptor : public iterator_facade { public: @@ -566,8 +707,326 @@ Standard compliant iterators). }; +``iterator_adaptor`` requirements +--------------------------------- +Write me. + +.. Make sure to mention that this words for both old and new + style iterators. -JGS + + +Specialized adaptors [lib.iterator.special.adaptors] +==================================================== + + +Indirect iterator +----------------- + +The indirect iterator adapts an iterator by applying an *extra* +dereference inside of ``operator*()``. For example, this iterator +adaptor makes it possible to view a container of pointers +(e.g. ``list``) as if it were a container of the pointed-to type +(e.g. ``list``) . + + +Template class ``indirect_iterator`` +++++++++++++++++++++++++++++++++++++ + +:: + + template < + class Iterator + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Pointer = use_default + , class Difference = use_default + > + class indirect_iterator + : public iterator_adaptor + { + typedef iterator_adaptor super_t; + friend class iterator_core_access; + public: + indirect_iterator() {} + + indirect_iterator(Iterator iter) + : super_t(iter) {} + + template < + class Iterator2, class Value2, class Category2 + , class Reference2, class Pointer2, class Difference2 + > + indirect_iterator( + indirect_iterator< + Iterator2, Value2, Category2, Reference2, Pointer2, Difference2 + > const& y + , typename enable_if_convertible::type* = 0 + ) + : super_t(y.base()) + {} + + private: + typename super_t::reference dereference() const + { + return **this->base(); + } + }; + + +``indirect_iterator`` requirements +++++++++++++++++++++++++++++++++++ + +The ``value_type`` of the ``Iterator`` template parameter should +itself be dereferenceable. The return type of the ``operator*`` for +the ``value_type`` must be the same type as the ``Reference`` template +parameter. The ``Value`` template parameter will be the ``value_type`` +for the ``indirect_iterator``, unless ``Value`` is const. If ``Value`` +is ``const X``, then ``value_type`` will be *non-* ``const X``. The +default for ``Value`` is + +:: + + iterator_traits< iterator_traits::value_type >::value_type + +If the default is used for ``Value``, then there must be a valid +specialization of ``iterator_traits`` for the value type of the base +iterator. + +The ``Reference`` parameter will be the ``reference`` type of the +``indirect_iterator``. The default is ``Value&``. + +The ``Pointer`` parameter will be the ``pointer`` type of the +``indirect_iterator``. The default is ``Value*``. + +The ``Category`` parameter is the ``iterator_category`` type for the +``indirect_iterator``. The default is +``iterator_traits::iterator_category``. + +The indirect iterator will model whichever standard iterator concepts +are modeled by the base iterator. For example, if the base iterator is +a model of Random Access Traversal Iterator then so is the resulting +indirect iterator. + + +Reverse iterator +---------------- + +The reverse iterator adaptor flips the direction of a base iterator's +motion. Invoking ``operator++()`` moves the base iterator backward and +invoking ``operator--()`` moves the base iterator forward. The Boost +reverse iterator adaptor is better to use than the +``std::reverse_iterator`` class in situations where pairs of +mutable/constant iterators are needed (e.g., in containers) because +comparisons and conversions between the mutable and const versions are +implemented correctly. + +Template class ``reverse_iterator`` ++++++++++++++++++++++++++++++++++++ + +:: + + template + class reverse_iterator : + public iterator_adaptor< reverse_iterator, Iterator > + { + typedef iterator_adaptor< reverse_iterator, Iterator > super_t; + friend class iterator_core_access; + public: + reverse_iterator() {} + + explicit reverse_iterator(Iterator x) + : super_t(x) {} + + template + reverse_iterator( + reverse_iterator const& r + , typename enable_if_convertible::type* = 0 + ) + : super_t(r.base()) + {} + + private: /* exposition */ + typename super_t::reference dereference() const { return *prior(this->base()); } + + void increment() { super_t::decrement(); } + void decrement() { super_t::increment(); } + + void advance(typename super_t::difference_type n) + { + super_t::advance(-n); + } + + template + typename super_t::difference_type + distance_to(reverse_iterator const& y) const + { + return -super_t::distance_to(y); + } + }; + + +``reverse_iterator`` requirements ++++++++++++++++++++++++++++++++++ + +The base iterator must be a model of Bidirectional Traversal +Iterator. The reverse iterator will model whichever standard iterator +concepts are modeled by the base iterator. For example, if the base +iterator is a model of Random Access Traversal Iterator then so is the +resulting reverse iterator. + + +Transform iterator +------------------ + +The transform iterator adapts an iterator by applying some function +object to the result of dereferencing the iterator. In other words, +the ``operator*`` of the transform iterator first dereferences the +base iterator, passes the result of this to the function object, and +then returns the result. + + +Template class ``transform_iterator`` ++++++++++++++++++++++++++++++++++++++ + +:: + + template + class transform_iterator + : public iterator_adaptor + { + typedef iterator_adaptor super_t; + friend class iterator_core_access; + public: + transform_iterator() { } + + transform_iterator(Iterator const& x, AdaptableUnaryFunction f) + : super_t(x), m_f(f) { } + + template + transform_iterator( + transform_iterator const& t + , typename enable_if_convertible::type* = 0 + ) + : super_t(t.base()), m_f(t.functor()) {} + + AdaptableUnaryFunction functor() const + { return m_f; } + + private: /* exposition */ + typename super_t::value_type dereference() const + { return m_f(super_t::dereference()); } + + AdaptableUnaryFunction m_f; + }; + + +``transform_iterator`` requirements ++++++++++++++++++++++++++++++++++++ + +Write me. Use ``result_of``? + + +Filter iterator +--------------- + +The filter iterator adaptor creates a view of an iterator range in +which some elements of the range are skipped over. A predicate +function object controls which elements are skipped. When the +predicate is applied to an element, if it returns ``true`` then the +element is retained and if it returns ``false`` then the element is +skipped over. + + +Template class ``filter_iterator`` +++++++++++++++++++++++++++++++++++ + +:: + + template + class filter_iterator + : public iterator_adaptor< + filter_iterator, Iterator + , use_default + , /* see details */ + > + { + public: + filter_iterator() { } + filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); + filter_iterator(Iterator x, Iterator end = Iterator()); + template + filter_iterator( + filter_iterator const& t + , typename enable_if_convertible::type* = 0 + ); + Predicate predicate() const; + Iterator end() const; + }; + + + +Counting iterator +----------------- + + +Template class ``counting_iterator`` +++++++++++++++++++++++++++++++++++++ + +:: + + template + class counting_iterator + : public iterator_adaptor + { + typedef iterator_adaptor super_t; + friend class iterator_core_access; + public: + counting_iterator(); + counting_iterator(counting_iterator const& rhs); + counting_iterator(Incrementable x); + }; + + +Function output iterator +------------------------ + +The function output iterator adaptor makes it easier to create custom +output iterators. The adaptor takes a unary function and creates a +model of Output Iterator. Each item assigned to the output iterator is +passed as an argument to the unary function. The motivation for this +iterator is that creating a conforming output iterator is non-trivial, +particularly because the proper implementation usually requires a +proxy object. + + +Template class ``function_output_iterator`` ++++++++++++++++++++++++++++++++++++++++++++ + +:: + + template + class function_output_iterator { + public: + typedef std::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + + explicit function_output_iterator(const UnaryFunction& f = UnaryFunction()) + : m_f(f) {} + + struct output_proxy { + output_proxy(UnaryFunction& f); + template output_proxy& operator=(const T& value); + }; + output_proxy operator*(); + function_output_iterator& operator++(); + function_output_iterator& operator++(int); + }; .. [Cop95] [Coplien, 1995] Coplien, J., Curiously Recurring Template - Patterns, C ++Report, February 1995, pp. 24-27. + Patterns, C++ Report, February 1995, pp. 24-27. diff --git a/doc/new-iter-concepts.rst b/doc/new-iter-concepts.rst index bddf886..238f987 100644 --- a/doc/new-iter-concepts.rst +++ b/doc/new-iter-concepts.rst @@ -230,7 +230,7 @@ combined into a single type using the following `iterator_tag` class. :: template - struct iterator_tag : appropriate old category + struct iterator_tag : /* appropriate old category */ { typedef AccessTag access; typedef TraversalTag traversal; @@ -530,7 +530,7 @@ Addition to [lib.iterator.synopsis] template struct traversal_category; template - struct iterator_tag : appropriate old category { + struct iterator_tag : /* appropriate old category */ { typedef AccessTag access; typedef TraversalTag traversal; };