diff --git a/doc/counting_iterator.html b/doc/counting_iterator.html index 75add53..ed9fabb 100644 --- a/doc/counting_iterator.html +++ b/doc/counting_iterator.html @@ -3,7 +3,7 @@ - + Counting Iterator @@ -36,12 +36,21 @@ Railway Operation and Construction -abstract: +abstract:How would you fill up a vector with the numbers zero +through one hundred using std::copy()? The only iterator +operation missing from builtin integer types is an +operator*() that returns the current value of the integer. +The counting iterator adaptor adds this crucial piece of +functionality to whatever type it wraps. One can use the +counting iterator adaptor not only with integer types, but with +any type that is Incrementable (see type requirements +below). -

counting_iterator adapts an arithmetic type, such as int, by -adding an operator* that returns the current value of the object.

+

counting_iterator adapts an incrementable type such as int +or std::list<std::string>::iterator, by adding an operator* +that returns the current value of the object.

Table of Contents

- + diff --git a/doc/counting_iterator.rst b/doc/counting_iterator.rst index 47db740..bcb3a64 100644 --- a/doc/counting_iterator.rst +++ b/doc/counting_iterator.rst @@ -14,7 +14,15 @@ .. _`Open Systems Lab`: http://www.osl.iu.edu .. _`Institute for Transport Railway Operation and Construction`: http://www.ive.uni-hannover.de -:abstract: +:abstract: How would you fill up a vector with the numbers zero + through one hundred using ``std::copy()``? The only iterator + operation missing from builtin integer types is an + ``operator*()`` that returns the current value of the integer. + The counting iterator adaptor adds this crucial piece of + functionality to whatever type it wraps. One can use the + counting iterator adaptor not only with integer types, but with + any type that is **Incrementable** (see type requirements + below). .. include:: counting_iterator_abstract.rst diff --git a/doc/counting_iterator_abstract.rst b/doc/counting_iterator_abstract.rst index 30f9986..7d5ea76 100644 --- a/doc/counting_iterator_abstract.rst +++ b/doc/counting_iterator_abstract.rst @@ -1,2 +1,3 @@ -``counting_iterator`` adapts an arithmetic type, such as ``int``, by -adding an ``operator*`` that returns the current value of the object. +``counting_iterator`` adapts an incrementable type such as ``int`` +or ``std::list::iterator``, by adding an ``operator*`` +that returns the current value of the object. diff --git a/doc/facade-and-adaptor.html b/doc/facade-and-adaptor.html index 3550cab..90e9456 100755 --- a/doc/facade-and-adaptor.html +++ b/doc/facade-and-adaptor.html @@ -3,7 +3,7 @@ - + Iterator Facade and Adaptor @@ -326,7 +326,7 @@ of the derived iterator type. These member functions are described briefly below and in more detail in the iterator facade requirements.

- +
@@ -725,7 +725,7 @@ is a constant object of a random access traversal iterator type interoperable with X.

iterator_facade Core Operations

-
+
@@ -1500,7 +1500,7 @@ Iterator and Readable Iterator.

The concepts that reverse_iterator models are dependent on what concepts the Iterator argument models, as specified in the following tables.

-
+
@@ -1519,7 +1519,7 @@ following tables.

- +
@@ -1541,7 +1541,7 @@ following tables.

- +
@@ -1734,7 +1734,7 @@ concept that is modeled by the IteratorIf transform_iterator is a model of Readable Lvalue Iterator then it models the following original iterator concepts depending on what the Iterator argument models.

-
+
@@ -1919,7 +1919,7 @@ Input Iterator.

The concepts that filter_iterator models are dependent on what concepts the Iterator argument models, as specified in the following tables.

-
+
@@ -1938,7 +1938,7 @@ following tables.

- +
@@ -1960,7 +1960,7 @@ following tables.

- +
@@ -2095,8 +2095,9 @@ or m_pred(*m_iter)

Counting iterator

-

counting_iterator adapts an arithmetic type, such as int, by -adding an operator* that returns the current value of the object.

+

counting_iterator adapts an incrementable type such as int +or std::list<std::string>::iterator, by adding an operator* +that returns the current value of the object.

Class template counting_iterator

@@ -2337,10 +2338,10 @@ LocalWords:  OtherIncrementable Coplien -->
 
- + diff --git a/doc/iterator_adaptor.html b/doc/iterator_adaptor.html index 40125b0..ad247c6 100644 --- a/doc/iterator_adaptor.html +++ b/doc/iterator_adaptor.html @@ -3,7 +3,7 @@ - + Iterator Adaptor @@ -57,20 +57,21 @@ core interface functions of iterator_facad -
@@ -239,7 +240,7 @@ expression involving Derived i
-

iterator_adaptor protected member functions

+

iterator_adaptor protected member functions

Base const& base_reference() const;

@@ -260,7 +261,7 @@ expression involving Derived i
-

iterator_adaptor private member functions

+

iterator_adaptor private member functions

typename iterator_adaptor::reference dereference() const;

@@ -328,11 +329,114 @@ typename iterator_adaptor::difference_type distance_to(
+
+

Tutorial Example

+ + + +

In this section we'll further refine the node_iter class +template we developed in the iterator_facade tutorial. If you haven't already +read that material, you should go back now and check it out because +we're going to pick up right where it left off.

+ - +

You probably didn't think of it that way, but the node_base* +object which underlies node_iterator is itself an iterator, +just like all other pointers. If we examine that pointer closely +from an iterator perspective, we can see that it has much in common +with the node_iterator we're building. First, they share most +of the same associated types (value_type, reference, +pointer, and difference_type). Second, even much of the +core functionality is the same: operator* and operator== on +the node_iterator just return the result of invoking the same +operations on the underlying pointer, via the node_iterator's +dereference and equal member functions)

+

It turns out that the pattern of building an iterator on another +iterator-like type (the Base 1 type) while modifying +just a few aspects of the underlying type's behavior is an +extremely common one, and it's the pattern addressed by +iterator_adaptor. Using iterator_adaptor is very much like +using iterator_facade, but because iterator_adaptor tries to +mimic as much of the Base type's behavior as possible, we +neither have to supply a Value argument, nor implement any core +behaviors other than increment. The implementation of +node_iter is thus reduced to:

+
+template <class Value>
+class node_iter
+  : public boost::iterator_adaptor<
+        node_iter<Value>                // Derived
+      , Value*                          // Base
+      , boost::use_default              // Value
+      , boost::forward_traversal_tag    // CategoryOrTraversal
+    >
+{
+ private:
+    struct enabler {};  // a private type avoids misuse
+
+    typedef boost::iterator_adaptor<
+        node_iter<Value>, Value*, boost::use_default, boost::forward_traversal_tag
+    > super_t;
+
+ public:
+    node_iter()
+      : super_t(0) {}
+
+    explicit node_iter(Value* p)
+      : super_t(p) {}
+
+    template <class OtherValue>
+    node_iter(
+        node_iter<OtherValue> const& other
+      , typename boost::enable_if<
+            boost::is_convertible<OtherValue*,Value*>
+          , enabler
+        >::type = enabler()
+    )
+      : super_t(other.base()) {}
+
+ private:
+    friend class boost::iterator_core_access;
+    void increment() { this->base_reference() = this->base()->next(); }
+};
+
+

You can see an example program which exercises this version of the +node iterators here.

+

In the case of node_iter, it's not very compelling to pass +boost::use_default as iterator_adaptor's Value +argument; we could have just passed node_iter's Value +along to iterator_adaptor, and that'd even be shorter! Most +iterator class templates built with iterator_adaptor are +parameterized on another iterator type, rather than on its +value_type. For example, boost::reverse_iterator takes an +iterator type argument and reverses its direction of traversal, +since the original iterator and the reversed one have all the same +associated types, iterator_adaptor's delegation of default +types to its Base saves the implementor of +boost::reverse_iterator from writing

+
+std::iterator_traits<Iterator>::some-associated-type
+
+

at least four times.

+

We urge you to review the documentation and implementations of +reverse_iterator and the other Boost specialized iterator +adaptors to get an idea of the sorts of things you can do with +iterator_adaptor. In particular, have a look at +counting_iterator, which demonstrates that iterator_adaptor's Base type needn't be an iterator.

+
+ + diff --git a/doc/iterator_adaptor.rst b/doc/iterator_adaptor.rst index e64e93a..42e25e3 100644 --- a/doc/iterator_adaptor.rst +++ b/doc/iterator_adaptor.rst @@ -20,8 +20,8 @@ .. contents:: Table of Contents -Introduction -============ +Overview +======== .. include:: iterator_adaptor_body.rst @@ -30,3 +30,8 @@ Reference ========= .. include:: iterator_adaptor_ref.rst + +Tutorial Example +================ + +.. include:: iterator_adaptor_tutorial.rst diff --git a/doc/iterator_adaptor_tutorial.rst b/doc/iterator_adaptor_tutorial.rst new file mode 100755 index 0000000..9aa6552 --- /dev/null +++ b/doc/iterator_adaptor_tutorial.rst @@ -0,0 +1,125 @@ +.. Copyright David Abrahams 2004. Use, modification and distribution is +.. subject to the Boost Software License, Version 1.0. (See accompanying +.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +In this section we'll further refine the ``node_iter`` class +template we developed in the |fac_tut|_. If you haven't already +read that material, you should go back now and check it out because +we're going to pick up right where it left off. + +.. |fac_tut| replace:: ``iterator_facade`` tutorial +.. _fac_tut: iterator_facade.html#tutorial-example + +.. sidebar:: ``node_base*`` really *is* an iterator + + It's not really a very interesting iterator, since ``node_base`` + is an abstract class: a pointer to a ``node_base`` just points + at some base subobject of an instance of some other class, and + incrementing a ``node_base*`` moves it past this base subobject + to who-knows-where? The most we can do with that incremented + position is to compare another ``node_base*`` to it. In other + words, the original iterator traverses a one-element array. + +You probably didn't think of it that way, but the ``node_base*`` +object which underlies ``node_iterator`` is itself an iterator, +just like all other pointers. If we examine that pointer closely +from an iterator perspective, we can see that it has much in common +with the ``node_iterator`` we're building. First, they share most +of the same associated types (``value_type``, ``reference``, +``pointer``, and ``difference_type``). Second, even much of the +core functionality is the same: ``operator*`` and ``operator==`` on +the ``node_iterator`` just return the result of invoking the same +operations on the underlying pointer, via the ``node_iterator``\ 's +|dereference_and_equal|_) + +.. |dereference_and_equal| replace:: ``dereference`` and ``equal`` member functions +.. _dereference_and_equal: iterator_facade.html#implementing-the-core-operations + +It turns out that the pattern of building an iterator on another +iterator-like type (the ``Base`` [#base]_ type) while modifying +just a few aspects of the underlying type's behavior is an +extremely common one, and it's the pattern addressed by +``iterator_adaptor``. Using ``iterator_adaptor`` is very much like +using ``iterator_facade``, but because iterator_adaptor tries to +mimic as much of the ``Base`` type's behavior as possible, we +neither have to supply a ``Value`` argument, nor implement any core +behaviors other than ``increment``. The implementation of +``node_iter`` is thus reduced to:: + + template + class node_iter + : public boost::iterator_adaptor< + node_iter // Derived + , Value* // Base + , boost::use_default // Value + , boost::forward_traversal_tag // CategoryOrTraversal + > + { + private: + struct enabler {}; // a private type avoids misuse + + typedef boost::iterator_adaptor< + node_iter, Value*, boost::use_default, boost::forward_traversal_tag + > super_t; + + public: + node_iter() + : super_t(0) {} + + explicit node_iter(Value* p) + : super_t(p) {} + + template + node_iter( + node_iter const& other + , typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() + ) + : super_t(other.base()) {} + + private: + friend class boost::iterator_core_access; + void increment() { this->base_reference() = this->base()->next(); } + }; + +You can see an example program which exercises this version of the +node iterators `here`__. + +__ ../example/node_iterator3.cpp + +In the case of ``node_iter``, it's not very compelling to pass +``boost::use_default`` as ``iterator_adaptor``\ 's ``Value`` +argument; we could have just passed ``node_iter``\ 's ``Value`` +along to ``iterator_adaptor``, and that'd even be shorter! Most +iterator class templates built with ``iterator_adaptor`` are +parameterized on another iterator type, rather than on its +``value_type``. For example, ``boost::reverse_iterator`` takes an +iterator type argument and reverses its direction of traversal, +since the original iterator and the reversed one have all the same +associated types, ``iterator_adaptor``\ 's delegation of default +types to its ``Base`` saves the implementor of +``boost::reverse_iterator`` from writing + +.. parsed-literal:: + + std::iterator_traits::*some-associated-type* + +at least four times. + +We urge you to review the documentation and implementations of +|reverse_iterator|_ and the other Boost `specialized iterator +adaptors`__ to get an idea of the sorts of things you can do with +``iterator_adaptor``. In particular, have a look at +|counting_iterator|_, which demonstrates that ``iterator_adaptor``\ +'s ``Base`` type needn't be an iterator. + +.. |reverse_iterator| replace:: ``reverse_iterator`` +.. _reverse_iterator: reverse_iterator.html + +.. |counting_iterator| replace:: ``counting_iterator`` +.. _counting_iterator: counting_iterator.html + +__ index.html#specialized-adaptors + diff --git a/doc/iterator_facade.html b/doc/iterator_facade.html index 5bb637f..3fe145b 100644 --- a/doc/iterator_facade.html +++ b/doc/iterator_facade.html @@ -45,44 +45,44 @@ and associated types, to be supplied by a derived iterator class.
-

Overview

+

Overview

@@ -669,7 +669,7 @@ example of a linked list of polymorphic objects. This example was inspired by a posting by Keith Macdonald on the Boost-Users mailing list.

-

The Problem

+

The Problem

Say we've written a polymorphic linked list node base class:

 # include <iostream>
@@ -731,7 +731,7 @@ inline std::ostream& operator<<(std::ostream& s, node_base const&a
 lists.

-

A Basic Iterator Using iterator_facade

+

A Basic Iterator Using iterator_facade

We will construct a node_iterator class using inheritance from iterator_facade to implement most of the iterator's operations.

@@ -745,24 +745,24 @@ class node_iterator
 };
 
-

Template Arguments for iterator_facade

+

Template Arguments for iterator_facade

iterator_facade has several template parameters, so we must decide what types to use for the arguments. The parameters are Derived, Value, CategoryOrTraversal, Reference, and Difference.

-

Derived

+

Derived

Because iterator_facade is meant to be used with the CRTP [Cop95] the first parameter is the iterator class name itself, node_iterator.

-

Value

+

Value

The Value parameter determines the node_iterator's value_type. In this case, we are iterating over node_base objects, so Value will be node_base.

-

CategoryOrTraversal

+

CategoryOrTraversal

Now we have to determine which iterator traversal concept our node_iterator is going to model. Singly-linked lists only have forward links, so our iterator can't can't be a bidirectional @@ -782,7 +782,7 @@ end up being std::forward_iterator_tag

-

Reference

+

Reference

The Reference argument becomes the type returned by node_iterator's dereference operation, and will also be the same as std::iterator_traits<node_iterator>::reference. The @@ -791,7 +791,7 @@ library's default for this parameter is Va type, we can omit this argument, or pass use_default.

-

Difference

+

Difference

The Difference argument determines how the distance between two node_iterators will be measured and will also be the same as std::iterator_traits<node_iterator>::difference_type. @@ -818,7 +818,7 @@ class node_iterator

-

Constructors and Data Members

+

Constructors and Data Members

Next we need to decide how to represent the iterator's position. This representation will take the form of data members, so we'll also need to write constructors to initialize them. The @@ -862,8 +862,8 @@ default constructor to leave m_node

-
-

Core Operations

+
+

Implementing the Core Operations

The last step is to implement the core operations required by the concepts we want our iterator to model. Referring to the table, we can see that the first three rows are applicable @@ -914,7 +914,7 @@ iterator! For a working example of its use, see -

A constant node_iterator

+

A constant node_iterator

-

Interoperability

+

Interoperability

Our const_node_iterator works perfectly well on its own, but taken together with node_iterator it doesn't quite meet expectations. For example, we'd like to be able to pass a @@ -1027,7 +1027,7 @@ compare them for equality.

This expected ability to use two different iterator types together is known as interoperability. Achieving interoperability in our case is as simple as templatizing the equal function and -adding a templatized converting constructor 3 4:

+adding a templatized converting constructor 3 4:

 template <class Value>
 class node_iter
@@ -1072,14 +1072,14 @@ typedef impl::node_iterator<node_base const> node_const_iterator;
 
-
[3]If you're using an older compiler and it can't handle +
[3]If you're using an older compiler and it can't handle this example, see the example code for workarounds.
- @@ -1088,7 +1088,7 @@ traversal iterator, we'd have had to templatize its iterators here.

-

Telling the Truth

+

Telling the Truth

Now node_iterator and node_const_iterator behave exactly as you'd expect... almost. We can compare them and we can convert in one direction: from node_iterator to node_const_iterator. @@ -1109,19 +1109,24 @@ the m_node conversion would fa follows, we can remove it from the overload set when it's not appropriate:

-template <class OtherValue>
-node_iter(
-    node_iter<OtherValue> const& other
-  , typename boost::enable_if<
-        boost::is_convertible<OtherValue*,Value*>
-      , enabler
-    >::type = enabler()
-)
-  : m_node(other.m_node) {}
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/utility/enable_if.hpp>
+
+  ...
+
+  template <class OtherValue>
+  node_iter(
+      node_iter<OtherValue> const& other
+    , typename boost::enable_if<
+          boost::is_convertible<OtherValue*,Value*>
+        , enabler
+      >::type = enabler()
+  )
+    : m_node(other.m_node) {}
 
-

Wrap Up

+

Wrap Up

This concludes our iterator_facade tutorial, but before you stop reading we urge you to take a look at iterator_adaptor. There's another way to approach writing these iterators which might @@ -1132,7 +1137,7 @@ even be superior.

diff --git a/doc/iterator_facade_tutorial.rst b/doc/iterator_facade_tutorial.rst index 837fcbc..bb96264 100755 --- a/doc/iterator_facade_tutorial.rst +++ b/doc/iterator_facade_tutorial.rst @@ -212,8 +212,8 @@ Our ``node_iterator`` then becomes:: really concerned with efficiency, we could've written the default constructor to leave ``m_node`` uninitialized. -Core Operations -............... +Implementing the Core Operations +................................ The last step is to implement the `core operations`_ required by the concepts we want our iterator to model. Referring to the @@ -475,6 +475,11 @@ In fact, that sort of magic is possible using follows, we can remove it from the overload set when it's not appropriate:: + #include + #include + + ... + template node_iter( node_iter const& other diff --git a/example/Jamfile b/example/Jamfile index 9ca17af..6eb6cc7 100644 --- a/example/Jamfile +++ b/example/Jamfile @@ -9,4 +9,5 @@ test-suite iterator_examples : [ run reverse_iterator.cpp ] [ run node_iterator1.cpp ] [ run node_iterator2.cpp ] + [ run node_iterator3.cpp ] ; diff --git a/example/node_iterator2.hpp b/example/node_iterator2.hpp index 15b40aa..22c9bf2 100755 --- a/example/node_iterator2.hpp +++ b/example/node_iterator2.hpp @@ -5,7 +5,7 @@ # define NODE_ITERATOR2_DWA2004110_HPP # include "node.hpp" -# include +# include # ifndef BOOST_NO_SFINAE # include @@ -14,21 +14,26 @@ template class node_iter - : public boost::iterator_facade< - node_iter - , Value - , boost::forward_traversal_tag + : public boost::iterator_adaptor< + node_iter // Derived + , Value* // Base + , boost::use_default // Value + , boost::forward_traversal_tag // CategoryOrTraversal > { private: struct enabler {}; // a private type avoids misuse + typedef boost::iterator_adaptor< + node_iter, Value*, boost::use_default, boost::forward_traversal_tag + > super_t; + public: node_iter() - : m_node(0) {} + : super_t(0) {} explicit node_iter(Value* p) - : m_node(p) {} + : super_t(p) {} template node_iter( @@ -42,29 +47,9 @@ class node_iter ) : m_node(other.m_node) {} - -# if !BOOST_WORKAROUND(__GNUC__, == 2) - private: // GCC2 can't even grant that friendship to template member functions -# endif - friend class boost::iterator_core_access; - - template - bool equal(node_iter const& other) const - { - return this->m_node == other.m_node; - } - private: + friend class boost::iterator_core_access; void increment() { m_node = m_node->next(); } - - Value& dereference() const { return *m_node; } - -# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS - public: -# else - template friend class node_iter; -# endif - Value* m_node; }; typedef node_iter node_iterator; diff --git a/example/node_iterator3.cpp b/example/node_iterator3.cpp new file mode 100755 index 0000000..331cc93 --- /dev/null +++ b/example/node_iterator3.cpp @@ -0,0 +1,43 @@ +// Copyright David Abrahams 2004. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include "node_iterator3.hpp" +#include +#include +#include +#include +#include +#include + +int main() +{ + std::auto_ptr > nodes(new node(42)); + nodes->append(new node(" is greater than ")); + nodes->append(new node(13)); + + // Check interoperability + assert(node_iterator(nodes.get()) == node_const_iterator(nodes.get())); + assert(node_const_iterator(nodes.get()) == node_iterator(nodes.get())); + + assert(node_iterator(nodes.get()) != node_const_iterator()); + assert(node_const_iterator(nodes.get()) != node_iterator()); + + std::copy( + node_iterator(nodes.get()), node_iterator() + , std::ostream_iterator(std::cout, " ") + ); + std::cout << std::endl; + + std::for_each( + node_iterator(nodes.get()), node_iterator() + , boost::mem_fn(&node_base::double_me) + ); + + std::copy( + node_const_iterator(nodes.get()), node_const_iterator() + , std::ostream_iterator(std::cout, "/") + ); + std::cout << std::endl; + return 0; +} diff --git a/example/node_iterator3.hpp b/example/node_iterator3.hpp new file mode 100755 index 0000000..ec632b0 --- /dev/null +++ b/example/node_iterator3.hpp @@ -0,0 +1,58 @@ +// Copyright David Abrahams 2004. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef NODE_ITERATOR3_DWA2004110_HPP +# define NODE_ITERATOR3_DWA2004110_HPP + +# include "node.hpp" +# include + +# ifndef BOOST_NO_SFINAE +# include +# include +# endif + +template +class node_iter + : public boost::iterator_adaptor< + node_iter // Derived + , Value* // Base + , boost::use_default // Value + , boost::forward_traversal_tag // CategoryOrTraversal + > +{ + private: + struct enabler {}; // a private type avoids misuse + + typedef boost::iterator_adaptor< + node_iter, Value*, boost::use_default, boost::forward_traversal_tag + > super_t; + + public: + node_iter() + : super_t(0) {} + + explicit node_iter(Value* p) + : super_t(p) {} + + template + node_iter( + node_iter const& other +# ifndef BOOST_NO_SFINAE + , typename boost::enable_if< + boost::is_convertible + , enabler + >::type = enabler() +# endif + ) + : m_node(other.m_node) {} + + private: + friend class boost::iterator_core_access; + void increment() { this->base_reference() = this->base()->next(); } +}; + +typedef node_iter node_iterator; +typedef node_iter node_const_iterator; + +#endif // NODE_ITERATOR3_DWA2004110_HPP
[4]If node_iterator had been a random access +
[4]If node_iterator had been a random access traversal iterator, we'd have had to templatize its distance_to function as well.