added a bunch for the specialized adaptors,

also filled out the facade and adaptor sections


[SVN r1181]
This commit is contained in:
Jeremy Siek
2003-04-25 04:51:32 +00:00
parent 80b70a675d
commit 1397e144c1
2 changed files with 524 additions and 65 deletions

View File

@@ -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 ``<iterator_helper>`` 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 Iterator>
class reverse_iterator;
template <class AdaptableUnaryFunction, class Iterator>
class transform_iterator;
template <class Predicate, class Iterator>
class filter_iterator;
template <
class Incrementable,
class Category = use_default,
class Difference = use_default
>
class counting_iterator
template <class UnaryFunction>
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;
<see details> operator->() const;
<see details> 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<Derived const*>(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<Derived, /*impl detail ...*/> {
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<foo*>``) as if it were a container of the pointed-to type
(e.g. ``list<foo>``) .
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</* see discussion */>
{
typedef iterator_adaptor</* see discussion */> 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<Iterator2, Iterator>::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<Iterator>::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>::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 Iterator>
class reverse_iterator :
public iterator_adaptor< reverse_iterator<Iterator>, Iterator >
{
typedef iterator_adaptor< reverse_iterator<Iterator>, Iterator > super_t;
friend class iterator_core_access;
public:
reverse_iterator() {}
explicit reverse_iterator(Iterator x)
: super_t(x) {}
template<class OtherIterator>
reverse_iterator(
reverse_iterator<OtherIterator> const& r
, typename enable_if_convertible<OtherIterator, Iterator>::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 <class OtherIterator>
typename super_t::difference_type
distance_to(reverse_iterator<OtherIterator> 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 AdaptableUnaryFunction, class Iterator>
class transform_iterator
: public iterator_adaptor</* see discussion */>
{
typedef iterator_adaptor</* see discussion */> super_t;
friend class iterator_core_access;
public:
transform_iterator() { }
transform_iterator(Iterator const& x, AdaptableUnaryFunction f)
: super_t(x), m_f(f) { }
template<class OtherIterator>
transform_iterator(
transform_iterator<AdaptableUnaryFunction, OtherIterator> const& t
, typename enable_if_convertible<OtherIterator, Iterator>::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 Predicate, class Iterator>
class filter_iterator
: public iterator_adaptor<
filter_iterator<Predicate, 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<class OtherIterator>
filter_iterator(
filter_iterator<Predicate, OtherIterator> const& t
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0
);
Predicate predicate() const;
Iterator end() const;
};
Counting iterator
-----------------
Template class ``counting_iterator``
++++++++++++++++++++++++++++++++++++
::
template <class Incrementable, class Category = not_specified, class Difference = not_specified>
class counting_iterator
: public iterator_adaptor</* see details */>
{
typedef iterator_adaptor</* see details */> 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 UnaryFunction>
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 <class T> 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.

View File

@@ -230,7 +230,7 @@ combined into a single type using the following `iterator_tag` class.
::
template <class AccessTag, class TraversalTag>
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 <class Iterator> struct traversal_category;
template <class AccessTag, class TraversalTag>
struct iterator_tag : appropriate old category {
struct iterator_tag : /* appropriate old category */ {
typedef AccessTag access;
typedef TraversalTag traversal;
};