From fbb3c49f8b7536c10ce8401c26d895cc58e04c21 Mon Sep 17 00:00:00 2001 From: nobody Date: Wed, 28 Feb 2001 21:40:00 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'unlabeled-1.8.2'. [SVN r9368] --- .gitattributes | 96 +++++ call_traits_test.cpp | 366 +++++++++++++++++++ counting_iterator.htm | 325 +++++++++++++++++ iterator_adaptors.htm | 819 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1606 insertions(+) create mode 100644 .gitattributes create mode 100644 call_traits_test.cpp create mode 100644 counting_iterator.htm create mode 100644 iterator_adaptors.htm diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/call_traits_test.cpp b/call_traits_test.cpp new file mode 100644 index 0000000..0c7155e --- /dev/null +++ b/call_traits_test.cpp @@ -0,0 +1,366 @@ + // boost::compressed_pair test program + + // (C) Copyright John Maddock 2000. 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. + +// standalone test program for +// 03 Oct 2000: +// Enabled extra tests for VC6. + +#include +#include +#include +#include +#include +#include + +#include "type_traits_test.hpp" +// +// struct contained models a type that contains a type (for example std::pair) +// arrays are contained by value, and have to be treated as a special case: +// +template +struct contained +{ + // define our typedefs first, arrays are stored by value + // so value_type is not the same as result_type: + typedef typename boost::call_traits::param_type param_type; + typedef typename boost::call_traits::reference reference; + typedef typename boost::call_traits::const_reference const_reference; + typedef T value_type; + typedef typename boost::call_traits::value_type result_type; + + // stored value: + value_type v_; + + // constructors: + contained() {} + contained(param_type p) : v_(p){} + // return byval: + result_type value()const { return v_; } + // return by_ref: + reference get() { return v_; } + const_reference const_get()const { return v_; } + // pass value: + void call(param_type p){} + +}; + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct contained +{ + typedef typename boost::call_traits::param_type param_type; + typedef typename boost::call_traits::reference reference; + typedef typename boost::call_traits::const_reference const_reference; + typedef T value_type[N]; + typedef typename boost::call_traits::value_type result_type; + + value_type v_; + + contained(param_type p) + { + std::copy(p, p+N, v_); + } + // return byval: + result_type value()const { return v_; } + // return by_ref: + reference get() { return v_; } + const_reference const_get()const { return v_; } + void call(param_type p){} +}; +#endif + +template +contained::value_type> wrap(const T& t) +{ + typedef typename boost::call_traits::value_type ct; + return contained(t); +} + +namespace test{ + +template +std::pair< + typename boost::call_traits::value_type, + typename boost::call_traits::value_type> + make_pair(const T1& t1, const T2& t2) +{ + return std::pair< + typename boost::call_traits::value_type, + typename boost::call_traits::value_type>(t1, t2); +} + +} // namespace test + +using namespace std; + +// +// struct checker: +// verifies behaviour of contained example: +// +template +struct checker +{ + typedef typename boost::call_traits::param_type param_type; + void operator()(param_type); +}; + +template +void checker::operator()(param_type p) +{ + T t(p); + contained c(t); + cout << "checking contained<" << typeid(T).name() << ">..." << endl; + assert(t == c.value()); + assert(t == c.get()); + assert(t == c.const_get()); + + //cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained::value).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained::get).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained::const_get).name() << endl; + cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained::call).name() << endl; + cout << endl; +} + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct checker +{ + typedef typename boost::call_traits::param_type param_type; + void operator()(param_type t) + { + contained c(t); + cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl; + unsigned int i = 0; + for(i = 0; i < N; ++i) + assert(t[i] == c.value()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.get()[i]); + for(i = 0; i < N; ++i) + assert(t[i] == c.const_get()[i]); + + cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained::v_).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained::value).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained::get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained::const_get).name() << endl; + cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained::call).name() << endl; + cout << endl; + } +}; +#endif + +// +// check_wrap: +template +void check_wrap(const contained& w, const U& u) +{ + cout << "checking contained<" << typeid(T).name() << ">..." << endl; + assert(w.value() == u); +} + +// +// check_make_pair: +// verifies behaviour of "make_pair": +// +template +void check_make_pair(T c, U u, V v) +{ + cout << "checking std::pair<" << typeid(c.first).name() << ", " << typeid(c.second).name() << ">..." << endl; + assert(c.first == u); + assert(c.second == v); + cout << endl; +} + + +struct UDT +{ + int i_; + UDT() : i_(2){} + bool operator == (const UDT& v){ return v.i_ == i_; } +}; + +int main() +{ + checker c1; + UDT u; + c1(u); + checker c2; + int i = 2; + c2(i); + int* pi = &i; +#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) + checker c3; + c3(pi); + checker c4; + c4(i); + checker c5; + c5(i); +#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + int a[2] = {1,2}; + checker c6; + c6(a); +#endif +#endif + + check_wrap(wrap(2), 2); + const char ca[4] = "abc"; + // compiler can't deduce this for some reason: + //check_wrap(wrap(ca), ca); +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + check_wrap(wrap(a), a); + check_make_pair(test::make_pair(a, a), a, a); +#endif + + // cv-qualifiers applied to reference types should have no effect + // declare these here for later use with is_reference and remove_reference: + typedef int& r_type; + typedef const r_type cr_type; + + type_test(UDT, boost::call_traits::value_type) + type_test(UDT&, boost::call_traits::reference) + type_test(const UDT&, boost::call_traits::const_reference) + type_test(const UDT&, boost::call_traits::param_type) + type_test(int, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(const int, boost::call_traits::param_type) + type_test(int*, boost::call_traits::value_type) + type_test(int*&, boost::call_traits::reference) + type_test(int*const&, boost::call_traits::const_reference) + type_test(int*const, boost::call_traits::param_type) +#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) + type_test(int&, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(int&, boost::call_traits::param_type) +#if !(defined(__GNUC__) && (__GNUC__ < 3)) + type_test(int&, boost::call_traits::value_type) + type_test(int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(int&, boost::call_traits::param_type) +#else + std::cout << "Your compiler cannot instantiate call_traits, skipping four tests (4 errors)" << std::endl; + failures += 4; + test_count += 4; +#endif + type_test(const int&, boost::call_traits::value_type) + type_test(const int&, boost::call_traits::reference) + type_test(const int&, boost::call_traits::const_reference) + type_test(const int&, boost::call_traits::param_type) +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + type_test(const int*, boost::call_traits::value_type) + type_test(int(&)[3], boost::call_traits::reference) + type_test(const int(&)[3], boost::call_traits::const_reference) + type_test(const int*const, boost::call_traits::param_type) + type_test(const int*, boost::call_traits::value_type) + type_test(const int(&)[3], boost::call_traits::reference) + type_test(const int(&)[3], boost::call_traits::const_reference) + type_test(const int*const, boost::call_traits::param_type) +#else + std::cout << "You're compiler does not support partial template instantiation, skipping 8 tests (8 errors)" << std::endl; + failures += 8; + test_count += 8; +#endif +#else + std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl; + failures += 20; + test_count += 20; +#endif + + std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit"; + std::cin.get(); + return failures; +} + +// +// define call_traits tests to check that the assertions in the docs do actually work +// this is an instantiate only set of tests: +// +template +struct call_traits_test +{ + typedef ::boost::call_traits ct; + typedef typename ct::param_type param_type; + typedef typename ct::reference reference; + typedef typename ct::const_reference const_reference; + typedef typename ct::value_type value_type; + static void assert_construct(param_type val); +}; + +template +void call_traits_test::assert_construct(typename call_traits_test::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t(val); + value_type v(t); + reference r(t); + const_reference cr(t); + param_type p(t); + value_type v2(v); + value_type v3(r); + value_type v4(p); + reference r2(v); + reference r3(r); + const_reference cr2(v); + const_reference cr3(r); + const_reference cr4(cr); + const_reference cr5(p); + param_type p2(v); + param_type p3(r); + param_type p4(p); +} +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct call_traits_test +{ + typedef ::boost::call_traits ct; + typedef typename ct::param_type param_type; + typedef typename ct::reference reference; + typedef typename ct::const_reference const_reference; + typedef typename ct::value_type value_type; + static void assert_construct(param_type val); +}; + +template +void call_traits_test::assert_construct(typename boost::call_traits::param_type val) +{ + // + // this is to check that the call_traits assertions are valid: + T t; + value_type v(t); + value_type v5(val); + reference r = t; + const_reference cr = t; + reference r2 = r; + #ifndef __BORLANDC__ + // C++ Builder buglet: + const_reference cr2 = r; + #endif + param_type p(t); + value_type v2(v); + const_reference cr3 = cr; + value_type v3(r); + value_type v4(p); + param_type p2(v); + param_type p3(r); + param_type p4(p); +} +#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// +// now check call_traits assertions by instantiating call_traits_test: +template struct call_traits_test; +template struct call_traits_test; +template struct call_traits_test; +#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES) +template struct call_traits_test; +template struct call_traits_test; +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template struct call_traits_test; +#endif +#endif + diff --git a/counting_iterator.htm b/counting_iterator.htm new file mode 100644 index 0000000..c221a6c --- /dev/null +++ b/counting_iterator.htm @@ -0,0 +1,325 @@ + + + + + + +Counting Iterator Adaptor Documentation + + + + +c++boost.gif (8819 bytes) + +

Counting Iterator Adaptor

+ +Defined in header +boost/counting_iterator.hpp + +

+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). The +following pseudo-code shows the general idea of how the +counting iterator is implemented. +

+ +
+  // inside a hypothetical counting_iterator class...
+  typedef Incrementable value_type;
+  value_type counting_iterator::operator*() const {
+    return this->base; // no dereference!
+  }
+
+ +All of the other operators of the counting iterator behave in the same +fashion as the Incrementable base type. + +

Synopsis

+ +
+namespace boost {
+  template <class Incrementable>
+  struct counting_iterator_traits;
+
+  template <class Incrementable>
+  struct counting_iterator_generator;
+
+  template <class Incrementable>
+  typename counting_iterator_generator<Incrementable>::type
+  make_counting_iterator(Incrementable x);
+}
+
+ +
+ +

The Counting Iterator Type +Generator

+ +The class template counting_iterator_generator<Incrementable> is a type generator for counting iterators. + +
+template <class Incrementable>
+class counting_iterator_generator
+{
+public:
+    typedef iterator_adaptor<...> type;
+};
+
+ +

Example

+ +In this example we use the counting iterator generator to create a +counting iterator, and count from zero to four. + +
+#include <boost/config.hpp>
+#include <iostream>
+#include <boost/counting_iterator.hpp>
+
+int main(int, char*[])
+{
+  // Example of using counting_iterator_generator
+  std::cout << "counting from 0 to 4:" << std::endl;
+  boost::counting_iterator_generator<int>::type first(0), last(4);
+  std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
+  std::cout << std::endl;
+
+  // to be continued...
+
+The output from this part is: +
+counting from 0 to 4:
+0 1 2 3 
+
+ +

Template Parameters

+ + + + + + + + + + + +
ParameterDescription
IncrementableThe type being wrapped by the adaptor.
+ +

Model of

+ +If the Incrementable type has all of the functionality of a +Random +Access Iterator except the operator*(), then the counting +iterator will be a model of Random +Access Iterator. If the Incrementable type has less +functionality, then the counting iterator will have correspondingly +less functionality. + +

Type Requirements

+ +The Incrementable type must be Default +Constructible, Copy +Constructible, and Assignable. +Also, the Incrementable type must provide access to an +associated difference_type and iterator_category +through the counting_iterator_traits +class. + +

+Furthermore, if you wish to create a counting iterator that is a Forward +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 Iterator, then pre-decrement is also required: +
+--i
+
+If you wish to create a counting iterator that is a Random +Access Iterator, then these additional expressions are also required: +
+counting_iterator_traits<Incrementable>::difference_type n;
+i += n
+n = i - j
+i < j
+
+ + + +

Members

+ +The counting iterator type implements the member functions and +operators required of the Random +Access Iterator concept. In addition it has the following +constructor: + +
+counting_iterator_generator::type(const Incrementable& i)
+
+ +

+


+

+ + +

The Counting Iterator Object Generator

+ +
+template <class Incrementable>
+typename counting_iterator_generator<Incrementable>::type
+make_counting_iterator(Incrementable base);
+
+ +An object +generator function that provides a convenient way to create counting +iterators.

+ + + +

Example

+ +In this example we count from negative five to positive five, this +time using the make_counting_iterator() function to save some +typing. + +
+  // continuing from previous example...
+
+  std::cout << "counting from -5 to 4:" << std::endl;
+  std::copy(boost::make_counting_iterator(-5),
+	    boost::make_counting_iterator(5),
+	    std::ostream_iterator<int>(std::cout, " "));
+  std::cout << std::endl;
+
+  // to be continued...
+
+The output from this part is: +
+counting from -5 to 4:
+-5 -4 -3 -2 -1 0 1 2 3 4 
+
+ +In the next example we create an array of numbers, and then create a +second array of pointers, where each pointer is the address of a +number in the first array. The counting iterator makes it easy to do +this since dereferencing a counting iterator that is wrapping an +iterator over the array of numbers just returns a pointer to the +current location in the array. We then use the indirect iterator adaptor to print +out the number in the array by accessing the numbers through the array +of pointers. + +
+  // continuing from previous example...
+
+  const int N = 7;
+  std::vector<int> numbers;
+  // Fill "numbers" array with [0,N)
+  std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
+	    std::back_inserter(numbers));
+
+  std::vector<std::vector<int>::iterator> pointers;
+
+  // Use counting iterator to fill in the array of pointers.
+  std::copy(boost::make_counting_iterator(numbers.begin()),
+	    boost::make_counting_iterator(numbers.end()),
+	    std::back_inserter(pointers));
+
+  // Use indirect iterator to print out numbers by accessing
+  // them through the array of pointers.
+  std::cout << "indirectly printing out the numbers from 0 to " 
+	    << N << std::endl;
+  std::copy(boost::make_indirect_iterator(pointers.begin()),
+	    boost::make_indirect_iterator(pointers.end()),
+	    std::ostream_iterator<int>(std::cout, " "));
+  std::cout << std::endl;
+
+The output is: +
+indirectly printing out the numbers from 0 to 7
+0 1 2 3 4 5 6 
+
+ +
+ +

Counting Iterator Traits

+ +The counting iterator adaptor needs to determine the appropriate +difference_type and iterator_category to use based on the +Incrementable type supplied by the user. The +counting_iterator_traits class provides these types. If the +Incrementable type is an integral type or an iterator, these types +will be correctly deduced by the counting_iterator_traits provided by +the library. Otherwise, the user must specialize +counting_iterator_traits for her type or add nested typedefs to +her type to fulfill the needs of + +std::iterator_traits. + +

The following pseudocode describes how the counting_iterator_traits are determined: + +

+template <class Incrementable>
+struct counting_iterator_traits
+{
+  if (numeric_limits<Incrementable>::is_specialized) {
+    if (!numeric_limits<Incrementable>::is_integer)
+       COMPILE_TIME_ERROR;
+
+    if (!numeric_limits<Incrementable>::is_bounded
+        && numeric_limits<Incrementable>::is_signed) {
+        typedef Incrementable difference_type;
+    }
+    else if (numeric_limits<Incrementable>::is_integral) {
+        typedef next-larger-signed-type-or-intmax_t difference_type;
+    }
+    typedef std::random_access_iterator_tag iterator_category;   
+  } else {
+    typedef std::iterator_traits<Incrementable>::difference_type difference_type;
+    typedef std::iterator_traits<Incrementable>::iterator_category iterator_category;
+  }
+};
+
+ +

The italicized sections above are implementation details, but it is important +to know that the difference_type for integral types is selected so that +it can always represent the difference between two values if such a built-in +integer exists. On platforms with a working std::numeric_limits +implementation, the difference_type for any variable-length signed +integer type T is T itself. + +


+

Revised 26 Feb 2001

+

© Copyright Jeremy Siek 2000. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose.

+ + + + + + + diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm new file mode 100644 index 0000000..7bfa3cd --- /dev/null +++ b/iterator_adaptors.htm @@ -0,0 +1,819 @@ + + + + + + +Header boost/iterator_adaptors.hpp Documentation + + + + +c++boost.gif (8819 bytes) + +

Header +boost/iterator_adaptors.hpp +and +boost/integer_range.hpp

+ +

The file boost/iterator_adaptors.hpp +includes the main iterator_adaptors class and several other classes +for constructing commonly used iterator adaptors.

+ + + +

The file boost/integer_range.hpp includes a class that + uses iterator adaptors to create an iterator that increments over a + range of integers. The file also includes a "container" type + that creates a container-interface for the range of integers. +

+ + + + +

Dave +Abrahams started the library, coming up with the idea to use +policy classes and how to handle the const/non-const iterator +interactions. He also contributed the indirect_iterators and +reverse_iterators classes.
+ +Jeremy Siek +contributed transform_iterator, integer_range, +and this documentation.
+ +John Potter +contributed indirect_iterator and projection_iterator +and made some simplifications to iterator_adaptor. + +

The Iterator Adaptors Class

+ +Implementing standard conforming iterators is a non-trivial task. +There are some fine-points such as iterator/const_iterator +interactions and there are the myriad of operators that should be +implemented but are easily forgotten such as +operator->(). The purpose of the +iterator_adaptors class is to make it easier to implement an +iterator class, and even easier to extend and adapt existing iterator +types. The iterator_adaptors class itself is not an adaptor +class but a type generator. It generates a pair of adaptor classes, +one class for the mutable iterator and one class for the const +iterator. The definition of the iterator_adaptors class is as +follows: + +

+ +
+
+template <class Iterator,
+          class ConstIterator,
+          class Traits = std::iterator_traits<Iterator>,
+          class ConstTraits = std::iterator_traits<ConstIterator>,
+          class Policies = default_iterator_policies>
+struct iterator_adaptors
+{
+  typedef ... iterator;
+  typedef ... const_iterator;
+};
+
+ +

The Iterator and ConstIterator template parameters +are the iterator types that you want to adapt. The Traits and +ConstTraits must be iterator traits classes. The traits +parameters default to the specialization of the +std::iterator_traits class for the adapted iterators. If you +want the traits for your new iterator adaptor (value_type, +iterator_category, etc.) to be the same as the adapted +iterator then use the default, otherwise create your own traits +classes and pass them in [1]. + + +

The Policies class that you pass in will become the heart of +the iterator adaptor, supplying the core iterator operations that will determine how your new adaptor +class will behave. The core iterator operations are: +

    +
  • dereference - returns an element of the iterator's reference type +
  • equal - tests the iterator for equality +
  • increment - increments the iterator +
  • decrement - decrements bidirectional and random-access iterators +
  • less - imposes a strict weak ordering relation on random-access iterators +
  • distance - measures the distance between random-access iterators +
  • advance - adds an integer offset to random-access iterators +
+The Policies class must implement three, four, or +seven of the core iterator operations depending on whether you wish the +new iterator adaptor class to be a + +ForwardIterator, + +BidirectionalIterator, or +RandomAccessIterator. The +iterator_category type of the traits class you pass in +must match the category of iterator that you want to create. The default +policy class, default_iterator_policies, implements all 7 of +the core operations in the usual way. If you wish to create an +iterator adaptor that only changes a few of the iterator's behaviors, +then you can have your new policy class inherit from +default_iterator_policies to avoid retyping the usual +behaviours. You should also look at default_iterator_policies +as the "boiler-plate" for your own policy classes. The +following is definition of the default_iterator_policies +class: + + +

+ +
+
+struct default_iterator_policies
+{
+  // required for a ForwardIterator
+  template <class Reference, class Iterator>
+  Reference dereference(type<Reference>, const Iterator& x) const
+    { return *x; }
+
+  template <class Iterator>
+  static void increment(Iterator& x)
+    { ++x; }
+
+  template <class Iterator1, class Iterator2>
+  bool equal(Iterator1& x, Iterator2& y) const
+    { return x == y; }
+
+  // required for a BidirectionalIterator
+  template <class Iterator>
+  static void decrement(Iterator& x)
+    { --x; }
+
+  // required for a RandomAccessIterator
+  template <class Iterator, class DifferenceType>
+  static void advance(Iterator& x, DifferenceType n)
+    { x += n; }
+
+  template <class Difference, class Iterator1, class Iterator2>
+  Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
+    { return y - x; }
+
+  template <class Iterator1, class Iterator2>
+  bool less(Iterator1& x, Iterator2& y) const
+    { return x < y; }
+};
+
+ +

+The generated iterator adaptor types will have the following +constructors. + +

+ +
+
+iterator(const Iterator& i, const Policies& p = Policies())
+
+const_iterator(const ConstIterator& i, const Policies& p = Policies())
+
+ +

The Iterator Adaptor Class

+ +This is the class used inside of the iterator_adaptors type +generator. Use this class directly (instead of using +iterator_adaptors) when you are interested in creating only +one of the iterator types (either const or non-const) or when there is +no difference between the const and non-const versions of the iterator +type (often this is because there is only a const (read-only) version +of the iterator, as is the case for std::set's iterators). + +

+ +
+
+template <class Iterator,
+          class Policies = default_iterator_policies,
+          class Traits = std::iterator_traits<Iterator> >
+struct iterator_adaptor;
+
+ + +

+Next we will look at some iterator adaptors that are examples of how +to use the iterator adaptors class, and that are useful iterator +adaptors in their own right. + +

The Transform Iterator Class

+ +It is often useful to automatically apply some function to the value +returned by dereferencing (operator*()) an iterator. The +transform_iterators class makes it easy to create an iterator +adaptor that does just that. + +First let us consider what the Policies class for the transform +iterator should look like. We are only changing one of the iterator +behaviours, so we will inherit from +default_iterator_policies. In addition, we will need a +function object to apply, so we will have a template parameter and a +data member for the function object. The function will take one +argument (the dereferenced value) and we will need to know the +result_type of the function, so +AdaptableUnaryFunction is the corrent concept to choose for the +function object type. Now for the heart of our iterator adaptor, we +implement the dereference method, applying the function +object to *i. The type<Reference> class is +there to tell you what the reference type of the iterator is, which is +handy when writing generic iterator adaptors such as this one [2]. + + +

+ +
+
+  template <class AdaptableUnaryFunction>
+  struct transform_iterator_policies : public default_iterator_policies
+  {
+    transform_iterator_policies() { }
+    transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
+
+    template <class Reference, class Iterator>
+    Reference dereference(type<Reference>, const Iterator& i) const
+      { return m_f(*i); }
+
+    AdaptableUnaryFunction m_f;
+  };
+
+ +Next we need to create the traits class for our new iterator. In some +situations you may need to create a separate traits class for the +const and non-const iterator types, but here a single traits class +will do. The value_type and reference type of our +transform iterator will be the result_type of the function +object. The difference_type and iterator_category +will be the same as the adapted iterator. + +

+ +
+
+  template <class AdaptableUnaryFunction, class IteratorTraits>
+  struct transform_iterator_traits {
+    typedef typename AdaptableUnaryFunction::result_type value_type;
+    typedef value_type reference;
+    typedef value_type* pointer;
+    typedef typename IteratorTraits::difference_type difference_type;
+    typedef typename IteratorTraits::iterator_category iterator_category;
+  };
+
+ +The final step is to use the iterator_adaptor class to +construct our transform iterator. We will use the single iterator +adaptor version because we will not need to create both a mutable and +const version of the transform iterator. The transform iterator is +inherently a read-only iterator. The nicest way to package up our new +transform iterator is to create a type generator similar to +iterator_adaptor. The first template parameter will be the +type of the function object. The second parameter will be the adapted +iterator type. The third parameter is the trait class for +the adapted iterator. Inside the transform_iterators class +we use the transform_iterator_traits class defined above to +create the traits class for the new transform iterator. We then use +the iterator_adaptor class to extract the generated +iterator adaptor type. + +

+ +
+
+template <class AdaptableUnaryFunction,
+          class Iterator,
+          class Traits = std::iterator_traits<Iterator>
+         >
+struct transform_iterator
+{
+  typedef transform_iterator_traits<AdaptableUnaryFunction,Traits>
+    TransTraits;
+  typedef iterator_adaptor<Iterator, TransTraits,
+    transform_iterator_policies<AdaptableUnaryFunction> >::type type;
+};
+
+ +

+The following is a simple example of how to use the +transform_iterators class to iterate through a range of +numbers, multiplying each of them by 2 when they are dereferenced. + +

+ +
+
+#include <functional>
+#include <iostream>
+#include <boost/iterator_adaptors.hpp>
+
+int
+main(int, char*[])
+{
+  int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+  typedef std::binder1st< std::multiplies<int> > Function;
+  typedef boost::transform_iterator<Function, int*, 
+    boost::iterator<std::random_access_iterator_tag, int>
+  >::type doubling_iterator;
+
+  doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
+    i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
+
+  std::cout << "multiplying the array by 2:" << std::endl;
+  while (i != i_end)
+    std::cout << *i++ << " ";
+  std::cout << std::endl;
+
+  return 0;
+}
+
+ + +

The Indirect Iterator Adaptors

+ +It is not all that uncommon to create data structures that consist of +pointers to pointers. For such a structure it might be nice to have an +iterator that applies a double-dereference inside the +operator*(). The implementation of this is similar to the +transform_iterators[3]. When talking about a +data structure of pointers to pointers (or more generally, iterators +to iterators), we call the first level iterators the outer +iterators and the second level iterators the inner +iterators. For example, if the outer iterator type is T** +then the inner iterator type is T*. + +To implement the indirect adaptors, we first create a policies class +which does a double-dereference in the dereference() method. + +

+ +
+
+struct indirect_iterator_policies : public default_iterator_policies
+{
+    template <class Reference, class Iterator>
+    Reference dereference(type<Reference>, const Iterator& x) const
+        { return **x; }
+};
+
+ +We then create a traits class, including a template parameter for both +the inner and outer iterators and traits classes. The +difference_type and iterator_category come from the +outer iterator, while the value_type, pointer, and +reference types come from the inner iterator. + +

+ +
+
+template <class OuterIterator, class InnerIterator,
+          class OuterTraits = std::iterator_traits<OuterIterator>,
+          class InnerTraits = std::iterator_traits<InnerIterator>
+         >
+struct indirect_traits
+{
+    typedef typename OuterTraits::difference_type difference_type;
+    typedef typename InnerTraits::value_type value_type;
+    typedef typename InnerTraits::pointer pointer;
+    typedef typename InnerTraits::reference reference;
+    typedef typename OuterTraits::iterator_category iterator_category;
+};
+
+ +Lastly we wrap this up in two type generators: +indirect_iterator for creating a single indirect iterator +type, and indirect_iterators for creating an const/non-const +pair of indirect iterator types. We use the iterator_adaptor +and iterator_adaptors classes here to do most of the work. + +

+ +
+
+template <class OuterIterator, class InnerIterator,
+          class OuterTraits = std::iterator_traits<OuterIterator>,
+          class InnerTraits = std::iterator_traits<InnerIterator>
+         >
+struct indirect_iterator
+{
+    typedef iterator_adaptor<OuterIterator,
+        indirect_iterator_policies,
+        indirect_traits<OuterIterator, InnerIterator,
+                        OuterTraits, InnerTraits>
+    > type;
+};
+
+template <class OuterIterator,      // Mutable or Immutable, does not matter
+          class InnerIterator,      // Mutable
+          class ConstInnerIterator, // Immutable
+          class OuterTraits = std::iterator_traits<OuterIterator>,
+          class InnerTraits = std::iterator_traits<InnerIterator>,
+          class ConstInnerTraits = std::iterator_traits<ConstInnerIterator>
+         >
+struct indirect_iterators
+{
+    typedef iterator_adaptors<OuterIterator, OuterIterator,
+        indirect_traits<OuterIterator, InnerIterator,
+                        OuterTraits, InnerTraits>,
+        indirect_traits<OuterIterator, ConstInnerIterator,
+                        OuterTraits, ConstInnerTraits>,
+        indirect_iterator_policies
+        > Adaptors;
+    typedef typename Adaptors::iterator iterator;
+    typedef typename Adaptors::const_iterator const_iterator;
+};
+
+ + +

The Projection Iterator Adaptors

+ +The projection iterator adaptor is very similar to the transform +iterator, except for a subtle difference in the return type: the +tranform iterator returns the result of the unary function by value, +whereas the projection iterator returns the result by reference. +Therefore, these two adaptors cater to different kinds of unary +functions. Transform iterator caters to functions that create new +objects, whereas projection iterator caters to a function that somehow +obtains a reference to an object that already exists. An example of a +unary function that is suitable for use with the projection adaptor is +select1st_: + +

+ +
+
+template <class Pair>
+struct select1st_ 
+  : public std::unary_function<Pair, typename Pair::first_type>
+{
+  const typename Pair::first_type& operator()(const Pair& x) const {
+    return x.first;
+  }
+  typename Pair::first_type& operator()(Pair& x) const {
+    return x.first;
+  }
+};
+
+ +The implementation of projection iterator is as follows. First, the +policies class is the same as the transform iterator's policies class. + +

+ +
+
+template <class AdaptableUnaryFunction>
+struct projection_iterator_policies : public default_iterator_policies
+{
+    projection_iterator_policies() { }
+    projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
+
+    template <class Reference, class Iterator>
+    Reference dereference (type<Reference>, Iterator const& iter) const {
+        return m_f(*iter);
+    }
+
+    AdaptableUnaryFunction m_f;    
+};
+
+ +Next we have two traits classes. We use value_type& for the +reference type of the mutable projection iterator, and const +value_type& for the immutable projection iterator. + +

+ +
+
+template <class AdaptableUnaryFunction, class Traits>
+struct projection_iterator_traits {
+    typedef typename AdaptableUnaryFunction::result_type value_type;
+    typedef value_type& reference;
+    typedef value_type* pointer;
+    typedef typename Traits::difference_type difference_type;
+    typedef typename Traits::iterator_category iterator_category;
+};
+
+template <class AdaptableUnaryFunction, class Traits>
+struct const_projection_iterator_traits {
+    typedef typename AdaptableUnaryFunction::result_type value_type;
+    typedef value_type const& reference;
+    typedef value_type const* pointer;
+    typedef typename Traits::difference_type difference_type;
+    typedef typename Traits::iterator_category iterator_category;
+};
+
+ +And to finish up, we create three generator classes that +use iterator_adaptor to create the projection iterator +types. The class projection_iterator creates a mutable +projection iterator type. The class const_projection_iterator +creates an immutable projection iterator type, and +projection_iterators creates both mutable and immutable +projection iterator types. + +

+ +
+
+template <class AdaptableUnaryFunction, class Iterator,
+          class Traits = std::iterator_traits<Iterator>
+         >
+struct projection_iterator {
+    typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
+            Projection_Traits;
+    typedef iterator_adaptor<Iterator,
+            projection_iterator_policies<AdaptableUnaryFunction>,
+            Projection_Traits> type;
+};
+
+template <class AdaptableUnaryFunction, class Iterator,
+          class Traits = std::iterator_traits<Iterator>
+         >
+struct const_projection_iterator {
+    typedef const_projection_iterator_traits<AdaptableUnaryFunction,
+            Traits> Projection_Traits;
+    typedef iterator_adaptor<Iterator,
+            projection_iterator_policies<AdaptableUnaryFunction>,
+            Projection_Traits> type;
+};
+
+template <class AdaptableUnaryFunction, class Iterator, class ConstIterator,
+          class Traits = std::iterator_traits<Iterator>,
+          class ConstTraits = std::iterator_traits<ConstIterator>
+         >
+struct projection_iterators {
+    typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
+            Projection_Traits;
+    typedef const_projection_iterator_traits<AdaptableUnaryFunction,
+            ConstTraits> Const_Projection_Traits;
+    typedef iterator_adaptors<Iterator, ConstIterator,
+            Projection_Traits, Const_Projection_Traits,
+            projection_iterator_policies<AdaptableUnaryFunction> > Adaptors;
+    typedef typename Adaptors::iterator iterator;
+    typedef typename Adaptors::const_iterator const_iterator;
+};
+
+ + +

The Reverse Iterators Class

+ +

+Yes, there is already a reverse_iterator adaptor class +defined in the C++ Standard, but using the iterator_adaptors +class we can re-implement this classic adaptor in a more succinct and +elegant fashion. Also, this makes for a good example of using +iterator_adaptors that is in familiar territory. + +

+The first step is to create the Policies class. As in the +std::reverse_iterator class, we need to flip all the +operations of the iterator. Increment will become decrement, advancing +by n will become retreating by n, etc. + +

+ +
+
+struct reverse_iterator_policies
+{
+  template <class Reference, class Iterator>
+  Reference dereference(type<Reference>, const Iterator& x) const
+    { return *boost::prior(x); }
+    // this is equivalent to { Iterator tmp = x; return *--tmp; }
+    
+  template <class Iterator>
+  void increment(Iterator& x) const
+    { --x; }
+    
+  template <class Iterator>
+  void decrement(Iterator& x) const
+    { ++x; }
+    
+  template <class Iterator, class DifferenceType>
+  void advance(Iterator& x, DifferenceType n) const
+    { x -= n; }
+    
+  template <class Difference, class Iterator1, class Iterator2>
+  Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
+    { return x - y; }
+    
+  template <class Iterator1, class Iterator2>
+  bool equal(Iterator1& x, Iterator2& y) const
+    { return x == y; }
+    
+  template <class Iterator1, class Iterator2>
+  bool less(Iterator1& x, Iterator2& y) const
+    { return y < x; }
+};
+
+ +Since the traits of the reverse iterator adaptor will be the same as +the adapted iterator's traits, we do not need to create new traits +classes as was the case for transform_iterator. We can skip to +the final stage of creating a type generator class for our reverse +iterators using the iterator_adaptor class. + +

+ +
+
+template <class Iterator, class ConstIterator,
+          class Traits = std::iterator_traits<Iterator>, 
+          class ConstTraits = std::iterator_traits<ConstIterator>
+         >
+struct reverse_iterators
+{
+  typedef iterator_adaptors<Iterator,ConstIterator,Traits,ConstTraits,
+    reverse_iterator_policies> Adaptor;
+  typedef typename Adaptor::iterator iterator;
+  typedef typename Adaptor::const_iterator const_iterator;
+};
+
+ +A typical use of the reverse_iterators class is in +user-defined container types. You can use the +reverse_iterators class to generate the reverse iterators for +your container. + +

+ +
+
+class my_container {
+  ...
+  typedef ... iterator;
+  typedef ... const_iterator;
+
+  typedef reverse_iterators<iterator, const_iterator> RevIters;
+  typedef typename RevIters::iterator reverse_iterator;
+  typedef typename RevIters::const_iterator const_reverse_iterator;
+  ...
+};
+
+ + +

The Integer Range Class

+ +The iterator_adaptors class can not only be used for adapting +iterators, but it can also be used to take a non-iterator type and use +it to build an iterator. An especially simple example of this is +turning an integer type into an iterator, a counting iterator. The +builtin integer types of C++ are almost iterators. They have +operator++(), operator--(), etc. The one operator +they are lacking is the operator*(), which we will want to +simply return the current value of the integer. The following few +lines of code implement the policy and traits class for the counting +iterator. + +

+ +
+
+template <class IntegerType>
+struct counting_iterator_policies : public default_iterator_policies
+{
+  IntegerType dereference(type<IntegerType>, const IntegerType& i) const
+    { return i; }
+};
+template <class IntegerType>
+struct counting_iterator_traits {
+  typedef IntegerType value_type;
+  typedef IntegerType reference;
+  typedef value_type* pointer;
+  typedef std::ptrdiff_t difference_type;
+  typedef std::random_access_iterator_tag iterator_category;
+};
+
+ +Typically we will want to count the integers in some range, so a nice +interface would be to have a fake container that represents the range +of integers. The following is the definition of such a class called +integer_range. + +

+ +
+
+template <class IntegerType>
+struct integer_range {
+  typedef typename iterator_adaptor<IntegerType, 
+                           counting_iterator_traits<IntegerType>,
+                           counting_iterator_policies >::type iterator;
+  typedef iterator const_iterator;
+  typedef IntegerType value_type;
+  typedef std::ptrdiff_t difference_type;
+  typedef IntegerType reference;
+  typedef IntegerType* pointer;
+  typedef IntegerType size_type;
+
+  integer_range(IntegerType start, IntegerType finish)
+    : m_start(start), m_finish(finish) { }
+
+  iterator begin() const { return iterator(m_start); }
+  iterator end() const { return iterator(m_finish); }
+  size_type size() const { return m_finish - m_start; }
+  bool empty() const { return m_finish == m_start; }
+  void swap(integer_range& x) {
+    std::swap(m_start, x.m_start);
+    std::swap(m_finish, x.m_finish);
+  }
+protected:
+  IntegerType m_start, m_finish;
+};
+
+ +

+The following is an example of how to use the +integer_range class to count from 0 to 4. + +

+ +
+
+boost::integer_range<int> r(0,5);
+
+cout << "counting to from 0 to 4:" << endl;
+std::copy(r.begin(), r.end(), ostream_iterator<int>(cout, " "));
+cout << endl;
+
+ +

Challenge

+ +

+There is an unlimited number of ways the the +iterator_adaptors class can be used to create iterators. One +interesting exercise would be to re-implement the iterators of +std::list and std::slist using +iterator_adaptors, where the adapted Iterator types +would be node pointers. + + +

Notes

+ +

+[1] +If your compiler does not support partial specialization and hence +does not have a working std::iterator_traits class, you will +not be able to use the defaults and will need to supply your own +Traits and ConstTraits classes. + +

+[2] +The reference type could also be obtained from +std::iterator_traits, but that is not portable on compilers +that do not support partial specialization. + +

+[3] +It would have been more elegant to implement indirect_iterators +using transform_iterators, but for subtle reasons that would require +the use of boost::remove_cv which is not portable. + +

Implementation Notes

+ +The code is somewhat complicated because there are three iterator +adaptor class: forward_iterator_adaptor, +bidirectional_iterator_adaptor, and +random_access_iterator_adaptor. The alternative would be to +just have one iterator adaptor equivalent to the +random_access_iterator_adaptor. The reason for going with +the three adaptors is that according to 14.5.3p5 in the C++ Standard, +friend functions defined inside a template class body are instantiated +when the template class is instantiated. This means that if we only +used the one iterator adaptor, then if the adapted iterator did not +meet all of the requirements for a + +RandomAccessIterator then a compiler error should occur. Many +current compilers in fact do not instantiate the friend functions +unless used, so we could get away with the one iterator adaptor in +most cases. However, out of respect for the standard this implementation +uses the three adaptors. + + + +
+

Revised 27 Nov 2000

+

© Copyright Jeremy Siek 2000. Permission to copy, use, +modify, sell and distribute this document is granted provided this copyright +notice appears in all copies. This document is provided "as is" +without express or implied warranty, and with no claim as to its suitability for +any purpose.

+ + + +