diff --git a/doc/access.png b/doc/access.png new file mode 100644 index 0000000..80011dc Binary files /dev/null and b/doc/access.png differ diff --git a/doc/access2old.png b/doc/access2old.png new file mode 100644 index 0000000..8a87b84 Binary files /dev/null and b/doc/access2old.png differ diff --git a/doc/default.css b/doc/default.css new file mode 100644 index 0000000..2e1fddb --- /dev/null +++ b/doc/default.css @@ -0,0 +1,188 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:date: $Date$ +:version: $Revision$ +:copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. +*/ + +.first { + margin-top: 0 } + +.last { + margin-bottom: 0 } + +a.toc-backref { + text-decoration: none ; + color: black } + +dd { + margin-bottom: 0.5em } + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.attention, div.caution, div.danger, div.error, div.hint, +div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +div.hint p.admonition-title, div.important p.admonition-title, +div.note p.admonition-title, div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em } + +div.footer, div.header { + font-size: smaller } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr { + width: 75% } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.line-block { + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option-argument { + font-style: italic } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +table { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.citation { + border-left: solid thin gray ; + padding-left: 0.5ex } + +table.docinfo { + margin: 2em 4em } + +table.footnote { + border-left: solid thin black ; + padding-left: 0.5ex } + +td, th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +th.docinfo-name, th.field-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap } + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + font-size: 100% } + +tt { + background-color: #eeeeee } + +ul.auto-toc { + list-style-type: none } diff --git a/doc/facade-and-adaptor.rst b/doc/facade-and-adaptor.rst new file mode 100644 index 0000000..169b856 --- /dev/null +++ b/doc/facade-and-adaptor.rst @@ -0,0 +1,1598 @@ ++++++++++++++++++++++++++++++ + Iterator Facade and Adaptor ++++++++++++++++++++++++++++++ + +:Author: David Abrahams, Jeremy Siek, Thomas Witt +: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 +.. _`Open Systems Lab`: http://www.osl.iu.edu +.. _`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, both from scratch and + by adapting other iterators. + +.. contents:: Table of Contents + +============ + Motivation +============ + +Iterators play an important role in modern C++ programming. The +iterator is the central abstraction of the algorithms of the Standard +Library, allowing algorithms to be re-used in in a wide variety of +contexts. The C++ Standard Library contains a wide variety of useful +iterators. Every one of the standard containers comes with constant +and mutable iterators [#mutable]_, and also reverse versions of those +same iterators which traverse the container in the opposite direction. +The Standard also supplies ``istream_iterator`` and +``ostream_iterator`` for reading from and writing to streams, +``insert_iterator``, ``front_insert_iterator`` and +``back_insert_iterator`` for inserting elements into containers, and +``raw_storage_iterator`` for initializing raw memory [7]. + +Despite the many iterators supplied by the Standard Library, obvious +and useful iterators are missing, and creating new iterator types is +still a common task for C++ programmers. The literature documents +several of these, for example line_iterator [3] and Constant_iterator +[9]. The iterator abstraction is so powerful that we expect +programmers will always need to invent new iterator types. + +Although it is easy to create iterators that *almost* conform to the +standard, the iterator requirements contain subtleties which can make +creating an iterator which *actually* conforms quite difficult. +Further, the iterator interface is rich, containing many operators +that are technically redundant and tedious to implement. To automate +the repetitive work of constructing iterators, we propose +``iterator_facade``, an iterator base class template which provides +the rich interface of standard iterators and delegates its +implementation to member functions of the derived class. In addition +to reducing the amount of code necessary to create an iterator, the +``iterator_facade`` also provides compile-time error detection. +Iterator implementation mistakes that often go unnoticed are turned +into compile-time errors because the derived class implementation must +match the expectations of the ``iterator_facade``. + +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. As with plain iterators, +iterator adaptors defined outside the Standard have become commonplace +in the literature: + +* Checked iter[13] adds bounds-checking to an existing iterator. + +* The iterators of the View Template Library[14], which adapts + containers, are themselves adaptors over the underlying iterators. + +* Smart iterators [5] adapt an iterator's dereferencing behavior by + applying a function object to the object being referenced and + returning the result. + +* Custom iterators [4], in which a variety of adaptor types are enumerated. + +* Compound iterators [1], which access a slice out of a container of containers. + +* Several iterator adaptors from the MTL [12]. The MTL contains a + strided iterator, where each call to ``operator++()`` moves the + iterator ahead by some constant factor, and a scaled iterator, which + multiplies the dereferenced value by some constant. + +.. [#concept] We use the term concept to mean a set of requirements + that a type must satisfy to be used with a particular template + parameter. + +.. [#mutable] The term mutable iterator refers to iterators over objects that + can be changed by assigning to the dereferenced iterator, while + constant iterator refers to iterators over objects that cannot be + modified. + +To fulfill the need for constructing adaptors, we propose the +``iterator_adaptor`` class template. Instantiations of +``iterator_adaptor`` serve as a base classes for new iterators, +providing the default behavior of forwarding all operations to the +underlying iterator. The user can selectively replace these features +in the derived iterator class. This proposal also includes a number +of more specialized adaptors, such as the ``transform_iterator`` that +applies some user-specified function during the dereference of the +iterator. + +======================== + Impact on the Standard +======================== + +This proposal is purely an addition to the C++ standard library. +However, note that this proposal relies on the proposal for New +Iterator Concepts. + +======== + Design +======== + +Iterator Concepts +================= + +This proposal is formulated in terms of the new ``iterator concepts`` +as proposed in `n1477`_, since user-defined and especially adapted +iterators suffer from the well known categorization problems that are +inherent to the current iterator categories. + +.. _`n1477`: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1477.html + +This proposal does not strictly depend on proposal `n1477`_, as there +is a direct mapping between new and old categories. This proposal +could be reformulated using this mapping if `n1477`_ was not accepted. + +Interoperability +================ + +The question of iterator interoperability is poorly addressed 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 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 +work. This proposal implements the proposed resolution to issue +`179`_, as most standard library implementations do nowadays. In other +words, if an iterator type A has an implicit or user defined +conversion to an iterator type B, the iterator types are interoperable +and the usual set of operators are available. + +Issue `280`_ concerns the current lack of interoperability between +reverse iterator types. The proposed new reverse_iterator template +fixes the issues raised in 280. It provides the desired +interoperability without introducing unwanted overloads. + +.. _`179`: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#179 +.. _`280`: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#280 + + +Iterator Facade +=============== + +While the iterator interface is rich, there is a core subset of the +interface that is necessary for all the functionality. We have +identified the following core behaviors for iterators: + +* dereferencing +* incrementing +* decrementing +* equality comparison +* random-access motion +* distance measurement + +In addition to the behaviors listed above, the core interface elements +include the associated types exposed through iterator traits: +``value_type``, ``reference``, ``difference_type``, and +``iterator_category``. + +Iterator facade uses the Curiously Recurring Template Pattern (CRTP) +[Cop95]_ so that the user can specify the behavior of +``iterator_facade`` in a derived class. Former designs used policy +objects to specify the behavior. The proposal does not use policy +objects for several reasons: + + 1. the creation and eventual copying of the policy object may create + overhead that can be avoided with the current approach. + + 2. The policy object approach does not allow for custom constructors + on the created iterator types, an essential feature if + ``iterator_facade`` should be used in other library + implementations. + + 3. Without the use of CRTP, the standard requirement that an + iterator's ``operator++`` returns the iterator type itself means + that all iterators generated by ``iterator_facade`` would be + instantiations of ``iterator_facade``. Cumbersome type generator + metafunctions would be needed to build new parameterized + iterators, and a separate ``iterator_adaptor`` layer would be + impossible. + +The user of ``iterator_facade`` derives his iterator class from an +instantiation of ``iterator_facade`` and defines member functions +implementing the core behaviors. The following table describes +expressions which are required to be valid depending on the category +of the derived iterator type. These member functions are described +briefly below and in more detail in the `iterator facade requirements`_. + + +----------------------------------------+-------------------------------------------+ + | Expression | Effects | + +========================================+===========================================+ + | ``i.dereference()`` | Access the value referred to | + +----------------------------------------+-------------------------------------------+ + | ``i.equal(j)`` | Compare for equality with ``j`` | + +----------------------------------------+-------------------------------------------+ + | ``i.increment()`` | Advance by one position | + +----------------------------------------+-------------------------------------------+ + | ``i.decrement()`` | Retreat by one position | + +----------------------------------------+-------------------------------------------+ + | ``i.advance(n)`` | Advance by ``n`` positions | + +----------------------------------------+-------------------------------------------+ + | ``i.distance_to(j)`` | Measure the distance to ``j`` | + +----------------------------------------+-------------------------------------------+ + +.. Should we add a comment that a zero overhead implementation of iterator_facade + is possible with proper inlining? + +In addition to implementing the core interface functions, an iterator +derived from ``iterator_facade`` typically defines several +constructors. To model any of the standard iterator concepts, the +iterator must at least have a copy constructor. Also, if the iterator +type ``X`` is meant to be automatically interoperate with another +iterator type ``Y`` (as with constant and mutable iterators) then +there must be an implicit conversion from ``X`` to ``Y`` or from ``Y`` +to ``X`` (but not both), typically implemented as a conversion +constructor. Also, if the iterator is to model Forward Traversal +Iterator, a default constructor is required. + + + +Iterator Core Access +==================== + +``iterator_facade`` and the operator implementations need to be able +to access the core member functions in the derived class. Making the +core member functions 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 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 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. + +.. This is no long uptodate -thw +.. Yes it is; I made sure of it! -DWA + +``iterator_core_access`` will be typically implemented as an empty +class containing only private static member functions which invoke the +iterator core member functions. There is, however, no need to +standardize the gateway protocol. Note that even if +``iterator_core_access`` used public member functions it would not +open a safety loophole, as every core member function preserves the +invariants of the iterator. + +``operator[]`` +================ + +The indexing operator for a generalized iterator presents special +challenges. A random access iterator's ``operator[]`` is only +required to return something convertible to its ``value_type``. +Requiring that it return an lvalue would rule out currently-legal +random-access iterators which hold the referenced value in a data +member (e.g. `counting_iterator`_), because ``*(p+n)`` is a reference +into the temporary iterator ``p+n``, which is destroyed when +``operator[]`` returns. + +Writable iterators built with ``iterator_facade`` implement the +semantics required by the preferred resolution to `issue 299`_ and +adopted by proposal `n1477`_: the result of ``p[n]`` is a proxy object +containing a copy of ``p+n``, and ``p[n] = x`` is equivalent to ``*(p ++ n) = x``. This approach will work properly for any random-access +iterator regardless of the other details of its implementation. A +user who knows more about the implementation of her iterator is free +to implement an ``operator[]`` which returns an lvalue in the derived +iterator class; it will hide the one supplied by ``iterator_facade`` +from clients of her iterator. + +.. _issue 299: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#299 + +``operator->`` +============== + +The ``reference`` type of a readable iterator (and today's input +iterator) need not in fact be a reference, so long as it is +convertible to the iterator's ``value_type``. When the ``value_type`` +is a class, however, it must still be possible to access members +through ``operator->``. Therefore, an iterator whose ``reference`` +type is not in fact a reference must return a proxy containing a copy +of the referenced value from its ``operator->``. + +This proposal does not explicitly specify the return type for +``operator->`` and ``operator[]``. Instead it requires each +``iterator_facade`` instantiation to meet the requirements of its +``iterator_category``. + +Iterator Adaptor +================ + +The ``iterator_adaptor`` class template adapts some ``Base`` [#base]_ +type to create a new iterator. Instantiations of ``iterator_adaptor`` +are derived from a corresponding instantiation of ``iterator_facade`` +and implement the core behaviors in terms of the ``Base`` type. In +essence, ``iterator_adaptor`` merely forwards all operations to an +instance of the ``Base`` type, which it stores as a member. + +.. [#base] The term "Base" here does not refer to a base class and is + not meant to imply the use of derivation. We have followed the lead + of the standard library, which provides a base() function to access + the underlying iterator object of a ``reverse_iterator`` adaptor. + +The user of ``iterator_adaptor`` creates a class derived from an +instantiation of ``iterator_adaptor`` and then selectively +redefines some of the core member functions described in the table +above. The ``Base`` type need not meet the full requirements for an +iterator. It need only support the operations used by the core +interface functions of ``iterator_adaptor`` that have not been +redefined in the user's derived class. + +Several of the template parameters of ``iterator_adaptor`` default to +``use_default``. This allows the user to make use of a default +parameter even when the user wants to specify a parameter later in the +parameter list. Also, the defaults for the corresponding associated +types are fairly complicated, so metaprogramming is required to +compute them, and ``use_default`` can help to simplify the +implementation. Finally, ``use_default`` is not left unspecified +because specification helps to highlight that the ``Reference`` +template parameter may not always be identical to the iterator's +``reference`` type, and will keep users making mistakes based on that +assumtion. + +Specialized Adaptors +==================== + +This proposal also contains several examples of specialized adaptors +which were easily implemented using ``iterator_adaptor``: + +* ``indirect_iterator``, which iterates over iterators, pointers, + or smart pointers and applies an extra level of dereferencing. + +* A new ``reverse_iterator``, which inverts the direction of a Base + iterator's motion, while allowing adapted constant and mutable + iterators to interact in the expected ways (unlike those in most + implementations of C++98). + +* ``transform_iterator``, which applies a user-defined function object + to the underlying values when dereferenced. + +* ``projection_iterator``, which is similar to ``transform_iterator`` + except that when dereferenced it returns a reference instead of + a value. + +* ``filter_iterator``, which provides a view of an iterator range in + which some elements of the underlying range are skipped. + +.. _counting_iterator: + +* ``counting_iterator``, which adapts any incrementable type + (e.g. integers, iterators) so that incrementing/decrementing the + adapted iterator and dereferencing it produces successive values of + the Base type. + +* ``function_output_iterator``, which makes it easier to create custom + output iterators. + +Based on examples in the Boost library, users have generated many new +adaptors, among them a permutation adaptor which applies some +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++ +Standard compliant iterators). + +=============== + Proposed Text +=============== + + +Header ```` synopsis [lib.iterator.helper.synopsis] +======================================================================= + + +:: + + struct use_default; + + struct iterator_core_access { /* implementation detail */ }; + + template < + class Derived + , class Value + , class AccessCategory + , class TraversalCategory + , class Reference = Value& + , class Difference = ptrdiff_t + > + class iterator_facade; + + template < + class Derived + , class Base + , class Value = use_default + , class Category = use_default + , class Reference = 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 Difference = use_default + > + class indirect_iterator; + + template + class reverse_iterator; + + template < + class UnaryFunction + , class Iterator + , class Reference = use_default + , class Value = use_default + > + 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 [lib.iterator.facade] +===================================== + +``iterator_facade`` is a base class template which implements the +interface of standard iterators in terms of a few core functions +and associated types, to be supplied by a derived iterator class. + +Class template ``iterator_facade`` +---------------------------------- + +:: + + template < + class Derived + , class Value + , class AccessCategory + , class TraversalCategory + , class Reference = /* see below */ + , class Difference = ptrdiff_t + > + class iterator_facade { + public: + typedef remove_cv::type value_type; + typedef Reference reference; + typedef /* see description of operator-> */ pointer; + typedef Difference difference_type; + typedef iterator_tag iterator_category; + + reference operator*() const; + /* see below */ operator->() const; + /* impl defined */ operator[](difference_type n) const; + Derived& operator++(); + Derived operator++(int); + Derived& operator--(); + Derived operator--(int); + Derived& operator+=(difference_type n); + Derived& operator-=(difference_type n); + Derived operator-(difference_type n) const; + }; + + // Comparison operators + template + typename enable_if_interoperable::type // exposition + operator ==(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator !=(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator <(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator <=(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator >(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator >=(iterator_facade const& lhs, + iterator_facade const& rhs); + + template + typename enable_if_interoperable::type + operator >=(iterator_facade const& lhs, + iterator_facade const& rhs); + + // Iterator difference + template + typename enable_if_interoperable::type + operator -(iterator_facade const& lhs, + iterator_facade const& rhs); + + // Iterator addition + template + Derived operator+ (iterator_facade const&, + typename Derived::difference_type n) + + +[*Note:* The ``enable_if_interoperable`` template used above is for exposition +purposes. The member operators should be only be in an overload set +provided the derived types ``Dr1`` and ``Dr2`` are interoperable, by +which we mean they are convertible to each other. The +``enable_if_interoperable`` approach uses SFINAE to take the operators +out of the overload set when the types are not interoperable.] + + +.. we need a new label here because the presence of markup in the + title prevents an automatic link from being generated + +.. _iterator facade requirements: + +``iterator_facade`` requirements +-------------------------------- + +The ``Derived`` template parameter must be a class derived from +``iterator_facade``. + +The default for the ``Reference`` parameter is `Value&`` if the access +category for ``iterator_facade`` is implicitly convertible to +``writable_iterator_tag``, and ``const Value&`` otherwise. + +The following table describes the other requirements on the +``Derived`` parameter. Depending on the resulting iterator's +``iterator_category``, a subset of the expressions listed in the table +are required to be valid. The operations in the first column must be +accessible to member functions of class ``iterator_core_access``. + +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 +------------------------------ + +The operations in this section are described in terms of operations on +the core interface of ``Derived`` which may be inaccessible +(i.e. private). The implementation should access these operations +through member functions of class ``iterator_core_access``. + +``reference operator*() const;`` + +:Returns: ``static_cast(this)->dereference()`` + +*see below* ``operator->() const;`` + +:Returns: If ``X::reference`` is a reference type, returns an object + of type ``X::pointer`` equal to:: + + &static_cast(this)->dereference() + + Otherwise returns an object of unspecified type such that, given an + object ``a`` of type ``X``, ``a->m`` is equivalent to ``(w = *a, + w.m)`` for some temporary object ``w`` of type ``X::value_type``. + + The type ``X::pointer`` is ``Value*`` if the access category for + ``X`` is implicitly convertible to ``writable_iterator_tag``, and + ``Value const*`` otherwise. + + +*unspecified* ``operator[](difference_type n) const;`` + +:Returns: an object convertible to ``X::reference`` and holding a copy + *p* of ``a+n`` such that, for a constant object ``v`` of type + ``X::value_type``, ``X::reference(a[n] = v)`` is equivalent + to ``p = v``. + + + +``Derived& operator++();`` + +:Effects: + + :: + + static_cast(this)->increment(); + return *this; + +.. I realize that the committee is moving away from specifying things + like this in terms of code, but I worried about the imprecision of + saying that a core interface function is invoked without describing + the downcast. An alternative to what I did would be to mention it + above where we talk about accessibility. + + +``Derived operator++(int);`` + +:Effects: + + :: + + Derived tmp(static_cast(this)); + ++*this; + return tmp; + + +``Derived& operator--();`` + +:Effects: + + :: + + static_cast(this)->decrement(); + return *this; + + +``Derived operator--(int);`` + +:Effects: + + :: + + Derived tmp(static_cast(this)); + --*this; + return tmp; + + +``Derived& operator+=(difference_type n);`` + +:Effects: + + :: + + static_cast(this)->advance(n); + return *this; + + +``Derived& operator-=(difference_type n);`` + +:Effects: + + :: + + static_cast(this)->advance(-n); + return *this; + + +``Derived operator-(difference_type n) const;`` + +:Effects: + + Derived tmp(static_cast(this)); + return tmp -= n; + +:Returns: ``static_cast(this)->advance(-n);`` + + +Iterator adaptor [lib.iterator.adaptor] +======================================= + +The ``iterator_adaptor`` is a base class template derived from an +instantiation of ``iterator_facade``. The core interface functions +expected by ``iterator_facade`` are implemented in terms of the +``iterator_adaptor``\ 's ``Base`` template parameter. A class derived +from ``iterator_adaptor`` typically redefines some of the core +interface functions to adapt the behavior of the ``Base`` type. +Whether the derived class models any of the standard iterator concepts +depends on the operations supported by the ``Base`` type and which +core interface functions of ``iterator_facade`` are redefined in the +``Derived`` class. + + +Class template ``iterator_adaptor`` +----------------------------------- + +:: + + template < + class Derived + , class Base + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Difference = use_default + > + class iterator_adaptor + : public iterator_facade + { + friend class iterator_core_access; + public: + iterator_adaptor(); + explicit iterator_adaptor(Base iter); + Base base() const; + protected: + Base const& base_reference() const; + Base& base_reference(); + private: // Core iterator interface for iterator_facade. + typename iterator_adaptor::reference dereference() const; + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + bool equal(iterator_adaptor const& x) const; + + void advance(typename iterator_adaptor::difference_type n); + void increment(); + void decrement(); + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + typename iterator_adaptor::difference_type distance_to( + iterator_adaptor const& y) const; + + private: + Base m_iterator; + }; + + + +``iterator_adaptor`` requirements +--------------------------------- + +The ``Derived`` template parameter must be a derived class of +``iterator_adaptor``. The ``Base`` type must implement the expressions +involving ``m_iterator`` in the specifications of those private member +functions of ``iterator_adaptor`` that are not redefined by the +``Derived`` class and that are needed to model the concept +corresponding to the chosen ``Category`` according to the requirements +of ``iterator_facade``. The rest of the template parameters specify +the types for the member typedefs in ``iterator_facade``. The +following pseudo-code specifies the traits types for +``iterator_adaptor``. + +:: + + if (Value == use_default) + value_type = iterator_traits::value_type; + else + value_type = remove_cv::type; + + if (Reference == use_default) { + if (Value == use_default) + reference = iterator_traits::reference; + else + reference = Value&; + } else + reference = Reference; + + if (Distance == use_default) + difference_type = iterator_traits::difference_type; + else + difference_type = Distance; + + if (Category == use_default) + iterator_category = iterator_tag< + access_category< + iterator< iterator_traits::iterator_category, + Value, + Distance, + Value*, + Reference > >, + traversal_category< + iterator< iterator_traits::iterator_category, + Value, + Distance, + Value*, + Reference > > + else + iterator_category = Category; + + +.. Replaced with new semantics --thw + if (Category == use_default) + iterator_category = iterator_traits::iterator_category; + else + iterator_category = Category; + + + +``iterator_adaptor`` public operations +-------------------------------------- + +``iterator_adaptor();`` + +:Requires: The ``Base`` type must be Default Constructible. +:Returns: An instance of ``iterator_adaptor`` with + ``m_iterator`` default constructed. + + +``explicit iterator_adaptor(Base iter);`` + +:Returns: An instance of ``iterator_adaptor`` with + ``m_iterator`` copy constructed from ``iter``. + +``Base base() const;`` + +:Returns: ``m_iterator`` + + +``iterator_adaptor`` protected member functions +----------------------------------------------- + +``Base const& base_reference() const;`` + +:Returns: A const reference to ``m_iterator``. + + +``Base& base_reference();`` + +:Returns: A non-const reference to ``m_iterator``. + + +``iterator_adaptor`` private member functions +--------------------------------------------- + +``typename iterator_adaptor::reference dereference() const;`` + +:Returns: ``*m_iterator`` + +:: + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + bool equal(iterator_adaptor const& x) const; + +:Returns: ``m_iterator == x.base()`` + + +``void advance(typename iterator_adaptor::difference_type n);`` + +:Effects: ``m_iterator += n;`` + +``void increment();`` + +:Effects: ``++m_iterator;`` + +``void decrement();`` + +:Effects: ``--m_iterator;`` + +:: + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + typename iterator_adaptor::difference_type distance_to( + iterator_adaptor const& y) const; + +:Returns: ``y.base() - m_iterator`` + + + +Specialized adaptors [lib.iterator.special.adaptors] +==================================================== + +.. The requirements for all of these need to be written *much* more + formally -DWA + + +[*Note:* The ``enable_if_convertible::type`` expression used in +this section is for exposition purposes. The converting constructors +for specialized adaptors should be only be in an overload set provided +that an object of type ``X`` is implicitly convertible to an object of +type ``Y``. The ``enable_if_convertible`` approach uses SFINAE to +take the constructor out of the overload set when the types are not +implicitly convertible.] + + +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``) . + +.. At some point we should add the capability to handle + iterators over smart pointers, which the impl handles. -JGS + + +Class template ``indirect_iterator`` +.................................... + +:: + + template < + class Iterator + , class Value = use_default + , class Category = use_default + , class Reference = use_default + , class Difference = use_default + > + class indirect_iterator + : public iterator_adaptor + { + friend class iterator_core_access; + public: + indirect_iterator(); + indirect_iterator(Iterator x); + template < + class Iterator2, class Value2, class Category2 + , class Reference2, class Difference2 + > + indirect_iterator( + indirect_iterator< + Iterator2, Value2, Category2, Reference2, Difference2 + > const& y + , typename enable_if_convertible::type* = 0 // exposition + ); + private: // as-if specification + typename indirect_iterator::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 ``Category`` parameter is the ``iterator_category`` type for the +``indirect_iterator``. The default is +``iterator_traits::iterator_category``. + +The indirect iterator will model the most refined standard traversal +concept that is modeled by the ``Iterator`` type. The indirect +iterator will model the most refined standard access concept that is +modeled by the value type of ``Iterator``. + + +``indirect_iterator`` operations +................................ + +``indirect_iterator();`` + +:Requires: ``Iterator`` must be Default Constructible. +:Returns: An instance of ``indirect_iterator`` with + a default constructed base object. + + +``indirect_iterator(Iterator x);`` + +:Returns: An instance of ``indirect_iterator`` with + the ``iterator_adaptor`` subobject copy constructed from ``x``. + +:: + + template < + class Iterator2, class Value2, class Category2 + , class Reference2, class Difference2 + > + indirect_iterator( + indirect_iterator< + Iterator2, Value2, Category2, Reference2, Difference2 + > const& y + , typename enable_if_convertible::type* = 0 // exposition + ); + +:Requires: ``Iterator2`` is implicitly convertible to ``Iterator``. +:Returns: An instance of ``indirect_iterator`` that is a copy of ``y``. + +Reverse iterator +---------------- + +.. I think we'd better strike the old reverse_iterator text from the standard, eh? + +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. + +Class template ``reverse_iterator`` +................................... + +:: + + template + class reverse_iterator : + public iterator_adaptor< reverse_iterator, Iterator > + { + friend class iterator_core_access; + public: + reverse_iterator() {} + explicit reverse_iterator(Iterator x) ; + + template + reverse_iterator( + reverse_iterator const& r + , typename enable_if_convertible::type* = 0 // exposition + ); + + private: // as-if specification + typename reverse_iterator::reference dereference() const { return *prior(this->base()); } + + void increment() { --this->base_reference(); } + void decrement() { ++this->base_reference(); } + + void advance(typename reverse_iterator::difference_type n) + { + this->base_reference() += -n; + } + + template + typename reverse_iterator::difference_type + distance_to(reverse_iterator const& y) const + { + return this->base_reference() - y.base(); + } + + }; + + +``reverse_iterator`` requirements +................................. + +The base ``Iterator`` must be a model of Bidirectional Traversal +Iterator. The resulting ``reverse_iterator`` will be a model of the +most refined standard traversal and access concepts that are modeled +by ``Iterator``. + + +``reverse_iterator();`` + +:Requires: ``Iterator`` must be Default Constructible. +:Returns: An instance of ``reverse_iterator`` with a + default constructed base object. + +``explicit reverse_iterator(Iterator x);`` + +:Returns: An instance of ``reverse_iterator`` with a + base object copy constructed from ``x``. + + +:: + + template + reverse_iterator( + reverse_iterator const& r + , typename enable_if_convertible::type* = 0 // exposition + ); + +:Requires: ``OtherIterator`` is implicitly convertible to ``Iterator``. +:Returns: An instance of ``reverse_iterator`` that is a copy of ``r``. + + +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. + + +Class template ``transform_iterator`` +..................................... + +:: + + template + class transform_iterator + : public iterator_adaptor + { + friend class iterator_core_access; + public: + transform_iterator(); + transform_iterator(Iterator const& x, AdaptableUnaryFunction f); + + template + transform_iterator( + transform_iterator const& t + , typename enable_if_convertible::type* = 0 // exposition + ); + + AdaptableUnaryFunction functor() const; + private: + typename transform_iterator::value_type dereference() const; + AdaptableUnaryFunction m_f; + }; + + +``transform_iterator`` requirements +................................... + +The type ``AdaptableUnaryFunction`` must be Assignable, Copy +Constructible, and the expression ``f(x)`` must be valid where ``f`` +is an object of type ``AdaptableUnaryFunction``, ``x`` is an object of +type ``AdaptableUnaryFunction::argument_type``, and where the type of +``f(x)`` must be ``AdaptableUnaryFunction::result_type``. + +The type ``Iterator`` must at least model Readable Iterator. The +resulting ``transform_iterator`` models the most refined of the +following options that is also modeled by ``Iterator``. + + * Writable Lvalue Iterator if the ``result_type`` of the + ``AdaptableUnaryFunction`` is a non-const reference. + + * Readable Lvalue Iterator if the ``result_type`` is a const + reference. + + * Readable Iterator otherwise. + + +The ``transform_iterator`` models the most refined standard traversal +concept that is modeled by ``Iterator``. + +The ``value_type`` of ``transform_iterator`` is +``remove_reference::type``. The ``reference`` type is +``result_type``. + + +``transform_iterator`` public operations +........................................ + + +``transform_iterator();`` + +:Returns: An instance of ``transform_iterator`` with ``m_f`` + and ``m_iterator`` default constructed. + + +``transform_iterator(Iterator const& x, AdaptableUnaryFunction f);`` + +:Returns: An instance of ``transform_iterator`` with ``m_f`` + initialized to ``f`` and ``m_iterator`` initialized to ``x``. + + +:: + + template + transform_iterator( + transform_iterator const& t + , typename enable_if_convertible::type* = 0 // exposition + ); + +:Returns: An instance of ``transform_iterator`` that is a copy of ``t``. +:Requires: ``OtherIterator`` is implicitly convertible to ``Iterator``. + +``AdaptableUnaryFunction functor() const;`` + +:Returns: ``m_f`` + +``transform_iterator`` private operations +......................................... + +``typename transform_iterator::value_type dereference() const;`` + +:Returns: ``m_f(transform_iterator::dereference());`` + + + +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. When skipping over elements, it is necessary for the +filter adaptor to know when to stop so as to avoid going past the end +of the underlying range. Therefore the constructor of the filter +iterator takes two iterator parameters: the position for the filtered +iterator and the end of the range. + + + +Class template ``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 // exposition + ); + Predicate predicate() const; + Iterator end() const; + + private: // as-if specification + void increment() + { + ++(this->base_reference()); + satisfy_predicate(); + } + + void satisfy_predicate() + { + while (this->base() != this->m_end && !this->m_predicate(*this->base())) + ++(this->base_reference()); + } + + Predicate m_predicate; + Iterator m_end; + }; + + +``filter_iterator`` requirements +-------------------------------- + +The base ``Iterator`` parameter must be a model of Readable Iterator +and Single Pass Iterator. The resulting ``filter_iterator`` will be a +model of Forward Traversal Iterator if ``Iterator`` is, otherwise the +``filter_iterator`` will be a model of Single Pass Iterator. The +access category of the ``filter_iterator`` will be the most refined +standard access category that is modeled by ``Iterator``. + +.. Thomas is going to try implementing filter_iterator so that + it will be bidirectional if the underlying iterator is. -JGS + + +The ``Predicate`` must be Assignable, Copy Constructible, and the +expression ``p(x)`` must be valid where ``p`` is an object of type +``Predicate``, ``x`` is an object of type +``iterator_traits::value_type``, and where the type of +``p(x)`` must be convertible to ``bool``. + + + +``filter_iterator`` operations +------------------------------ + +``filter_iterator();`` + +:Requires: ``Predicate`` and ``Iterator`` must be Default Constructible. +:Returns: a ``filter_iterator`` whose + predicate is a default constructed ``Predicate`` and + whose ``end`` is a default constructed ``Iterator``. + + +``filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());`` + +:Returns: A ``filter_iterator`` at position ``x`` that filters according + to predicate ``f`` and that will not increment past ``end``. + + +``filter_iterator(Iterator x, Iterator end = Iterator());`` + +:Requires: ``Predicate`` must be Default Constructible. +:Returns: A ``filter_iterator`` at position ``x`` that filters + according to a default constructed ``Predicate`` + and that will not increment past ``end``. + + +:: + + template + filter_iterator( + filter_iterator const& t + , typename enable_if_convertible::type* = 0 // exposition + );`` + +:Requires: ``OtherIterator`` is implicitly convertible to ``Iterator``. +:Returns: A copy of iterator ``t``. + + +``Predicate predicate() const;`` + +:Returns: A copy of the predicate object used to construct ``*this``. + + +``Iterator end() const;`` + +:Returns: The object ``end`` used to construct ``*this``. + + +Counting iterator +----------------- + +The counting iterator adaptor implements dereference by returning a +reference to the base object. The other operations are implemented by +the base ``m_iterator``, as per the inheritance from +``iterator_adaptor``. + + +Class template ``counting_iterator`` +.................................... + +:: + + template + class counting_iterator + : public iterator_adaptor< + counting_iterator + , Incrementable + , Incrementable + , /* see details for category */ + , Incrementable const& + , Incrementable const* + , /* distance = Difference or a signed integral type */> + { + friend class iterator_core_access; + public: + counting_iterator(); + counting_iterator(counting_iterator const& rhs); + counting_iterator(Incrementable x); + private: + typename counting_iterator::reference dereference() const + { + return this->base_reference(); + } + }; + + +[*Note:* implementers are encouraged to provide an implementation of + ``distance_to`` and a ``difference_type`` that avoids overflows in + the cases when the ``Incrementable`` type is a numeric type.] + +``counting_iterator`` requirements +---------------------------------- + +The ``Incrementable`` type must be Default Constructible, Copy +Constructible, and Assignable. The default distance is +an implementation defined signed integegral type. + +The resulting ``counting_iterator`` models Readable Lvalue Iterator. + +Furthermore, if you wish to create a counting iterator that is a Forward +Traversal Iterator, then the following expressions must be valid: +:: + + Incrementable i, j; + ++i // pre-increment + i == j // operator equal + +If you wish to create a counting iterator that is a +Bidirectional Traversal Iterator, then pre-decrement is also required: +:: + + --i + +If you wish to create a counting iterator that is a Random Access +Traversal Iterator, then these additional expressions are also +required: +:: + + counting_iterator::difference_type n; + i += n + n = i - j + i < j + + + + +``counting_iterator`` operations +-------------------------------- + +``counting_iterator();`` + +:Returns: A default constructed instance of ``counting_iterator``. + + +``counting_iterator(counting_iterator const& rhs);`` + +:Returns: An instance of ``counting_iterator`` that is a copy of ``rhs``. + + + +``counting_iterator(Incrementable x);`` + +:Returns: An instance of ``counting_iterator`` with its base + object copy constructed from ``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. + + +Class template ``function_output_iterator`` +........................................... + +:: + + template + class function_output_iterator { + public: + typedef iterator_tag< + writable_iterator_tag + , incrementable_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()); + + 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); + }; + + +``function_output_iterator`` requirements +----------------------------------------- + +The ``UnaryFunction`` must be Assignable, Copy Constructible, and the +expression ``f(x)`` must be valid, where ``f`` is an object of type +``UnaryFunction`` and ``x`` is an object of a type accepted by ``f``. +The resulting ``function_output_iterator`` is a model of the Writable +and Incrementable Iterator concepts. + + +``function_output_iterator`` operations +--------------------------------------- + +``explicit function_output_iterator(const UnaryFunction& f = UnaryFunction());`` + +:Returns: An instance of ``function_output_iterator`` with + ``f`` stored as a data member. + + +``output_proxy operator*();`` + +:Returns: An instance of ``output_proxy`` constructed with + a copy of the unary function ``f``. + + +``function_output_iterator& operator++();`` + +:Returns: ``*this`` + + +``function_output_iterator& operator++(int);`` + +:Returns: ``*this`` + + +``function_output_iterator::output_proxy`` operations +----------------------------------------------------- + +``output_proxy(UnaryFunction& f);`` + +:Returns: An instance of ``output_proxy`` with ``f`` stored as + a data member. + + +``template output_proxy& operator=(const T& value);`` + +:Effects: + :: + + m_f(value); + return *this; + + + +.. [Cop95] [Coplien, 1995] Coplien, J., Curiously Recurring Template + Patterns, C++ Report, February 1995, pp. 24-27. + +.. + LocalWords: Abrahams Siek Witt istream ostream iter MTL strided interoperate + LocalWords: CRTP metafunctions inlining lvalue JGS incrementable BGL LEDA cv + LocalWords: GraphBase struct ptrdiff UnaryFunction const int typename bool pp + LocalWords: lhs rhs SFINAE markup iff tmp OtherDerived OtherIterator DWA foo + LocalWords: dereferenceable subobject AdaptableUnaryFunction impl pre ifdef'd + LocalWords: OtherIncrementable Coplien diff --git a/doc/iterator-categories.html b/doc/iterator-categories.html new file mode 100644 index 0000000..eb76523 --- /dev/null +++ b/doc/iterator-categories.html @@ -0,0 +1,822 @@ + +Improved Iterator Categories and Requirements + + + +

+
Improved Iterator Categories and Requirements

+

Introduction

The standard iterator categories and requirements are +flawed because they use a single hierarchy of requirements to address two +orthogonal issues: iterator traversal and dereference return +type. The current iterator requirement hierarchy is mainly geared +towards iterator traversal (hence the category names), while requirements that +address dereference return type sneak in at various places. The following table +gives a summary of the current dereference return type requirements in the +iterator categories. +

+

+ + + + + + + + + + + + + + +
Output Iterator*i = a
Input Iterator*i is convertible to T
Forward Iterator*i is T& (or const T& once issue + 200 is resolved)
Random Access Iteratori[n] is convertible to T (which is odd because the + operational semantics say i[n] is equivalent to *(i + n) + which would have a return type of T&)
Table 1. Summary of current dereference return type + requirements.
+

Examples of useful iterators that do not ``fit''

+

Because of the mixing of iterator traversal and dereference return type, many +useful iterators can not be appropriately categorized. For example, +vector<bool>::iterator is almost a random access iterator, but +the return type is not bool& (see +issue 96 +and Herb Sutter's paper J16/99-0008 = WG21 N1185). Therefore, the +iterators only meet the requirements of input iterator and output iterator. This +is so nonintuitive that at least one implementation erroneously assigns +random_access_iterator_tag as its iterator_category. Also, +vector<bool> is not the only example of useful iterators that do +not return true references: there is the often cited example of disk-based +collections. +

Another example is a counting iterator, an iterator the returns a sequence of +integers when incremented and dereferenced (see boost::counting_iterator). +There are two ways to implement this iterator, 1) make the reference +type be a true reference (a reference to an integer data member of the counting +iterator) or 2) make the reference type be the same as the +value_type. Option 1) runs into the problems discussed in Issue +198, the reference will not be valid after the iterator is destroyed. Option +2) is therefore a better choice, but then we have a counting iterator that +cannot be a random access iterator. +

Yet another example is a transform iterator, an iterator adaptor that applies +a unary function object to the dereference value of the wrapped iterator (see boost::transform_iterator). +For unary functions such as std::times the return type of +operator* clearly needs to be the result_type of the function +object, which is typically not a reference. However, with the current iterator +requirements, if you wrap int* with a transform iterator, you do not +get a random access iterator as expected, but an input iterator. +

A fourth example is found in the vertex and edge iterators of the Boost Graph +Library. These iterators return vertex and edge descriptors, which are +lightweight handles created on-the-fly. They must be returned by-value. As a +result, their current standard iterator category is +std::input_iterator_tag, which means that, strictly speaking, you could +not use these iterators with algorithms like std::min_element(). As a +temporary solution, we introduced the concept Multi-Pass +Input Iterator to describe the vertex and edge descriptors, but as the +design notes for concept suggest, a better solution is needed. +

In short, there are many useful iterators that do not fit into the current +standard iterator categories. As a result, the following bad things happen: +

    +
  • Iterators are often miss-categorized. +
  • Algorithm requirements are more strict than necessary, because they can + not separate out the need for random-access from the need for a true reference + return type.
+

Proposal for new iterator categories and requirements

The iterator +requirements should be separated into two hierarchies. One set of concepts +handles the return type semantics: +The other set of concepts handles iterator +traversal: + + +

The current Input Iterator and Output Iterator requirements will +continue to be used as is. Note that Input Iterator implies Readable +Iterator and Output Iterator implies Writable Iterator.

+ +

Note: we considered defining a Single-Pass Iterator, which could be +combined with Readable or Writable Iterator to replace the Input and +Output Iterator requirements. We rejected this idea because there are +several differences between Input and Output Iterators that make it +hard to merge them: Input Iterator requires Equality Comparable while +Output Iterator does not and Input Iterator requires Assignable while +Output Iterator does not.

+ +

New category tags and traits classes

+ +

The new iterator categories will require new tag classes.

+ +
namespace std {
+
+  // Returns Category Tags
+  struct readable_iterator_tag { };
+  struct writable_iterator_tag { };
+  struct swappable_iterator_tag { };
+  struct mutable_lvalue_iterator_tag : virtual public writable_iterator_tag,
+    virtual public readable_iterator_tag { };
+  struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
+
+  // Traversal Category Tags
+  struct input_traversal_tag { };
+  struct output_traversal_tag { };
+  struct forward_traversal_tag { };
+  struct bidirectional_traversal_tag : public forward_traversal_tag { };
+  struct random_access_traversal_tag : public bidirectional_traversal_tag { };
+
+}
+
+ +

Access to the return and traversal tags will be through the +following two traits classes, which have a member typedef named +type that provides the tag type. We explain the +definitions of these classes later.

+ +
+  template <typename Iterator>
+  struct return_category; // contains: typedef ... type;
+
+  template <typename Iterator>
+  struct traversal_category; // contains: typedef ... type;
+
+ +

We want it to be convenient for programmers to create iterators +that satisfy both the old and new iterator requirements. Therefore +the following class is provided as a way to create tags for use as the +old iterator_category typedef within +iterator_traits. + +

namespace std {
+  template <class ReturnTag, class TraversalTag>
+  struct iterator_tag : cvt_iterator_category<ReturnTag, TraversalTag>::type
+  {
+    typedef ReturnTag returns;
+    typedef TraversalTag traversal;
+  };
+
+ +

The cvt_iterator_category template computes the +appropriate old iterator category based on the return and traversal +category.

+ +
namespace std {
+  template <class RC, class TC>
+  struct cvt_iterator_category
+  {
+    // Pseudo-code, <= means inherits or same type
+    if (RC <= constant_lvalue_iterator_tag || RC <= mutable_lvalue_iterator_tag) {
+      if (TC <= random_access_traversal_tag)
+        typedef random_access_iterator_tag type;
+      else if (TC <= bidirectional_traversal_tag)
+        typedef bidirectional_iterator_tag type;
+      else if (TC <= forward_traversal_tag)
+        typedef forward_iterator_tag type;
+      else
+        error;
+   } else if (RC <= readable_iterator_tag && RC <= input_traversal_tag)
+     typedef input_iterator_tag type;
+   else if (RC <= writable_iterator_tag && output_traversal_tag)
+     typedef output_iterator_tag type;
+   else
+     error;
+  };
+}
+
+ +

The following is an example of a new iterator class using the +iterator_tag class to create its iterator_category +member typedef.

+ +
+struct my_iterator {
+  typedef std::iterator_tag<std::readable_iterator_tag, 
+    std::random_access_traversal_tag> iterator_category;
+  ...
+};
+
+ +We also want old iterators to work with new algorithms, that is, +algorithms that use the new iterator categories. We facilitate this by +defining the return_category and traversal_category +in such a way as they can be used with both old and new iterators. +For old iterators, the appropriate return and traversal categories are +computed based on the old iterator category. For new iterators, the +return and traversal tags are extracted from within the +iterator_category tag. + + +
+  template <typename Iterator>
+  class return_category
+  {
+    // Pseudo-code
+    typedef iterator_traits<Iterator>::iterator_category tag;
+    typedef iterator_traits<Iterator>::value_type T;
+  public:
+    if (exists(tag::returns)) // must be a new iterator
+      typedef tag::returns type;
+    else if (tag <= forward_iterator_tag) {
+      if (is-const(T))
+        typedef constant_lvalue_iterator_tag type;
+      else
+        typedef mutable_lvalue_iterator_tag type;
+    } else if (tag <= input_iterator_tag)
+      typedef readable_iterator_tag type;
+    else if (tag <= output_iterator_tag)
+      typedef writable_iterator_tag type;
+    else
+      error;
+  };
+
+  template <typename T>
+  struct return_category<T*>
+  {
+    // Pseudo-code
+    if (is-const(T))
+      typedef boost::constant_lvalue_iterator_tag type;
+    else
+      typedef boost::mutable_lvalue_iterator_tag type;
+  };
+
+  template <typename Iterator>
+  class traversal_category
+  {
+    typedef iterator_traits<Iterator>::iterator_category tag;
+  public:
+    // Pseudo-code
+    if (exists(tag::traversal)) // must be a new iterator
+      typedef tag::traversal type;
+    else if (tag <= random_access_iterator_tag)
+      typedef random_access_traversal_tag type;
+    else if (tag <= bidirectional_iterator_tag)
+      typedef bidirectional_traversal_tag type;
+    else if (tag <= is_forward_iterator_tag)
+      typedef forward_traversal_tag type;
+    else if (tag <= input_iterator_tag)
+      typedef input_traversal_tag type;
+    else if (tag <= out_iterator_tag)
+      typedef output_traversal_tag type;
+    else
+      error;
+  };
+
+  template <typename T>
+  struct traversal_category<T*>
+  {
+    typedef random_access_traversal_tag type;
+  };
+
+ +

Impact on the Standard Algorithms

+ +

Many of the standard algorithms place more requirements than +necessary on their iterator parameters due to the coarseness of the +current iterator categories. By using the new iterator categories a +better fit can be achieved, thereby increasing the reusability of the +algorithms. These changes will not affect user-code, though they will +require changes by standard implementers: dispatching should be based +on the new categories, and in places return values may need to be +handled more carefully. In particular, uses of std::swap() +will need to be replaced with std::iter_swap(), and +std::iter_swap() will need to call std::swap().

+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AlgorithmRequirement Change
find_endForward Iterator
-> Forward Traversal Iterator and + Readable Iterator
find_first_of
adjacent_find
search
search_n
rotate_copy
lower_bound
upper_bound
equal_range
binary_search
min_element
max_element
iter_swapForward Iterator
-> Swappable Iterator
fillForward Iterator
-> Forward Traversal Iterator and + Writable Iterator
generate
swap_rangesForward Iterator
-> Forward Traversal Iterator and + Swappable Iterator
rotate
replaceForward Iterator
-> Forward Traversal Iterator + and
Readable Iterator and Writable Iterator
replace_if
remove
remove_if
unique
reverseBidirectional Iterator
-> Bidirectional Traversal + Iterator and Swappable Iterator
partition
copy_backwardsBidirectional Iterator
-> Bidirectional Traversal Iterator and + Readable Iterator
Bidirectional Iterator
-> Bidirectional + Traversal Iterator and Writable Iterator
next_permutationBidirectional Iterator
-> Bidirectional Traversal + Iterator and
Swappable Iterator and Readable Iterator
prev_permutation
stable_partitionBidirectional Iterator
-> Bidirectional Traversal + Iterator and
Readable Iterator and Writable Iterator
inplace_merge
reverse_copyBidirectional Iterator
-> Bidirectional Traversal Iterator and + Readable Iterator
random_shuffleRandom Access Iterator
-> Random Access Traversal + Iterator and Swappable Iterator
sort
stable_sort
partial_sort
nth_element
push_heap
pop_heap
make_heap
sort_heap
Table 2. Requirement changes for standard + algorithms.
+

The New Iterator Requirements

+

Notation

+ + + + + + + + + + + + + +
XThe iterator type.
TThe value type of X, i.e., + std::iterator_traits<X>::value_type.
x, yAn object of type X.
tAn object of type T.
+

+


+ +

Readable Iterator

A Readable +Iterator is an iterator that dereferences to produce an rvalue that is +convertible to the value_type of the iterator. +

Associated Types

+ + + + + + + + + + + + + +
Value typestd::iterator_traits<X>::value_typeThe type of the objects pointed to by the iterator.
Reference typestd::iterator_traits<X>::referenceThe return type of dereferencing the iterator. This type must be + convertible to T.
Return Categorystd::return_category<X>::typeA type convertible to std::readable_iterator_tag +
+

Refinement of

Copy +Constructible +

Valid expressions

+ + + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Dereference*x std::iterator_traits<X>::reference
Member accessx->mT is a type with a member named m.If m is a data member, the type of m. If m + is a member function, the return type of m.
+

+


+ +

Writable Iterator

A Writable +Iterator is an iterator that can be used to store a value using the +dereference-assignment expression. +

Definitions

If x is an Writable Iterator of type X, +then the expression *x = a; stores the value a into +x. Note that operator=, like other C++ functions, may be +overloaded; it may, in fact, even be a template function. In general, then, +a may be any of several different types. A type A belongs to +the set of value types of X if, for an object a of type +A, *x = a; is well-defined and does not require performing any +non-trivial conversions on a. +

Associated Types

+ + + + + +
Return Categorystd::return_category<X>::typeA type convertible to std::writable_iterator_tag +
+

Refinement of

Copy +Constructible +

Valid expressions

+ + + + + + + + + +
NameExpressionReturn type
Dereference assignment*x = aunspecified
+

+


+ +

Swappable Iterator

A Swappable +Iterator is an iterator whose dereferenced values can be swapped. +

Note: the requirements for Swappable Iterator are dependent on the issues +surrounding std::swap() being resolved. Here we assume that the issue +will be resolved by allowing the overload of std::swap() for +user-defined types. +

Note: Readable Iterator and Writable Iterator combined implies Swappable +Iterator because of the fully templated std::swap(). However, Swappable +Iterator does not imply Readable Iterator nor Writable Iterator. +

Associated Types

+ + + + + +
Return Categorystd::return_category<X>::typeA type convertible to std::swappable_iterator_tag +
+

Valid expressions

Of the two valid expressions listed below, only one +OR the other is required. If std::iter_swap() is overloaded for +X then std::swap() is not required. If +std::iter_swap() is not overloaded for X then the default +(fully templated) version is used, which will call std::swap() (this +means changing the current requirements for std::iter_swap()). +

+ + + + + + + + + + + + + +
NameExpressionReturn type
Iterator Swapstd::iter_swap(x, y)void
Dereference and Swapstd::swap(*x, *y)void
+

+


+ +

Constant Lvalue Iterator

A +Constant Lvalue Iterator is an iterator that dereferences to produce a const +reference to the pointed-to object, i.e., the associated reference type +is const T&. Changing the value of or destroying an iterator that +models Constant Lvalue Iterator does not invalidate pointers and references +previously obtained from that iterator. +

Refinement of

Readable +Iterator +

Associated Types

+ + + + + + + + + +
Reference typestd::iterator_traits<X>::referenceThe return type of dereferencing the iterator, which must be const + T&.
Return Categorystd::return_category<X>::typeA type convertible to std::constant_lvalue_iterator_tag +
+

+


+ +

Mutable Lvalue Iterator

A +Mutable Lvalue Iterator is an iterator that dereferences to produce a reference +to the pointed-to object. The associated reference type is +T&. Changing the value of or destroying an iterator that models +Mutable Lvalue Iterator does not invalidate pointers and references previously +obtained from that iterator. +

Refinement of

Readable +Iterator, Writable +Iterator, and Swappable +Iterator. +

Associated Types

+ + + + + + + + + +
Reference typestd::iterator_traits<X>::referenceThe return type of dereferencing the iterator, which must be + T&.
Return Categorystd::return_category<X>::typeA type convertible to std::mutable_lvalue_iterator_tag +
+

+


+ +

Forward Traversal Iterator +

The Forward Iterator is an iterator that can be incremented. Also, it is +permissible to make multiple passes through the iterator's range. +

Refinement of

Copy +Constructible, Assignable, Default +Constructible, and Equality +Comparable +

Associated types

+ + + + + + + + + +
Difference Typestd::iterator_traits<X>::difference_typeA signed integral type used for representing distances between + iterators that point into the same range.
Traversal Categorystd::traversal_category<X>::typeA type convertible to std::forward_traversal_tag +
+

Valid expressions

+ + + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Preincrement++i X&
Postincrementi++ convertible to const X&
+

+


+ +

Bidirectional Traversal +Iterator

An iterator that can be incremented and decremented. +

Refinement of

Forward +Traversal Iterator +

Associated types

+ + + + + +
Traversal Categorystd::traversal_category<X>::typeA type convertible to std::bidirectional_traversal_tag +
+

Valid expressions

+ + + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Predecrement--i X&
Postdecrementi-- convertible to const X&
+

+


+ +

Random Access Traversal +Iterator

An iterator that provides constant-time methods for moving forward +and backward in arbitrary-sized steps. +

Refinement of

Bidirectional +Traversal Iterator and Less Than +Comparable where < is a total ordering +

Associated types

+ + + + + +
Traversal Categorystd::traversal_category<X>::typeA type convertible to std::random_access_traversal_tag +
+

Valid expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Iterator additioni += n X&
Iterator additioni + n or n + i X
Iterator subtractioni -= n X&
Iterator subtractioni - n X
Differencei - j std::iterator_traits<X>::difference_type
Element operatori[n]X must also be a model of Readable + Iterator. std::iterator_traits<X>::reference
Element assignmenti[n] = tX must also be a model of Writable + Iterator.unspecified
+

+


+ diff --git a/doc/new-iter-concepts.rst b/doc/new-iter-concepts.rst new file mode 100644 index 0000000..cd29dbe --- /dev/null +++ b/doc/new-iter-concepts.rst @@ -0,0 +1,731 @@ +++++++++++++++++++++++ + New Iterator Concepts +++++++++++++++++++++++ + +:Author: David Abrahams, Jeremy Siek, Thomas Witt +: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: N1477=03-0060 +:copyright: Copyright Dave Abrahams, Jeremy Siek, and Thomas Witt 2003. All rights reserved + +.. _`Boost Consulting`: http://www.boost-consulting.com +.. _`Open Systems Lab`: http://www.osl.iu.edu +.. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de + +:Abstract: We propose a new system of iterator concepts that treat + access and positioning independently. This allows the + concepts to more closely match the requirements + of algorithms and provides better categorizations + of iterators that are used in practice. This proposal + is a revision of paper n1297_. + +.. contents:: Table of Contents + +.. _n1297: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1297.html + +============ + Motivation +============ + +The standard iterator categories and requirements are flawed because +they use a single hierarchy of concepts to address two orthogonal +issues: *iterator traversal* and *value access*. As a result, many +algorithms with requirements expressed in terms of the iterator +categories are too strict. Also, many real-world iterators can not be +accurately categorized. A proxy-based iterator with random-access +traversal, for example, may only legally have a category of "input +iterator", so generic algorithms are unable to take advantage of its +random-access capabilities. The current iterator concept hierarchy is +geared towards iterator traversal (hence the category names), while +requirements that address value access sneak in at various places. The +following table gives a summary of the current value access +requirements in the iterator categories. + ++------------------------+-------------------------------------------------------------------------+ +| Output Iterator | ``*i = a`` | ++------------------------+-------------------------------------------------------------------------+ +| Input Iterator | ``*i`` is convertible to ``T`` | ++------------------------+-------------------------------------------------------------------------+ +| Forward Iterator | ``*i`` is ``T&`` (or ``const T&`` once | +| | `issue 200`_ is resolved) | ++------------------------+-------------------------------------------------------------------------+ +| Random Access Iterator | ``i[n]`` is convertible to ``T`` (also ``i[n] = t`` is required for | +| | mutable iterators once `issue 299`_ is resolved) | ++------------------------+-------------------------------------------------------------------------+ + +.. _issue 200: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#200 +.. _issue 299: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#299 + + +Because iterator traversal and value access are mixed together in a +single hierarchy, many useful iterators can not be appropriately +categorized. For example, ``vector::iterator`` is almost a +random access iterator, but the return type is not ``bool&`` (see +`issue 96`_ and Herb Sutter's paper J16/99-0008 = WG21 +N1185). Therefore, the iterators of ``vector`` only meet the +requirements of input iterator and output iterator. This is so +nonintuitive that at least one implementation erroneously assigns +``random_access_iterator_tag`` as its ``iterator_category``. + +.. _issue 96: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#96 + +Another difficult-to-categorize iterator is the transform iterator, an +adaptor which applies a unary function object to the dereferenced +value of the some underlying iterator (see `transform_iterator`_). +For unary functions such as ``times``, the return type of +``operator*`` clearly needs to be the ``result_type`` of the function +object, which is typically not a reference. Because random access +iterators are required to return lvalues from ``operator*``, if you +wrap ``int*`` with a transform iterator, you do not get a random +access iterator as might be expected, but an input iterator. + +.. _`transform_iterator`: http://www.boost.org/libs/utility/transform_iterator.htm + +A third example is found in the vertex and edge iterators of the +`Boost Graph Library`_. These iterators return vertex and edge +descriptors, which are lightweight handles created on-the-fly. They +must be returned by-value. As a result, their current standard +iterator category is ``input_iterator_tag``, which means that, +strictly speaking, you could not use these iterators with algorithms +like ``min_element()``. As a temporary solution, the concept +`Multi-Pass Input Iterator`_ was introduced to describe the vertex and +edge descriptors, but as the design notes for the concept suggest, a +better solution is needed. + +.. _Boost Graph Library: http://www.boost.org/libs/graph/doc/table_of_contents.html +.. _Multi-Pass Input Iterator: http://www.boost.org/libs/utility/MultiPassInputIterator.html + +In short, there are many useful iterators that do not fit into the +current standard iterator categories. As a result, the following bad +things happen: + +- Iterators are often mis-categorized. + +- Algorithm requirements are more strict than necessary, because they + cannot separate the need for random access or bidirectional + traversal from the need for a true reference return type. + + +======================== + Impact on the Standard +======================== + +The new iterator concepts are backward-compatible with the old +iterator requirements, and old iterators are forward-compatible with +the new iterator concepts. That is to say, iterators that satisfy the +old requirements also satisfy appropriate concepts in the new system, +and iterators modeling the new concepts will automatically satisfy the +appropriate old requirements. + +.. I think we need to say something about the resolution to allow + convertibility to any of the old-style tags as a TR issue (hope it + made it). -DWA + +.. Hmm, not sure I understand. Are you talking about whether a + standards conforming input iterator is allowed to have + a tag that is not input_iterator_tag but that + is convertible to input_iterator_tag? -JGS + +The algorithms in the standard library benefit from the new iterator +concepts because the new concepts provide a more accurate way to +express their type requirements. The result is algorithms that are +usable in more situations and have fewer type requirements. The +following lists the proposed changes to the type requirements of +algorithms. + +Forward Iterator -> Forward Traversal Iterator and Readable Iterator + ``find_end, adjacent_find, search, search_n, rotate_copy, lower_bound, upper_bound, equal_range, binary_search, min_element, max_element`` + +Forward Iterator (1) -> Single Pass Iterator and Readable Iterator +Forward Iterator (2) -> Forward Traversal Iterator and Readable Iterator + ``find_first_of`` + +Forward Iterator -> Readable Iterator and Writable Iterator + ``iter_swap`` + +Forward Iterator -> Single Pass Iterator and Writable Iterator + ``fill, generate`` + +Forward Iterator -> Forward Traversal Iterator and Swappable Iterator + ``rotate`` + +Forward Iterator (1) -> Swappable Iterator and Single Pass Iterator +Forward Iterator (2) -> Swappable Iterator and Incrementable Iterator + ``swap_ranges`` + +Forward Iterator -> Forward Traversal Iterator and Readable Iterator and Writable Iterator + ``remove, remove_if, unique`` + +Forward Iterator -> Single Pass Iterator and Readable Iterator and Writable Iterator + ``replace, replace_if`` + +Bidirectional Iterator -> Bidirectional Traversal Iterator and Swappable Iterator + ``reverse`` + +Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable and Swappable Iterator + ``partition`` + +Bidirectional Iterator (1) -> Bidirectional Traversal Iterator and Readable Iterator, +Bidirectional Iterator (2) -> Bidirectional Traversal Iterator and Writable Iterator + ``copy_backwards`` + +Bidirectional Iterator -> Bidirectional Traversal Iterator and Swappable Iterator and Readable Iterator + ``next_permutation, prev_permutation`` + +Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable Iterator and Writable Iterator + ``stable_partition, inplace_merge`` + +Bidirectional Iterator -> Bidirectional Traversal Iterator and Readable Iterator + ``reverse_copy`` + +Random Access Iterator -> Random Access Traversal Iterator and Readable and Swappable Iterator + ``random_shuffle, sort, stable_sort, partial_sort, nth_element, push_heap, pop_heap + make_heap, sort_heap`` + +Input Iterator (2) -> Incrementable Iterator and Readable Iterator + ``equal`` + +Input Iterator (2) -> Incrementable Iterator and Readable Iterator + ``transform`` + +======== + Design +======== + +The iterator requirements are be separated into two hierarchies. One +set of concepts handles the syntax and semantics of value access: + +- Readable Iterator +- Writable Iterator +- Swappable Iterator +- Readable Lvalue Iterator +- Writable Lvalue Iterator + +The refinement relationships among these iterator concepts are given +in the following diagram. + +.. image:: access.png + +The access concepts describe requirements related to ``operator*`` and +``operator->``, including the ``value_type``, ``reference``, and +``pointer`` associated types. + +The other set of concepts handles traversal: + +- Incrementable Iterator +- Single Pass Iterator +- Forward Traversal Iterator +- Bidirectional Traversal Iterator +- Random Access Traversal Iterator + +The refinement relationships for the traversal concepts are in the +following diagram. + +.. image:: traversal.png + +In addition to the iterator movement operators, such as +``operator++``, the traversal concepts also include requirements on +position comparison such as ``operator==`` and ``operator<``. The +reason for the fine grain slicing of the concepts into the +Incrementable and Single Pass is to provide concepts that are exact +matches with the original input and output iterator requirements. + +The relationship between the new iterator concepts and the old are +given in the following diagram. + +.. image:: oldeqnew.png + +Like the old iterator requirements, we provide tags for purposes of +dispatching. There are two hierarchies of tags, one for the access +concepts and one for the traversal concepts. We provide an access +mechanism for mapping iterator types to these new tags. Our design +reuses ``iterator_traits::iterator_category`` as the access +mechanism. To enable this, a pair of access and traversal tags are +combined into a single type using the following `iterator_tag` class. + +:: + + template + struct iterator_tag : /* appropriate old category or categories */ + { + typedef AccessTag access; + typedef TraversalTag traversal; + }; + +The ``iterator_tag`` class template is derived from the appropriate +iterator tag or tags from the old requirements based on the new-style +tags passed as template parameters. The algorithm for determining the +old tag or tags from the new tags picks the least-refined old concepts +that include all of the requirements of the access and traversal +concepts (that is, the closest fit), if any such category exists. For +example, a the category tag for a Readable Single Pass Iterator will +always be derived from ``input_iterator_tag``, while the category tag +for a Single Pass Iterator that is both Readable and Writable will be +derived from both ``input_iterator_tag`` and ``output_iterator_tag``. + +We also provide two helper classes that make it convenient to obtain +the access and traversal tags of an iterator. These helper classes +work both for iterators whose ``iterator_category`` is +``iterator_tag`` and also for iterators using the original iterator +categories. + +:: + + template struct access_category { typedef ... type; }; + template struct traversal_category { typedef ... type; }; + + +The most difficult design decision concerned the ``operator[]``. The +direct approach for specifying ``operator[]`` would have a return type +of ``reference``; the same as ``operator*``. However, going in this +direction would mean that an iterator satisfying the old Random Access +Iterator requirements would not necessarily be a model of Readable or +Writable Lvalue Iterator. Instead we have chosen a design that +matches the preferred resolution of `issue 299`_: ``operator[]`` is +only required to return something convertible to the ``value_type`` +(for a Readable Iterator), and is required to support assignment +``i[n] = t`` (for a Writable Iterator). + + +=============== + Proposed Text +=============== + +Addition to [lib.iterator.requirements] +======================================= + +Iterator Value Access Concepts [lib.iterator.value.access] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In the tables below, ``X`` is an iterator type, ``a`` is a constant +object of type ``X``, ``T`` is +``std::iterator_traits::value_type``, and ``v`` is a constant +object of type ``T``. + +.. _Readable Iterator: + +Readable Iterators [lib.readable.iterators] +------------------------------------------- + +A class or built-in type ``X`` models the *Readable Iterator* concept +for the value type ``T`` if the following expressions are valid and +respect the stated semantics. ``U`` is the type of any specified +member of type ``T``. + + +------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Readable Iterator Requirements (in addition to CopyConstructible) | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition | + +======================================+===================================================+=================================================================+ + | ``iterator_traits::value_type`` | ``T`` | Any non-reference, non-cv-qualified type | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + | ``iterator_traits::reference`` | Convertible to ``iterator_traits::value_type`` | | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + | ``access_category::type`` | Convertible to ``readable_iterator_tag`` | | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + | ``*a`` | ``iterator_traits::reference`` | pre: ``a`` is dereferenceable. If ``a == b`` then | + | | | ``*a`` is equivalent to ``*b`` | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + | ``a->m`` | ``U&`` | pre: ``(*a).m`` is well-defined. Equivalent to ``(*a).m`` | + +--------------------------------------+---------------------------------------------------+-----------------------------------------------------------------+ + + +.. _Writable Iterator: + +Writable Iterators [lib.writable.iterators] +------------------------------------------- + +A class or built-in type ``X`` models the *Writable Iterator* concept +if the following expressions are valid and respect the stated +semantics. + +.. A type ``T`` belongs to the *set of value types* of ``X`` + if, for an object ``v`` of type ``T``, ``*a = v`` is valid. + + ** This appears to be a mutual recursion which ends up meaning + nothing. Kill the assertion column? + + Separate but related question: Is a writable iterator required + to have a meaningful value_type? If not, we need to use a + different name from ``v`` in this table -DWA + ++------------------------------------------------------------------------------------------------------------------------------+ +| Writable Iterator Requirements (in addition to CopyConstructible) | ++--------------------------------------+------------------------------------------+--------------------------------------------+ +| Expression | Return Type | Assertion/Note/Precondition/Postcondition | ++======================================+==========================================+============================================+ +| ``access_category::type`` | Convertible to ``writable_iterator_tag`` | | ++--------------------------------------+------------------------------------------+--------------------------------------------+ +| ``*a = v`` | | .. ** pre: The type of ``v`` is in the set | +| | | of value types of ``X`` | ++--------------------------------------+------------------------------------------+--------------------------------------------+ + + +Swappable Iterators [lib.swappable.iterators] +--------------------------------------------- + +A class or built-in type ``X`` models the *Swappable Iterator* concept +if the following expressions are valid and respect the stated +semantics. + + +------------------------------------------------------------------------------------------------+ + | Swappable Iterator Requirements (in addition to CopyConstructible) | + +------------------------------------+-------------+---------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition | + +====================================+=============+=============================================+ + | ``iter_swap(a, b)`` | ``void`` | post: the pointed to values are exchanged | + +------------------------------------+-------------+---------------------------------------------+ + +[*Note:* An iterator that is a model of the *Readable* and *Writable Iterator* concepts + is also a model of *Swappable Iterator*. *--end note*] + + +Readable Lvalue Iterators [lib.readable.lvalue.iterators] +--------------------------------------------------------- + +The *Readable Lvalue Iterator* concept adds the requirement that the +``reference`` type be a reference to the value type of the iterator. + + +--------------------------------------------------------------------------------------------------------------------------------------------------+ + | Readable Lvalue Iterator Requirements (in addition to Readable Iterator) | + +------------------------------------+-------------------------------------------------+-----------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition | + +====================================+=================================================+===========================================================+ + | ``iterator_traits::reference`` | ``T&`` | ``T`` is *cv* ``iterator_traits::value_type`` where | + | | | *cv* is an optional cv-qualification | + +------------------------------------+-------------------------------------------------+-----------------------------------------------------------+ + | ``access_category::type`` | Convertible to ``readable_lvalue_iterator_tag`` | | + +------------------------------------+-------------------------------------------------+-----------------------------------------------------------+ + + +Writable Lvalue Iterators [lib.writable.lvalue.iterators] +--------------------------------------------------------- + +The *Writable Lvalue Iterator* concept adds the requirement that the +``reference`` type be a non-const reference to the value type of the +iterator. + + +------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Writable Lvalue Iterator Requirements (in addition to Readable Lvalue Iterator) | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition | + +======================================+==================================================+============================================================+ + | ``iterator_traits::reference`` | ``iterator_traits::value_type&`` | | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + | ``access_category::type`` | Convertible to ``writable_lvalue_iterator_tag`` | | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + + +Iterator Traversal Concepts [lib.iterator.traversal] +++++++++++++++++++++++++++++++++++++++++++++++++++++ + +In the tables below, ``X`` is an iterator type, ``a`` and ``b`` are +constant objects of type ``X``, ``r`` and ``s`` are mutable objects of +type ``X``, ``T`` is ``std::iterator_traits::value_type``, and +``v`` is a constant object of type ``T``. + + +Incrementable Iterators [lib.incrementable.iterators] +----------------------------------------------------- + +A class or built-in type ``X`` models the *Incrementable Iterator* +concept if the following expressions are valid and respect the stated +semantics. + + + +------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Incrementable Iterator Requirements (in addition to Assignable, Copy Constructible) | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition | + +======================================+==================================================+============================================================+ + | ``++r`` | ``X&`` | ``&r == &++r`` | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + | ``r++`` | convertible to ``const X&`` | ``{ X tmp = r; ++r; return tmp; }`` | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + | ``traversal_category::type`` | | Convertible to ``incrementable_iterator_tag`` | + +--------------------------------------+--------------------------------------------------+------------------------------------------------------------+ + + +Single Pass Iterators [lib.single.pass.iterators] +------------------------------------------------- + +A class or built-in type ``X`` models the *Single Pass Iterator* +concept if the following expressions are valid and respect the stated +semantics. + + +------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality Comparable) | + +----------------------------------+-------------------------+-----------------------------------------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition/Semantics | + +==================================+=========================+=========================================================================================+ + | ``++r`` | ``X&`` | pre: ``r`` is dereferenceable; post: ``r`` is dereferenceable or ``r`` is past-the-end | + +----------------------------------+-------------------------+-----------------------------------------------------------------------------------------+ + | ``a == b`` | convertible to ``bool`` | ``==`` is an equivalence relation over its domain | + +----------------------------------+-------------------------+-----------------------------------------------------------------------------------------+ + | ``a != b`` | convertible to ``bool`` | ``!(a == b)`` | + +----------------------------------+-------------------------+-----------------------------------------------------------------------------------------+ + | ``traversal_category::type`` | | Convertible to ``single_pass_iterator_tag`` | + +----------------------------------+-------------------------+-----------------------------------------------------------------------------------------+ + + +Forward Traversal Iterators [lib.forward.traversal.iterators] +------------------------------------------------------------- + +A class or built-in type ``X`` models the *Forward Traversal Iterator* +concept if the following expressions are valid and respect the stated +semantics. + + +----------------------------------------------------------------------------------------------------------------------------------+ + | Forward Traversal Iterator Requirements (in addition to Single Pass Iterator) | + +------------------------------------------+--------------+------------------------------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition/Semantics | + +==========================================+==============+========================================================================+ + | ``X u;`` | ``X&`` | ``note: u may have a singular value.`` | + +------------------------------------------+--------------+------------------------------------------------------------------------+ + | ``++r`` | ``X&`` | ``r == s`` and ``r`` is dereferenceable implies ``++r == ++s.`` | + +------------------------------------------+--------------+------------------------------------------------------------------------+ + | ``iterator_traits::difference_type`` | | A signed integral type representing the distance between iterators | + +------------------------------------------+--------------+------------------------------------------------------------------------+ + | ``traversal_category::type`` | | Convertible to ``forward_traversal_iterator_tag`` | + +------------------------------------------+--------------+------------------------------------------------------------------------+ + + +Bidirectional Traversal Iterators [lib.bidirectional.traversal.iterators] +------------------------------------------------------------------------- + +A class or built-in type ``X`` models the *Bidirectional Traversal +Iterator* concept if the following expressions are valid and respect +the stated semantics. + + +-------------------------------------------------------------------------------------------------------------+ + |Bidirectional Traversal Iterator Requirements (in addition to Forward Traversal Iterator) | + +-----------------------------------------+-------------+-----------------------------------------------------+ + | Expression | Return Type | Assertion/Note/Precondition/Postcondition/Semantics | + +=========================================+=============+=====================================================+ + | ``--r`` | ``X&`` |pre: there exists ``s`` such that ``r == ++s``. | + | | |post: ``s`` is dereferenceable. ``--(++r) == r``. | + | | |``--r == --s`` implies ``r == s``. ``&r == &--r``. | + +-----------------------------------------+-------------+-----------------------------------------------------+ + |``r--`` |convertible |``{ X tmp = r; --r; return tmp; }`` | + | |to ``const | | + | |X&`` | | + +-----------------------------------------+-------------+-----------------------------------------------------+ + | ``traversal_category::type`` | | Convertible to | + | | | ``bidirectional_traversal_iterator_tag`` | + | | | | + +-----------------------------------------+-------------+-----------------------------------------------------+ + + +Random Access Traversal Iterators [lib.random.access.traversal.iterators] +------------------------------------------------------------------------- + +A class or built-in type ``X`` models the *Random Access Traversal +Iterator* concept if the following expressions are valid and respect +the stated semantics. In the table below, ``Distance`` is +``iterator_traits::difference_type`` and ``n`` represents a +constant object of type ``Distance``. + + +--------------------------------------------------------------------------------------------------------------------------------------------+ + | Random Access Traversal Iterator Requirements (in addition to Bidirectional Traversal Iterator) | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + | Expression | Return Type | Operational Semantics | Assertion/Note/Pre/Post-condition | + +================================+=======================================+==========================+========================================+ + |``r += n`` | ``X&`` |:: | | + | | | | | + | | | { | | + | | | Distance m = n; | | + | | | if (m >= 0) | | + | | | while (m--) | | + | | | ++r; | | + | | | else | | + | | | while (m++) | | + | | | --r; | | + | | | return r; | | + | | | } | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + | ``a + n``, ``n + a`` | ``X`` |``{ X tmp = a; return tmp | | + | | |+= n; }`` | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``r -= n`` | ``X&`` |``return r += -n`` | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a - n`` | ``X`` |``{ X tmp = a; return tmp | | + | | |-= n; }`` | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``b - a`` |``Distance`` |``a < b ? distance(a,b) : |pre: there exists a value ``n`` of | + | | |-distance(b,a)`` |``Distance`` such that ``a + n == b``. | + | | | |``b == a + (b - a)``. | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a[n]`` |convertible to T |``*(a + n)`` |pre: a is a `readable iterator`_ | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a[n] = v`` |convertible to T |``*(a + n) = v`` |pre: a is a `writable iterator`_ | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a < b`` |convertible to ``bool`` |``b - a > 0`` |``<`` is a total ordering relation | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a > b`` |convertible to ``bool`` |``b < a`` |``>`` is a total ordering relation | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a >= b`` |convertible to ``bool`` |``!(a < b)`` | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``a <= b`` |convertible to ``bool`` |``!(a > b)`` | | + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + |``traversal_category::type`` | | |Convertible to | + | | | |``random_access_traversal_iterator_tag``| + +--------------------------------+---------------------------------------+--------------------------+----------------------------------------+ + + + +Addition to [lib.iterator.synopsis] +=================================== + +:: + + // lib.iterator.traits, traits and tags + template struct access_category; + template struct traversal_category; + + template + struct iterator_tag : /* appropriate old category or categories */ { + typedef AccessTag access; + typedef TraversalTag traversal; + }; + + struct readable_iterator_tag { }; + struct writable_iterator_tag { }; + struct swappable_iterator_tag { }; + struct readable_writable_iterator_tag + : virtual readable_iterator_tag + , virtual writable_iterator_tag + , virtual swappable_iterator_tag { }; + struct readable_lvalue_iterator_tag { }; + struct writable_lvalue_iterator_tag + : virtual public readable_writable_iterator_tag + , virtual public readable_lvalue_iterator_tag { }; + + struct incrementable_iterator_tag { }; + struct single_pass_iterator_tag : incrementable_iterator_tag { }; + struct forward_traversal_tag : single_pass_iterator_tag { }; + struct bidirectional_traversal_tag : forward_traversal_tag { }; + struct random_access_traversal_tag : bidirectional_traversal_tag { }; + + struct null_category_tag { }; + struct input_output_iterator_tag : input_iterator_tag, output_iterator_tag {}; + +Addition to [lib.iterator.traits] +================================= + +The ``iterator_tag`` class template is an iterator category tag that +encodes the access and traversal tags in addition to being compatible +with the original iterator tags. The ``iterator_tag`` class inherits +from one of the original iterator tags according to the following +pseudo-code. + +:: + + inherit-category(access-tag, traversal-tag) = + if (access-tag is convertible to readable_lvalue_iterator_tag) { + if (traversal-tag is convertible to random_access_traversal_tag) + return random_access_iterator_tag; + else if (traversal-tag is convertible to bidirectional_traversal_tag) + return bidirectional_iterator_tag; + else if (traversal-tag is convertible to forward_traversal_tag) + return forward_iterator_tag; + else if (traversal-tag is convertible to single_pass_traversal_tag) + if (access-tag is convertible to writable_iterator_tag) + return input_output_iterator_tag; + else + return input_iterator_tag; + else if (access-tag is convertible to writable_iterator_tag) + return output_iterator_tag; + else + return null_category_tag; + } else if (access-tag is convertible to readable_writable_iterator_tag + and traversal-tag is convertible to single_pass_iterator_tag) + return input_output_iterator_tag; + else if (access-tag is convertible to readable_iterator_tag + and traversal-tag is convertible to single_pass_iterator_tag) + return input_iterator_tag; + else if (access-tag is convertible to writable_iterator_tag + and traversal-tag is convertible to incrementable_iterator_tag) + return output_iterator_tag; + else + return null_category_tag; + + +The ``access_category`` and ``traversal_category`` class templates are +traits classes. For iterators whose +``iterator_traits::iterator_category`` type is ``iterator_tag``, +the ``access_category`` and ``traversal_category`` traits access the +``access`` and ``traversal`` member types within ``iterator_tag``. +For iterators whose ``iterator_traits::iterator_category`` type +is not ``iterator_tag`` and instead is a tag convertible to one of the +original tags, the appropriate traversal and access tags is deduced. +The following pseudo-code describes the algorithm. + +:: + + access-category(Iterator) = + cat = iterator_traits::iterator_category; + if (cat == iterator_tag) + return Access; + else if (cat is convertible to forward_iterator_tag) { + if (iterator_traits::reference is a const reference) + return readable_lvalue_iterator_tag; + else + return writable_lvalue_iterator_tag; + } else if (cat is convertible to input_iterator_tag) + return readable_iterator_tag; + else if (cat is convertible to output_iterator_tag) + return writable_iterator_tag; + else + return null_category_tag; + + traversal-category(Iterator) = + cat = iterator_traits::iterator_category; + if (cat == iterator_tag) + return Traversal; + else if (cat is convertible to random_access_iterator_tag) + return random_access_traversal_tag; + else if (cat is convertible to bidirectional_iterator_tag) + return bidirectional_traversal_tag; + else if (cat is convertible to forward_iterator_tag) + return forward_traversal_tag; + else if (cat is convertible to input_iterator_tag) + return single_pass_iterator_tag; + else if (cat is convertible to output_iterator_tag) + return incrementable_iterator_tag; + else + return null_category_tag; + + +The following specializations provide the access and traversal +category tags for pointer types. + +:: + + template + struct access_category + { + typedef readable_lvalue_iterator_tag type; + }; + template + struct access_category + { + typedef writable_lvalue_iterator_tag type; + }; + + template + struct traversal_category + { + typedef random_access_traversal_tag type; + }; + + + +.. + LocalWords: Abrahams Siek Witt const bool Sutter's WG int UL LI href Lvalue + LocalWords: ReadableIterator WritableIterator SwappableIterator cv pre iter + LocalWords: ConstantLvalueIterator MutableLvalueIterator CopyConstructible TR + LocalWords: ForwardTraversalIterator BidirectionalTraversalIterator lvalue + LocalWords: RandomAccessTraversalIterator dereferenceable Incrementable tmp + LocalWords: incrementable xxx min prev inplace png oldeqnew AccessTag struct + LocalWords: TraversalTag typename lvalues DWA Hmm JGS diff --git a/doc/oldeqnew.png b/doc/oldeqnew.png new file mode 100644 index 0000000..30cd159 Binary files /dev/null and b/doc/oldeqnew.png differ diff --git a/doc/traversal.png b/doc/traversal.png new file mode 100644 index 0000000..a9bbe98 Binary files /dev/null and b/doc/traversal.png differ diff --git a/example/Jamfile b/example/Jamfile new file mode 100644 index 0000000..921ff30 --- /dev/null +++ b/example/Jamfile @@ -0,0 +1 @@ +unit-test ia1 : reverse_iterator.cpp : ../../.. $(BOOST) ; \ No newline at end of file diff --git a/example/reverse_iterator.cpp b/example/reverse_iterator.cpp new file mode 100644 index 0000000..ffe6e3d --- /dev/null +++ b/example/reverse_iterator.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include + +int main() +{ + int x[] = { 1, 2, 3, 4 }; + boost::reverse_iterator + , std::ptrdiff_t> first(x + 4), last(x); + std::copy(first, last, std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + return 0; +} diff --git a/include/boost/iterator/detail/categories.hpp b/include/boost/iterator/detail/categories.hpp new file mode 100644 index 0000000..48d1e3d --- /dev/null +++ b/include/boost/iterator/detail/categories.hpp @@ -0,0 +1,338 @@ +// (C) Copyright Thomas Witt 2002. Permission to copy, use, modify, +// sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#ifndef BOOST_ITERATOR_DETAIL_CATEGORIES_HPP +# define BOOST_ITERATOR_DETAIL_CATEGORIES_HPP + +# include +# include + +# include + +# include +# include + +# include +# include +# include +# include +# include +# include + +# include + +namespace boost +{ + + // faked new old-style categories needed to make new->old mapping + // work + namespace detail + { + struct null_category_tag {}; + struct input_output_iterator_tag : std::input_iterator_tag, std::output_iterator_tag {}; + } + + // + // Access Categories + // + struct readable_iterator_tag + { + typedef std::input_iterator_tag max_category; + }; + + struct writable_iterator_tag + { + typedef std::output_iterator_tag max_category; + }; + + struct swappable_iterator_tag + { + typedef detail::null_category_tag max_category; + }; + + struct readable_writable_iterator_tag + : virtual readable_iterator_tag + , virtual writable_iterator_tag + , virtual swappable_iterator_tag + { + typedef detail::input_output_iterator_tag max_category; + }; + + struct readable_lvalue_iterator_tag + : virtual readable_iterator_tag + { + typedef std::random_access_iterator_tag max_category; + }; + + struct writable_lvalue_iterator_tag + : virtual public readable_writable_iterator_tag + , virtual public readable_lvalue_iterator_tag + { + typedef std::random_access_iterator_tag max_category; + }; + + // + // Traversal Categories + // + struct incrementable_traversal_tag + { + typedef std::output_iterator_tag max_category; + }; + + struct single_pass_traversal_tag + : incrementable_traversal_tag + { + typedef detail::input_output_iterator_tag max_category; + }; + + struct forward_traversal_tag + : single_pass_traversal_tag + { + typedef std::forward_iterator_tag max_category; + }; + + struct bidirectional_traversal_tag + : forward_traversal_tag + { + typedef std::bidirectional_iterator_tag max_category; + }; + + struct random_access_traversal_tag + : bidirectional_traversal_tag + { + typedef std::random_access_iterator_tag max_category; + }; + + struct error_iterator_tag { }; + + namespace detail + { + // + // Tag detection meta functions + // + + // I bet this is defined somewhere else. Let's wait and see. + struct error_type; + +# ifndef BOOST_NO_IS_CONVERTIBLE + + // True iff T is a tag "derived" from Tag + template + struct is_tag + : mpl::or_< + is_convertible + + // Because we can't actually get forward_iterator_tag to + // derive from input_output_iterator_tag, we need this + // case. + , mpl::and_< + is_convertible + , is_convertible + > + > + {}; + + +# else + template + struct is_tag; +# endif + + // Generate specializations which will allow us to find + // null_category_tag as a minimum old-style category for new-style + // iterators which don't have an actual old-style category. We + // need that so there is a valid base class for all new-style + // iterators. +# define BOOST_OLD_ITERATOR_CATEGORY(category) \ + template <> \ + struct is_tag \ + : mpl::true_ {}; + + BOOST_OLD_ITERATOR_CATEGORY(input_iterator_tag) + BOOST_OLD_ITERATOR_CATEGORY(output_iterator_tag) + BOOST_OLD_ITERATOR_CATEGORY(forward_iterator_tag) + BOOST_OLD_ITERATOR_CATEGORY(bidirectional_iterator_tag) + BOOST_OLD_ITERATOR_CATEGORY(random_access_iterator_tag) +# undef BOOST_OLD_ITERATOR_CATEGORY + + template <> + struct is_tag + : mpl::true_ + { + }; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + struct is_tag : mpl::true_ + {}; + +# ifdef BOOST_NO_IS_CONVERTIBLE + // Workarounds for CWPro7 which can't detect derivation at + // compile-time. + + // Fact of life: we can only detect tag refinement relationships + // among predefined tags. + // + // Algorithm: + // is_tag(T,U) -> + // T == U + // || (exists d in derived_from(T) such that is_tag(d, U)) + // + // T == U case is handled above + + // false by default + template + struct is_tag_impl : mpl::false_ + {}; + + // The generalized template dispatches to is_tag_impl because + // is_tag and is_tag are equally specialized. + // This technique simulates making is_tag more-specialized. + template + struct is_tag + : is_tag_impl + {}; + +# define BOOST_ITERATOR_DERIVED_TAG1(base, derived) \ + BOOST_ITERATOR_DERIVED_TAG1_AUX(base, _, derived) + +# define BOOST_ITERATOR_DERIVED_TAG1_AUX(base, underscore, derived) \ + template \ + struct is_tag_impl \ + : is_tag \ + { \ + }; + + // Old-style tag relations + template + struct is_tag_impl + : mpl::or_< + is_tag + , is_tag + > + { + }; + + BOOST_ITERATOR_DERIVED_TAG1(std::output_iterator, detail::input_output_iterator) + BOOST_ITERATOR_DERIVED_TAG1(std::input_iterator, detail::input_output_iterator) + BOOST_ITERATOR_DERIVED_TAG1(detail::input_output_iterator, std::forward_iterator) + BOOST_ITERATOR_DERIVED_TAG1(std::forward_iterator, std::bidirectional_iterator) + BOOST_ITERATOR_DERIVED_TAG1(std::bidirectional_iterator, std::random_access_iterator) + + // Access tag relations + BOOST_ITERATOR_DERIVED_TAG1(readable_lvalue_iterator, writable_lvalue_iterator) + BOOST_ITERATOR_DERIVED_TAG1(swappable_iterator, readable_writable_iterator) + BOOST_ITERATOR_DERIVED_TAG1(readable_writable_iterator, writable_lvalue_iterator) + + template + struct is_tag_impl + : mpl::or_< + is_tag + , is_tag + > + { + }; + + BOOST_ITERATOR_DERIVED_TAG1(writable_iterator, readable_writable_iterator) + + // Traversal tag relations + BOOST_ITERATOR_DERIVED_TAG1(bidirectional_traversal, random_access_traversal) + BOOST_ITERATOR_DERIVED_TAG1(forward_traversal, bidirectional_traversal) + BOOST_ITERATOR_DERIVED_TAG1(single_pass_traversal, forward_traversal) + BOOST_ITERATOR_DERIVED_TAG1(incrementable_traversal, single_pass_traversal) + +# endif // BOOST_NO_IS_CONVERTIBLE workarounds + +# endif // ndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + template + struct known_tag + : mpl::apply_if, mpl::identity, Else> + {}; + + template + struct max_known_traversal_tag + : known_tag< + Tag, random_access_traversal_tag + , known_tag< + Tag, bidirectional_traversal_tag + , known_tag< + Tag, forward_traversal_tag + , known_tag< + Tag, single_pass_traversal_tag + , known_tag< + Tag, incrementable_traversal_tag + , error_iterator_tag + > + > + > + > + > + {}; + + // Doesn't cope with these odd combinations: readable+swappable, + // writable+swappable. That doesn't matter for the sake of + // new-style tag base computation, which is all it's used for + // anyway. + template + struct max_known_access_tag + : known_tag< + Tag, writable_lvalue_iterator_tag + , known_tag< + Tag, readable_lvalue_iterator_tag + , known_tag< + Tag, readable_writable_iterator_tag + , known_tag< + Tag, writable_iterator_tag + , known_tag< + Tag, readable_iterator_tag + , mpl::apply_if< + is_tag + , mpl::identity + , error_iterator_tag + > + > + > + > + > + > + {}; + + // + // Returns the minimum category type or error_type + // if T1 and T2 are unrelated. + // + // For compilers not supporting is_convertible this only + // works with the new boost return and traversal category + // types. The exact boost _types_ are required. No derived types + // will work. + // + // + template + struct minimum_category + : mpl::apply_if< + is_tag + , mpl::identity + , mpl::if_< + is_tag + , T2 + , error_type + > + > + {}; + +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) + // Deal with ETI + template <> struct minimum_category { typedef minimum_category type; }; +# endif + + } // namespace detail + +} // namespace boost + +#include + +#endif // BOOST_ITERATOR_DETAIL_CATEGORIES_HPP diff --git a/include/boost/iterator/detail/config_def.hpp b/include/boost/iterator/detail/config_def.hpp new file mode 100644 index 0000000..6789d4a --- /dev/null +++ b/include/boost/iterator/detail/config_def.hpp @@ -0,0 +1,104 @@ +// (C) Copyright David Abrahams 2002. +// (C) Copyright Jeremy Siek 2002. +// (C) Copyright Thomas Witt 2002. +// Permission to copy, use, modify, +// sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +// no include guard multiple inclusion intended + +// +// This is a temporary workaround until the bulk of this is +// available in boost config. +// 23/02/03 thw +// + +#include // for prior +#include + +#define BOOST_ITERATOR_CONFIG_DEF // if you get an error here, you have nested config_def #inclusion. + +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) \ + || BOOST_WORKAROUND(__GNUC__, <= 2 && __GNUC_MINOR__ <= 95) \ + || BOOST_WORKAROUND(__MWERKS__, <= 0x3000) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +# define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented" + +# if 0 // test code + template + struct bar + { + typedef int type; + }; + + template <> + struct bar + { + }; + + + template + struct foo : bar<(sizeof(T) == 1)> + { + }; + + template + char* f(int, typename foo::type = 0) { return 0; } + + template + int f(...) { return 0; } + + char* x = f(0); + int y = f(0); + + int main() + { + return 0; + } +# endif + +#endif + +#if BOOST_WORKAROUND(__MWERKS__, <=0x2407) +# define BOOST_NO_IS_CONVERTIBLE // "is_convertible doesn't work for simple types" +#endif + +#if BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(3)) || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +# define BOOST_NO_IS_CONVERTIBLE_TEMPLATE // The following program fails to compile: + +# if 0 // test code + template + struct foo + { + foo(T); + + template + foo(foo const& other) : p(other.p) { } + + T p; + }; + + bool x = boost::is_convertible, foo >::value; +# endif + +#endif + +#if BOOST_WORKAROUND(__GNUC__, == 2 && __GNUC_MINOR__ == 95) \ + || BOOST_WORKAROUND(__MWERKS__, <= 0x2407) \ + || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) +# define BOOST_ITERATOR_NO_MPL_AUX_HAS_XXX // "MPL's has_xxx facility doesn't work" +#endif + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_IS_CONVERTIBLE) || defined(BOOST_NO_IS_CONVERTIBLE_TEMPLATE) +# define BOOST_NO_STRICT_ITERATOR_INTEROPERABILITY +#endif + +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) +# define BOOST_ARG_DEPENDENT_TYPENAME typename +# else +# define BOOST_ARG_DEPENDENT_TYPENAME +# endif + +// no include guard multiple inclusion intended diff --git a/include/boost/iterator/detail/config_undef.hpp b/include/boost/iterator/detail/config_undef.hpp new file mode 100644 index 0000000..f58df62 --- /dev/null +++ b/include/boost/iterator/detail/config_undef.hpp @@ -0,0 +1,26 @@ +// (C) Copyright Thomas Witt 2002. +// Permission to copy, use, modify, +// sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +// no include guard multiple inclusion intended + +// +// This is a temporary workaround until the bulk of this is +// available in boost config. +// 23/02/03 thw +// + +#undef BOOST_NO_SFINAE +#undef BOOST_NO_IS_CONVERTIBLE +#undef BOOST_NO_IS_CONVERTIBLE_TEMPLATE +#undef BOOST_NO_STRICT_ITERATOR_INTEROPERABILITY +#undef BOOST_ARG_DEPENDENT_TYPENAME + +#ifdef BOOST_ITERATOR_CONFIG_DEF +# undef BOOST_ITERATOR_CONFIG_DEF +#else +# error missing or nested #include config_def +#endif diff --git a/include/boost/iterator/detail/enable_if.hpp b/include/boost/iterator/detail/enable_if.hpp new file mode 100644 index 0000000..d939fbb --- /dev/null +++ b/include/boost/iterator/detail/enable_if.hpp @@ -0,0 +1,88 @@ +// (C) Copyright David Abrahams 2002. +// (C) Copyright Jeremy Siek 2002. +// (C) Copyright Thomas Witt 2002. +// Permission to copy, use, modify, +// sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef BOOST_ENABLE_IF_23022003THW_HPP +#define BOOST_ENABLE_IF_23022003THW_HPP + +#include +#include + +#include + +// +// Boost iterators uses its own enable_if cause we need +// special semantics for deficient compilers. +// 23/02/03 thw +// + +namespace boost +{ + + namespace detail + { + // + // Base machinery for all kinds of enable if + // + template + struct enabled + { + template + struct base + { + typedef T type; + }; + }; + + // + // For compilers that don't support "Substitution Failure Is Not An Error" + // enable_if falls back to always enabled. See comments + // on operator implementation for consequences. + // + template<> + struct enabled + { + template + struct base + { +#ifdef BOOST_NO_SFINAE + + typedef T type; + + // This way to do it would give a nice error message containing + // invalid overload, but has the big disadvantage that + // there is no reference to user code in the error message. + // + // struct invalid_overload; + // typedef invalid_overload type; + // +#endif + }; + }; + + + template + struct enable_if +# if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) + : enabled<(Cond::value)>::template base +# else + : mpl::identity +# endif + { +# if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) + typedef Return type; +# endif + }; + + } // namespace detail + +} // namespace boost + +#include + +#endif // BOOST_ENABLE_IF_23022003THW_HPP