]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/iterator/doc/iterator_facade_tutorial.rst
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / iterator / doc / iterator_facade_tutorial.rst
CommitLineData
7c673cae
FG
1.. Copyright David Abrahams 2004. Use, modification and distribution is
2.. subject to the Boost Software License, Version 1.0. (See accompanying
3.. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5In this section we'll walk through the implementation of a few
6iterators using ``iterator_facade``, based around the simple
7example of a linked list of polymorphic objects. This example was
8inspired by a `posting`__ by Keith Macdonald on the `Boost-Users`_
9mailing list.
10
11.. _`Boost-Users`: http://www.boost.org/more/mailing_lists.htm#users
12
13__ http://thread.gmane.org/gmane.comp.lib.boost.user/5100
14
15The Problem
16-----------
17
18Say we've written a polymorphic linked list node base class::
19
20 # include <iostream>
21
22 struct node_base
23 {
24 node_base() : m_next(0) {}
25
26 // Each node manages all of its tail nodes
27 virtual ~node_base() { delete m_next; }
28
29 // Access the rest of the list
30 node_base* next() const { return m_next; }
31
32 // print to the stream
33 virtual void print(std::ostream& s) const = 0;
34
35 // double the value
36 virtual void double_me() = 0;
37
38 void append(node_base* p)
39 {
40 if (m_next)
41 m_next->append(p);
42 else
43 m_next = p;
44 }
45
46 private:
47 node_base* m_next;
48 };
49
50Lists can hold objects of different types by linking together
51specializations of the following template::
52
53 template <class T>
54 struct node : node_base
55 {
56 node(T x)
57 : m_value(x)
58 {}
59
60 void print(std::ostream& s) const { s << this->m_value; }
61 void double_me() { m_value += m_value; }
62
63 private:
64 T m_value;
65 };
66
67And we can print any node using the following streaming operator::
68
69 inline std::ostream& operator<<(std::ostream& s, node_base const& n)
70 {
71 n.print(s);
72 return s;
73 }
74
75Our first challenge is to build an appropriate iterator over these
76lists.
77
78A Basic Iterator Using ``iterator_facade``
79------------------------------------------
80
81We will construct a ``node_iterator`` class using inheritance from
82``iterator_facade`` to implement most of the iterator's operations.
83
84::
85
86 # include "node.hpp"
87 # include <boost/iterator/iterator_facade.hpp>
88
89 class node_iterator
90 : public boost::iterator_facade<...>
91 {
92 ...
93 };
94
95
96
97Template Arguments for ``iterator_facade``
98..........................................
99
100``iterator_facade`` has several template parameters, so we must decide
101what types to use for the arguments. The parameters are ``Derived``,
102``Value``, ``CategoryOrTraversal``, ``Reference``, and ``Difference``.
103
104
105``Derived``
106'''''''''''
107
108Because ``iterator_facade`` is meant to be used with the CRTP
109[Cop95]_ the first parameter is the iterator class name itself,
110``node_iterator``.
111
112``Value``
113'''''''''
114
115The ``Value`` parameter determines the ``node_iterator``\ 's
116``value_type``. In this case, we are iterating over ``node_base``
117objects, so ``Value`` will be ``node_base``.
118
119
120``CategoryOrTraversal``
121'''''''''''''''''''''''
122
123Now we have to determine which `iterator traversal concept`_ our
124``node_iterator`` is going to model. Singly-linked lists only have
125forward links, so our iterator can't can't be a `bidirectional
126traversal iterator`_. Our iterator should be able to make multiple
127passes over the same linked list (unlike, say, an
128``istream_iterator`` which consumes the stream it traverses), so it
129must be a `forward traversal iterator`_. Therefore, we'll pass
130``boost::forward_traversal_tag`` in this position [#category]_.
131
132.. [#category] ``iterator_facade`` also supports old-style category
133 tags, so we could have passed ``std::forward_iterator_tag`` here;
134 either way, the resulting iterator's ``iterator_category`` will
135 end up being ``std::forward_iterator_tag``.
136
137``Reference``
138'''''''''''''
139
140The ``Reference`` argument becomes the type returned by
141``node_iterator``\ 's dereference operation, and will also be the
142same as ``std::iterator_traits<node_iterator>::reference``. The
143library's default for this parameter is ``Value&``; since
144``node_base&`` is a good choice for the iterator's ``reference``
145type, we can omit this argument, or pass ``use_default``.
146
147``Difference``
148''''''''''''''
149
150The ``Difference`` argument determines how the distance between
151two ``node_iterator``\ s will be measured and will also be the
152same as ``std::iterator_traits<node_iterator>::difference_type``.
153The library's default for ``Difference`` is ``std::ptrdiff_t``, an
154appropriate type for measuring the distance between any two
155addresses in memory, and one that works for almost any iterator,
156so we can omit this argument, too.
157
158The declaration of ``node_iterator`` will therefore look something
159like::
160
161 # include "node.hpp"
162 # include <boost/iterator/iterator_facade.hpp>
163
164 class node_iterator
165 : public boost::iterator_facade<
166 node_iterator
167 , node_base
168 , boost::forward_traversal_tag
169 >
170 {
171 ...
172 };
173
174Constructors and Data Members
175.............................
176
177Next we need to decide how to represent the iterator's position.
178This representation will take the form of data members, so we'll
179also need to write constructors to initialize them. The
180``node_iterator``\ 's position is quite naturally represented using
181a pointer to a ``node_base``. We'll need a constructor to build an
182iterator from a ``node_base*``, and a default constructor to
183satisfy the `forward traversal iterator`_ requirements [#default]_.
184Our ``node_iterator`` then becomes::
185
186 # include "node.hpp"
187 # include <boost/iterator/iterator_facade.hpp>
188
189 class node_iterator
190 : public boost::iterator_facade<
191 node_iterator
192 , node_base
193 , boost::forward_traversal_tag
194 >
195 {
196 public:
197 node_iterator()
198 : m_node(0)
199 {}
200
201 explicit node_iterator(node_base* p)
202 : m_node(p)
203 {}
204
205 private:
206 ...
207 node_base* m_node;
208 };
209
210.. [#default] Technically, the C++ standard places almost no
211 requirements on a default-constructed iterator, so if we were
212 really concerned with efficiency, we could've written the
213 default constructor to leave ``m_node`` uninitialized.
214
215Implementing the Core Operations
216................................
217
218The last step is to implement the `core operations`_ required by
219the concepts we want our iterator to model. Referring to the
220table__, we can see that the first three rows are applicable
221because ``node_iterator`` needs to satisfy the requirements for
222`readable iterator`_, `single pass iterator`_, and `incrementable
223iterator`_.
224
225__ `core operations`_
226
227We therefore need to supply ``dereference``,
228``equal``, and ``increment`` members. We don't want these members
229to become part of ``node_iterator``\ 's public interface, so we can
230make them private and grant friendship to
231``boost::iterator_core_access``, a "back-door" that
232``iterator_facade`` uses to get access to the core operations::
233
234 # include "node.hpp"
235 # include <boost/iterator/iterator_facade.hpp>
236
237 class node_iterator
238 : public boost::iterator_facade<
239 node_iterator
240 , node_base
241 , boost::forward_traversal_tag
242 >
243 {
244 public:
245 node_iterator()
246 : m_node(0) {}
247
248 explicit node_iterator(node_base* p)
249 : m_node(p) {}
250
251 private:
252 friend class boost::iterator_core_access;
253
254 void increment() { m_node = m_node->next(); }
255
256 bool equal(node_iterator const& other) const
257 {
258 return this->m_node == other.m_node;
259 }
260
261 node_base& dereference() const { return *m_node; }
262
263 node_base* m_node;
264 };
265
266