diff --git a/doc/counting_iterator_eg.rst b/doc/counting_iterator_eg.rst new file mode 100644 index 0000000..5f6b3b3 --- /dev/null +++ b/doc/counting_iterator_eg.rst @@ -0,0 +1,40 @@ + +Example +....... + +This example fills an array with numbers and a second array with +pointers into the first array, using ``counting_iterator`` for both +tasks. Finally ``indirect_iterator`` is used to print out the numbers +into the first array via indirection through the second array. + +:: + + int N = 7; + std::vector numbers; + typedef std::vector::iterator n_iter; + std::copy(boost::counting_iterator(0), + boost::counting_iterator(N), + std::back_inserter(numbers)); + + std::vector::iterator> pointers; + std::copy(boost::make_counting_iterator(numbers.begin()), + boost::make_counting_iterator(numbers.end()), + std::back_inserter(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(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 + +The source code for this example can be found `here`__. + +__ ../example/counting_iterator_example.cpp + diff --git a/doc/filter_iterator_eg.rst b/doc/filter_iterator_eg.rst new file mode 100644 index 0000000..36448fe --- /dev/null +++ b/doc/filter_iterator_eg.rst @@ -0,0 +1,69 @@ + +Example +....... + +This example uses ``filter_iterator`` and then +``make_filter_iterator`` to output only the positive integers from an +array of integers. Then ``make_filter_iterator`` is is used to output +the integers greater than ``-2``. + +:: + + struct is_positive_number { + bool operator()(int x) { return 0 < x; } + }; + + int main() + { + int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 }; + const int N = sizeof(numbers_)/sizeof(int); + + typedef int* base_iterator; + base_iterator numbers(numbers_); + + // Example using filter_iterator + typedef boost::filter_iterator + FilterIter; + + is_positive_number predicate; + FilterIter filter_iter_first(predicate, numbers, numbers + N); + FilterIter filter_iter_last(predicate, numbers + N, numbers + N); + + std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + // Example using make_filter_iterator() + std::copy(boost::make_filter_iterator(numbers, numbers + N), + boost::make_filter_iterator(numbers + N, numbers + N), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + // Another example using make_filter_iterator() + std::copy( + boost::make_filter_iterator( + std::bind2nd(std::greater(), -2) + , numbers, numbers + N) + + , boost::make_filter_iterator( + std::bind2nd(std::greater(), -2) + , numbers + N, numbers + N) + + , std::ostream_iterator(std::cout, " ") + ); + + std::cout << std::endl; + + return boost::exit_success; + } + + +The output is:: + + 4 5 8 + 4 5 8 + 0 -1 4 5 8 + + +The source code for this example can be found `here`__. + +__ ../example/filter_iterator_example.cpp diff --git a/doc/function_output_iterator_eg.rst b/doc/function_output_iterator_eg.rst new file mode 100644 index 0000000..eb635df --- /dev/null +++ b/doc/function_output_iterator_eg.rst @@ -0,0 +1,35 @@ +Example +....... + +:: + + struct string_appender + { + string_appender(std::string& s) + : m_str(&s) + {} + + void operator()(const std::string& x) const + { + *m_str += x; + } + + std::string* m_str; + }; + + int main(int, char*[]) + { + std::vector x; + x.push_back("hello"); + x.push_back(" "); + x.push_back("world"); + x.push_back("!"); + + std::string s = ""; + std::copy(x.begin(), x.end(), + boost::make_function_output_iterator(string_appender(s))); + + std::cout << s << std::endl; + + return 0; + } diff --git a/doc/indirect_iterator_eg.rst b/doc/indirect_iterator_eg.rst new file mode 100644 index 0000000..356a2dd --- /dev/null +++ b/doc/indirect_iterator_eg.rst @@ -0,0 +1,69 @@ +Example +....... + +This example prints an array of characters, using +``indirect_iterator`` to access the array of characters through an +array of pointers. Next ``indirect_iterator`` is used with the +``transform`` algorithm to copy the characters (incremented by one) to +another array. A constant indirect iterator is used for the source and +a mutable indirect iterator is used for the destination. The last part +of the example prints the original array of characters, but this time +using the ``make_indirect_iterator`` helper function. + + +:: + + char characters[] = "abcdefg"; + const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char + char* pointers_to_chars[N]; // at the end. + for (int i = 0; i < N; ++i) + pointers_to_chars[i] = &characters[i]; + + // Example of using indirect_iterator + + boost::indirect_iterator + indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); + + std::copy(indirect_first, indirect_last, std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + + // Example of making mutable and constant indirect iterators + + char mutable_characters[N]; + char* pointers_to_mutable_chars[N]; + for (int j = 0; j < N; ++j) + pointers_to_mutable_chars[j] = &mutable_characters[j]; + + boost::indirect_iterator mutable_indirect_first(pointers_to_mutable_chars), + mutable_indirect_last(pointers_to_mutable_chars + N); + boost::indirect_iterator const_indirect_first(pointers_to_chars), + const_indirect_last(pointers_to_chars + N); + + std::transform(const_indirect_first, const_indirect_last, + mutable_indirect_first, std::bind1st(std::plus(), 1)); + + std::copy(mutable_indirect_first, mutable_indirect_last, + std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + + // Example of using make_indirect_iterator() + + std::copy(boost::make_indirect_iterator(pointers_to_chars), + boost::make_indirect_iterator(pointers_to_chars + N), + std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + +The output is:: + + a,b,c,d,e,f,g, + b,c,d,e,f,g,h, + a,b,c,d,e,f,g, + + +The source code for this example can be found `here`__. + +__ ../example/indirect_iterator_example.cpp + diff --git a/doc/interoperability-revisited.rst b/doc/interoperability-revisited.rst new file mode 100755 index 0000000..6754b9c --- /dev/null +++ b/doc/interoperability-revisited.rst @@ -0,0 +1,232 @@ +++++++++++++++++++++++++++++ + Interoperability Revisited +++++++++++++++++++++++++++++ + +:date: $Date$ +:copyright: Copyright Thomas Witt 2004. + + +Problem +======= + +The current iterator_facade specification makes it unneccessarily tedious to +implement interoperable iterators. + +In the following text a simplified example of the current iterator_facade specification is used to +illustrate the problem. + +In the current specification binary operators are implemented in the following way: + +template +struct Facade +{ +}; + +template +struct is_interoperable : + or_< + is_convertible + , is_convertible + > +{}; + +template< + class Derived1 + , class Derived2 +> +enable_if, bool> operator==( + Derived1 const& lhs + , Derived2 const& rhs +) +{ + return static_cast(lhs).equal_to(static_cast +{ + bool equal_to(Mutable const&); +}; + +struct Constant : Facade +{ + Constant(); + Constant(Constant const&); + Constant(Mutable const&); + + ... + + bool equal_to(Constant const&); +}; + +Constant c; +Mutable m; + +c == m; // ok, dispatched to Constant::equal_to +m == c; // !! error, dispatched to Mutable::equal_to + +Instead the following "slightly" more complicated implementation is neccessary + +struct Mutable : Facade +{ + template + enable_if || is_convertible, bool>::type equal_to(T const&); +}; + +struct Constant : Tag +{ + Constant(); + Constant(Constant const&); + Constant(Mutable const&); + + template + enable_if || is_convertible, bool>::type equal_to(T const&); +}; + +Beside the fact that the code is significantly more complex to understand and to teach there is +a major design problem lurking here. Note that in both types equal_to is a function template with +an unconstrained argument T. This is neccessary so that further types can be made interoperable with +Mutable or Constant. Would Mutable be defined as + +struct Mutable : Facade +{ + bool equal_to(Mutable const&); + bool equal_to(Constant const&); +}; + +Constant and Mutable would still be interoperable but no further interoperable could be added +without changing Mutable. Even if this would be considered acceptable the current specification forces +a two way dependency between interoperable types. Note in the templated equal_to case this dependency +is implicitly created when specializing equal_to. + +Solution +======== + +The two way dependency can be avoided by enabling type conversion in the binary operator +implementation. Note that this is the usual way interoperability betwween types is achieved +for binary operators and one reason why binary operators are usually implemented as non-members. + +A simple implementation of this strategy would look like this + +template< + class T1 + , class T2 +> +struct interoperable_base : + if_< + is_convertible< + T2 + , T1 + > + , T1 + , T2> +{}; + + +template< + class Derived1 + , class Derived2 +> +enable_if, bool> operator==( + Derived1 const& lhs + , Derived2 const& rhs +) +{ + typedef interoperable_base< + Derived1 + , Derived2 + >::type Base; + + return static_cast(lhs).equal_to(static_cast +enable_if, bool> operator==( + Derived1 const& lhs + , Derived2 const& rhs +) +{ + return static_cast(lhs).equal_to(static_cast +enable_if, bool> operator==( + Derived1 const& lhs + , Derived2 const& rhs +) +{ + return static_cast(rhs).equal_to(static_cast +{ + Constant(); + Constant(Constant const&); + Constant(Mutable const&); + + ... + + bool equal_to(Constant const&); + bool equal_to(Mutable const&); +}; + +c == m; // ok, dispatched to Constant::equal_to(Mutable const&), no conversion +m == c; // ok, dispatched to Constant::equal_to(Mutable const&), no conversion + +This definition of operator== introduces a possible ambiguity when both types are convertible +to each other. I don't think this is a problem as this behaviour is the same with concrete types. +I.e. + +struct A {}; + +bool operator==(A, A); + +struct B { B(A); }; + +bool operator==(B, B); + +A a; +B b(a); + +a == b; // error, ambiguous overload + +Effect +====== + +Iterator implementations using iterator_facade look exactly as if they were +"hand-implemented" (I am working on better wording). + +a) Less burden for the user + +b) The definition (standardese) of specialized adpters might be easier + (This has to be proved yet) \ No newline at end of file diff --git a/doc/make_counting_iterator.rst b/doc/make_counting_iterator.rst new file mode 100755 index 0000000..f1c9ae9 --- /dev/null +++ b/doc/make_counting_iterator.rst @@ -0,0 +1,9 @@ + +:: + + template + counting_iterator make_counting_iterator(Incrementable x); + +:Returns: An instance of ``counting_iterator`` + with ``current`` constructed from ``x``. + diff --git a/doc/make_reverse_iterator.rst b/doc/make_reverse_iterator.rst new file mode 100644 index 0000000..c3e20ed --- /dev/null +++ b/doc/make_reverse_iterator.rst @@ -0,0 +1,9 @@ +:: + + template + reverse_iteratorn + make_reverse_iterator(BidirectionalIterator x); + +:Returns: An instance of ``reverse_iterator`` + with a ``current`` constructed from ``x``. + diff --git a/doc/make_transform_iterator.rst b/doc/make_transform_iterator.rst new file mode 100755 index 0000000..5d5f1b2 --- /dev/null +++ b/doc/make_transform_iterator.rst @@ -0,0 +1,19 @@ +:: + + template + transform_iterator + make_transform_iterator(Iterator it, UnaryFunction fun); + +:Returns: An instance of ``transform_iterator`` with ``m_f`` + initialized to ``f`` and ``m_iterator`` initialized to ``x``. + + + +:: + + template + transform_iterator + make_transform_iterator(Iterator it); + +:Returns: An instance of ``transform_iterator`` with ``m_f`` + default constructed and ``m_iterator`` initialized to ``x``. diff --git a/doc/permutation_iterator_eg.rst b/doc/permutation_iterator_eg.rst new file mode 100644 index 0000000..b493c7a --- /dev/null +++ b/doc/permutation_iterator_eg.rst @@ -0,0 +1,67 @@ +:: + + using namespace boost; + int i = 0; + + typedef std::vector< int > element_range_type; + typedef std::list< int > index_type; + + static const int element_range_size = 10; + static const int index_size = 4; + + element_range_type elements( element_range_size ); + for(element_range_type::iterator el_it = elements.begin() ; el_it != elements.end() ; ++el_it) + *el_it = std::distance(elements.begin(), el_it); + + index_type indices( index_size ); + for(index_type::iterator i_it = indices.begin() ; i_it != indices.end() ; ++i_it ) + *i_it = element_range_size - index_size + std::distance(indices.begin(), i_it); + std::reverse( indices.begin(), indices.end() ); + + typedef permutation_iterator< element_range_type::iterator, index_type::iterator > permutation_type; + permutation_type begin = make_permutation_iterator( elements.begin(), indices.begin() ); + permutation_type it = begin; + permutation_type end = make_permutation_iterator( elements.begin(), indices.end() ); + + std::cout << "The original range is : "; + std::copy( elements.begin(), elements.end(), std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "The reindexing scheme is : "; + std::copy( indices.begin(), indices.end(), std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "The permutated range is : "; + std::copy( begin, end, std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "Elements at even indices in the permutation : "; + it = begin; + for(i = 0; i < index_size / 2 ; ++i, it+=2 ) std::cout << *it << " "; + std::cout << "\n"; + + std::cout << "Permutation backwards : "; + it = begin + (index_size); + assert( it != begin ); + for( ; it-- != begin ; ) std::cout << *it << " "; + std::cout << "\n"; + + std::cout << "Iterate backward with stride 2 : "; + it = begin + (index_size - 1); + for(i = 0 ; i < index_size / 2 ; ++i, it-=2 ) std::cout << *it << " "; + std::cout << "\n"; + + +The output is:: + + The original range is : 0 1 2 3 4 5 6 7 8 9 + The reindexing scheme is : 9 8 7 6 + The permutated range is : 9 8 7 6 + Elements at even indices in the permutation : 9 7 + Permutation backwards : 6 7 8 9 + Iterate backward with stride 2 : 6 8 + + +The source code for this example can be found `here`__. + +__ ../example/permutation_iterator_example.cpp diff --git a/doc/reverse_iterator_eg.rst b/doc/reverse_iterator_eg.rst new file mode 100644 index 0000000..7923f2f --- /dev/null +++ b/doc/reverse_iterator_eg.rst @@ -0,0 +1,42 @@ + +Example +....... + +The following example prints an array of characters in reverse order +using ``reverse_iterator``. + +:: + + char letters_[] = "hello world!"; + const int N = sizeof(letters_)/sizeof(char) - 1; + typedef char* base_iterator; + base_iterator letters(letters_); + std::cout << "original sequence of letters:\t\t\t" << letters_ << std::endl; + + boost::reverse_iterator + reverse_letters_first(letters + N), + reverse_letters_last(letters); + + std::cout << "sequence in reverse order:\t\t\t"; + std::copy(reverse_letters_first, reverse_letters_last, + std::ostream_iterator(std::cout)); + std::cout << std::endl; + + std::cout << "sequence in double-reversed (normal) order:\t"; + std::copy(boost::make_reverse_iterator(reverse_letters_last), + boost::make_reverse_iterator(reverse_letters_first), + std::ostream_iterator(std::cout)); + std::cout << std::endl; + + + +The output is:: + + original sequence of letters: hello world! + sequence in reverse order: !dlrow olleh + sequence in double-reversed (normal) order: hello world! + + +The source code for this example can be found `here`__. + +__ ../example/reverse_iterator_example.cpp diff --git a/doc/transform_iterator_eg.rst b/doc/transform_iterator_eg.rst new file mode 100755 index 0000000..a6629ca --- /dev/null +++ b/doc/transform_iterator_eg.rst @@ -0,0 +1,42 @@ +Example +....... + +This is a simple example of using the transform_iterators class to +generate iterators that multiply (or add to) the value returned by +dereferencing the iterator. It would be cooler to use lambda library +in this example. + +:: + + int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + const int N = sizeof(x)/sizeof(int); + + typedef boost::binder1st< std::multiplies > Function; + typedef boost::transform_iterator doubling_iterator; + + doubling_iterator i(x, boost::bind1st(std::multiplies(), 2)), + i_end(x + N, boost::bind1st(std::multiplies(), 2)); + + std::cout << "multiplying the array by 2:" << std::endl; + while (i != i_end) + std::cout << *i++ << " "; + std::cout << std::endl; + + std::cout << "adding 4 to each element in the array:" << std::endl; + std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus(), 4)), + boost::make_transform_iterator(x + N, boost::bind1st(std::plus(), 4)), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + +The output is:: + + multiplying the array by 2: + 2 4 6 8 10 12 14 16 + adding 4 to each element in the array: + 5 6 7 8 9 10 11 12 + + +The source code for this example can be found `here`__. + +__ ../example/transform_iterator_example.cpp diff --git a/example/counting_iterator_example.cpp b/example/counting_iterator_example.cpp new file mode 100644 index 0000000..4113075 --- /dev/null +++ b/example/counting_iterator_example.cpp @@ -0,0 +1,54 @@ +// (C) Copyright Jeremy Siek 2000-2004. +// 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. + + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int, char*[]) +{ + // Example of using counting_iterator + std::cout << "counting from 0 to 4:" << std::endl; + boost::counting_iterator first(0), last(4); + std::copy(first, last, std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + // Example of using counting iterator to create an array of pointers. + int N = 7; + std::vector numbers; + typedef std::vector::iterator n_iter; + // Fill "numbers" array with [0,N) + std::copy( + boost::counting_iterator(0) + , boost::counting_iterator(N) + , std::back_inserter(numbers)); + + std::vector::iterator> pointers; + + // Use counting iterator to fill in the array of pointers. + // causes an ICE with MSVC6 + 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(std::cout, " ")); + std::cout << std::endl; + + return boost::exit_success; +} diff --git a/example/filter_iterator_example.cpp b/example/filter_iterator_example.cpp new file mode 100644 index 0000000..5748daa --- /dev/null +++ b/example/filter_iterator_example.cpp @@ -0,0 +1,60 @@ +// (C) Copyright Jeremy Siek 1999-2004. +// 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. + +#include +#include +#include +#include +#include +#include // for exit_success + +struct is_positive_number { + bool operator()(int x) { return 0 < x; } +}; + +int main() +{ + int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 }; + const int N = sizeof(numbers_)/sizeof(int); + + typedef int* base_iterator; + base_iterator numbers(numbers_); + + // Example using make_filter_iterator() + std::copy(boost::make_filter_iterator(numbers, numbers + N), + boost::make_filter_iterator(numbers + N, numbers + N), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + // Example using filter_iterator + typedef boost::filter_iterator + FilterIter; + + is_positive_number predicate; + FilterIter filter_iter_first(predicate, numbers, numbers + N); + FilterIter filter_iter_last(predicate, numbers + N, numbers + N); + + std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + // Another example using make_filter_iterator() + std::copy( + boost::make_filter_iterator( + std::bind2nd(std::greater(), -2) + , numbers, numbers + N) + + , boost::make_filter_iterator( + std::bind2nd(std::greater(), -2) + , numbers + N, numbers + N) + + , std::ostream_iterator(std::cout, " ") + ); + + std::cout << std::endl; + + return boost::exit_success; +} diff --git a/example/function_output_iterator_example.cpp b/example/function_output_iterator_example.cpp new file mode 100644 index 0000000..de0feae --- /dev/null +++ b/example/function_output_iterator_example.cpp @@ -0,0 +1,48 @@ +// (C) Copyright Jeremy Siek 2001-2004. +// 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. + +// Revision History: + +// 27 Feb 2001 Jeremy Siek +// Initial checkin. + +#include +#include +#include + +#include + +struct string_appender +{ + string_appender(std::string& s) + : m_str(&s) + {} + + void operator()(const std::string& x) const + { + *m_str += x; + } + + std::string* m_str; +}; + +int main(int, char*[]) +{ + std::vector x; + x.push_back("hello"); + x.push_back(" "); + x.push_back("world"); + x.push_back("!"); + + std::string s = ""; + std::copy(x.begin(), x.end(), + boost::make_function_output_iterator(string_appender(s))); + + std::cout << s << std::endl; + + return 0; +} diff --git a/example/indirect_iterator_example.cpp b/example/indirect_iterator_example.cpp new file mode 100644 index 0000000..7d74072 --- /dev/null +++ b/example/indirect_iterator_example.cpp @@ -0,0 +1,61 @@ +// (C) Copyright Jeremy Siek 2000-2004. +// 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. + +#include +#include +#include +#include +#include +#include +#include + +int main(int, char*[]) +{ + char characters[] = "abcdefg"; + const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char + char* pointers_to_chars[N]; // at the end. + for (int i = 0; i < N; ++i) + pointers_to_chars[i] = &characters[i]; + + // Example of using indirect_iterator + + boost::indirect_iterator + indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); + + std::copy(indirect_first, indirect_last, std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + + // Example of making mutable and constant indirect iterators + + char mutable_characters[N]; + char* pointers_to_mutable_chars[N]; + for (int j = 0; j < N; ++j) + pointers_to_mutable_chars[j] = &mutable_characters[j]; + + boost::indirect_iterator mutable_indirect_first(pointers_to_mutable_chars), + mutable_indirect_last(pointers_to_mutable_chars + N); + boost::indirect_iterator const_indirect_first(pointers_to_chars), + const_indirect_last(pointers_to_chars + N); + + std::transform(const_indirect_first, const_indirect_last, + mutable_indirect_first, std::bind1st(std::plus(), 1)); + + std::copy(mutable_indirect_first, mutable_indirect_last, + std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + + // Example of using make_indirect_iterator() + + std::copy(boost::make_indirect_iterator(pointers_to_chars), + boost::make_indirect_iterator(pointers_to_chars + N), + std::ostream_iterator(std::cout, ",")); + std::cout << std::endl; + + return 0; +} diff --git a/example/node.hpp b/example/node.hpp new file mode 100755 index 0000000..4e80d96 --- /dev/null +++ b/example/node.hpp @@ -0,0 +1,60 @@ +// 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_DWA2004110_HPP +# define NODE_DWA2004110_HPP + +# include + +// Polymorphic list node base class + +struct node_base +{ + node_base() : m_next(0) {} + + virtual ~node_base() + { + delete m_next; + } + + node_base* next() const + { + return m_next; + } + + virtual void print(std::ostream& s) const = 0; + virtual void double_me() = 0; + + void append(node_base* p) + { + if (m_next) + m_next->append(p); + else + m_next = p; + } + + private: + node_base* m_next; +}; + +inline std::ostream& operator<<(std::ostream& s, node_base const& n) +{ + n.print(s); + return s; +} + +template +struct node : node_base +{ + node(T x) + : m_value(x) + {} + + void print(std::ostream& s) const { s << this->m_value; } + void double_me() { m_value += m_value; } + + private: + T m_value; +}; + +#endif // NODE_DWA2004110_HPP diff --git a/example/node_iterator1.cpp b/example/node_iterator1.cpp new file mode 100755 index 0000000..6411b03 --- /dev/null +++ b/example/node_iterator1.cpp @@ -0,0 +1,34 @@ +// 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_iterator1.hpp" +#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)); + + 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() + , std::mem_fun_ref(&node_base::double_me) + ); + + std::copy( + node_iterator(nodes.get()), node_iterator() + , std::ostream_iterator(std::cout, "/") + ); + std::cout << std::endl; +} diff --git a/example/node_iterator1.hpp b/example/node_iterator1.hpp new file mode 100755 index 0000000..1188c7c --- /dev/null +++ b/example/node_iterator1.hpp @@ -0,0 +1,42 @@ +// 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_ITERATOR1_DWA2004110_HPP +# define NODE_ITERATOR1_DWA2004110_HPP + +# include "node.hpp" +# include + +class node_iterator + : public boost::iterator_facade< + node_iterator + , node_base + , boost::forward_traversal_tag + > +{ + public: + node_iterator() + : m_node(0) + {} + + explicit node_iterator(node_base* p) + : m_node(p) + {} + + private: + friend class boost::iterator_core_access; + + void increment() + { m_node = m_node->next(); } + + bool equal(node_iterator const& other) const + { return this->m_node == other.m_node; } + + node_base& dereference() const + { return *m_node; } + + node_base* m_node; +}; + + +#endif // NODE_ITERATOR1_DWA2004110_HPP diff --git a/example/node_iterator2.cpp b/example/node_iterator2.cpp new file mode 100755 index 0000000..62211b2 --- /dev/null +++ b/example/node_iterator2.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_iterator2.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_iterator2.hpp b/example/node_iterator2.hpp new file mode 100755 index 0000000..22c9bf2 --- /dev/null +++ b/example/node_iterator2.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_ITERATOR2_DWA2004110_HPP +# define NODE_ITERATOR2_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() { m_node = m_node->next(); } +}; + +typedef node_iter node_iterator; +typedef node_iter node_const_iterator; + +#endif // NODE_ITERATOR2_DWA2004110_HPP 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 diff --git a/example/permutation_iterator_example.cpp b/example/permutation_iterator_example.cpp new file mode 100644 index 0000000..195f39d --- /dev/null +++ b/example/permutation_iterator_example.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + + +int main() { + using namespace boost; + int i = 0; + + typedef std::vector< int > element_range_type; + typedef std::list< int > index_type; + + static const int element_range_size = 10; + static const int index_size = 4; + + element_range_type elements( element_range_size ); + for(element_range_type::iterator el_it = elements.begin() ; el_it != elements.end() ; ++el_it) + *el_it = std::distance(elements.begin(), el_it); + + index_type indices( index_size ); + for(index_type::iterator i_it = indices.begin() ; i_it != indices.end() ; ++i_it ) + *i_it = element_range_size - index_size + std::distance(indices.begin(), i_it); + std::reverse( indices.begin(), indices.end() ); + + typedef permutation_iterator< element_range_type::iterator, index_type::iterator > permutation_type; + permutation_type begin = make_permutation_iterator( elements.begin(), indices.begin() ); + permutation_type it = begin; + permutation_type end = make_permutation_iterator( elements.begin(), indices.end() ); + + std::cout << "The original range is : "; + std::copy( elements.begin(), elements.end(), std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "The reindexing scheme is : "; + std::copy( indices.begin(), indices.end(), std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "The permutated range is : "; + std::copy( begin, end, std::ostream_iterator< int >( std::cout, " " ) ); + std::cout << "\n"; + + std::cout << "Elements at even indices in the permutation : "; + it = begin; + for(i = 0; i < index_size / 2 ; ++i, it+=2 ) std::cout << *it << " "; + std::cout << "\n"; + + std::cout << "Permutation backwards : "; + it = begin + (index_size); + assert( it != begin ); + for( ; it-- != begin ; ) std::cout << *it << " "; + std::cout << "\n"; + + std::cout << "Iterate backward with stride 2 : "; + it = begin + (index_size - 1); + for(i = 0 ; i < index_size / 2 ; ++i, it-=2 ) std::cout << *it << " "; + std::cout << "\n"; + + return boost::exit_success; +} diff --git a/example/reverse_iterator_example.cpp b/example/reverse_iterator_example.cpp new file mode 100644 index 0000000..34c14a8 --- /dev/null +++ b/example/reverse_iterator_example.cpp @@ -0,0 +1,43 @@ +// (C) Copyright Jeremy Siek 2000-2004. +// 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. + +#include +#include +#include +#include +#include + +int main(int, char*[]) +{ + char letters_[] = "hello world!"; + const int N = sizeof(letters_)/sizeof(char) - 1; + typedef char* base_iterator; + base_iterator letters(letters_); + + std::cout << "original sequence of letters:\t\t\t" + << letters_ << std::endl; + + // Use reverse_iterator to print a sequence of letters in reverse + // order. + + boost::reverse_iterator + reverse_letters_first(letters + N), + reverse_letters_last(letters); + + std::cout << "sequence in reverse order:\t\t\t"; + std::copy(reverse_letters_first, reverse_letters_last, + std::ostream_iterator(std::cout)); + std::cout << std::endl; + + std::cout << "sequence in double-reversed (normal) order:\t"; + std::copy(boost::make_reverse_iterator(reverse_letters_last), + boost::make_reverse_iterator(reverse_letters_first), + std::ostream_iterator(std::cout)); + std::cout << std::endl; + + return boost::exit_success; +} diff --git a/example/transform_iterator_example.cpp b/example/transform_iterator_example.cpp new file mode 100644 index 0000000..4733997 --- /dev/null +++ b/example/transform_iterator_example.cpp @@ -0,0 +1,78 @@ +// (C) Copyright Jeremy Siek 2000-2004. +// 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. + + +#include +#include +#include +#include + +// What a bummer. We can't use std::binder1st with transform iterator +// because it does not have a default constructor. Here's a version +// that does. + +namespace boost { + + template + class binder1st + : public std::unary_function { + protected: + Operation op; + typename Operation::first_argument_type value; + public: + binder1st() { } // this had to be added! + binder1st(const Operation& x, + const typename Operation::first_argument_type& y) + : op(x), value(y) {} + typename Operation::result_type + operator()(const typename Operation::second_argument_type& x) const { + return op(value, x); + } + }; + + template + inline binder1st bind1st(const Operation& op, const T& x) { + typedef typename Operation::first_argument_type arg1_type; + return binder1st(op, arg1_type(x)); + } + +} // namespace boost + +int +main(int, char*[]) +{ + // This is a simple example of using the transform_iterators class to + // generate iterators that multiply the value returned by dereferencing + // the iterator. In this case we are multiplying by 2. + // Would be cooler to use lambda library in this example. + + int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + const int N = sizeof(x)/sizeof(int); + + typedef boost::binder1st< std::multiplies > Function; + typedef boost::transform_iterator doubling_iterator; + + doubling_iterator i(x, boost::bind1st(std::multiplies(), 2)), + i_end(x + N, boost::bind1st(std::multiplies(), 2)); + + std::cout << "multiplying the array by 2:" << std::endl; + while (i != i_end) + std::cout << *i++ << " "; + std::cout << std::endl; + + std::cout << "adding 4 to each element in the array:" << std::endl; + + std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus(), 4)), + boost::make_transform_iterator(x + N, boost::bind1st(std::plus(), 4)), + std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + return 0; +} + + diff --git a/test/pointee.cpp b/test/pointee.cpp new file mode 100755 index 0000000..b39fce1 --- /dev/null +++ b/test/pointee.cpp @@ -0,0 +1,72 @@ +// 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 +#include +#include "static_assert_same.hpp" +#include +#include + +template +struct proxy_ptr +{ + typedef T element_type; + struct proxy + { + operator Ref() const; + }; + proxy operator*() const; +}; + +template +struct proxy_ref_ptr : proxy_ptr +{ +}; + +template +struct proxy_value_ptr : proxy_ptr +{ + typedef typename boost::add_const::type element_type; +}; + +struct X { + template X(T const&); + template operator T&() const; +}; + +BOOST_TT_BROKEN_COMPILER_SPEC(X) + +int main() +{ + STATIC_ASSERT_SAME(boost::pointee >::type, int); + STATIC_ASSERT_SAME(boost::pointee >::type, X); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee::type, int); + STATIC_ASSERT_SAME(boost::pointee::type, int const); + + STATIC_ASSERT_SAME(boost::pointee::type, X); + STATIC_ASSERT_SAME(boost::pointee::type, X const); + + STATIC_ASSERT_SAME(boost::pointee >::type, int); + STATIC_ASSERT_SAME(boost::pointee >::type, X); + + STATIC_ASSERT_SAME(boost::pointee >::type, int const); + STATIC_ASSERT_SAME(boost::pointee >::type, X const); + + STATIC_ASSERT_SAME(boost::pointee::iterator >::type, int); + STATIC_ASSERT_SAME(boost::pointee::iterator >::type, X); + + STATIC_ASSERT_SAME(boost::pointee::const_iterator >::type, int const); + STATIC_ASSERT_SAME(boost::pointee::const_iterator >::type, X const); + return 0; +}