| 1 | // Copyright Louis Dionne 2012. Use, modification and distribution is subject
 | 
|---|
| 2 | // to the Boost Software License, Version 1.0. (See accompanying file
 | 
|---|
| 3 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
|---|
| 4 | 
 | 
|---|
| 5 | #include <boost/iterator/transform_output_iterator.hpp>
 | 
|---|
| 6 | #include <boost/concept/assert.hpp>
 | 
|---|
| 7 | #include <boost/concept/usage.hpp>
 | 
|---|
| 8 | #include <boost/concept_archetype.hpp>
 | 
|---|
| 9 | #include <boost/concept_check.hpp>
 | 
|---|
| 10 | #include <boost/iterator/counting_iterator.hpp>
 | 
|---|
| 11 | #include <boost/iterator/iterator_concepts.hpp>
 | 
|---|
| 12 | #include <boost/iterator/iterator_traits.hpp>
 | 
|---|
| 13 | 
 | 
|---|
| 14 | #include <algorithm>
 | 
|---|
| 15 | #include <cassert>
 | 
|---|
| 16 | #include <iterator>
 | 
|---|
| 17 | #include <string>
 | 
|---|
| 18 | #include <vector>
 | 
|---|
| 19 | 
 | 
|---|
| 20 | 
 | 
|---|
| 21 | namespace transform_output_iterator_test {
 | 
|---|
| 22 | 
 | 
|---|
| 23 | template <typename Iterator, typename OutputType = typename
 | 
|---|
| 24 |                                 boost::iterator_value<Iterator>::type>
 | 
|---|
| 25 | struct test_concepts {
 | 
|---|
| 26 |     BOOST_CONCEPT_USAGE(test_concepts) {
 | 
|---|
| 27 |         BOOST_CONCEPT_ASSERT((boost::OutputIterator<
 | 
|---|
| 28 |                                 boost::transform_output_iterator<
 | 
|---|
| 29 |                                     OutputType (*)(OutputType),
 | 
|---|
| 30 |                                     Iterator
 | 
|---|
| 31 |                                 >,
 | 
|---|
| 32 |                                 OutputType
 | 
|---|
| 33 |                             >));
 | 
|---|
| 34 | 
 | 
|---|
| 35 |         BOOST_CONCEPT_ASSERT((boost_concepts::WritableIterator<
 | 
|---|
| 36 |                                 boost::transform_output_iterator<
 | 
|---|
| 37 |                                     OutputType (*)(OutputType),
 | 
|---|
| 38 |                                     Iterator
 | 
|---|
| 39 |                                 >,
 | 
|---|
| 40 |                                 OutputType
 | 
|---|
| 41 |                             >));
 | 
|---|
| 42 | 
 | 
|---|
| 43 |         BOOST_CONCEPT_ASSERT((boost_concepts::IncrementableIterator<
 | 
|---|
| 44 |                                 boost::transform_output_iterator<
 | 
|---|
| 45 |                                     OutputType (*)(OutputType),
 | 
|---|
| 46 |                                     Iterator
 | 
|---|
| 47 |                                 >
 | 
|---|
| 48 |                             >));
 | 
|---|
| 49 |     }
 | 
|---|
| 50 | };
 | 
|---|
| 51 | 
 | 
|---|
| 52 | struct dummy { };
 | 
|---|
| 53 | BOOST_CONCEPT_ASSERT((
 | 
|---|
| 54 |     test_concepts<boost::output_iterator_archetype<dummy>, dummy>
 | 
|---|
| 55 | ));
 | 
|---|
| 56 | BOOST_CONCEPT_ASSERT((
 | 
|---|
| 57 |     test_concepts<boost::input_output_iterator_archetype<dummy>, dummy>
 | 
|---|
| 58 | ));
 | 
|---|
| 59 | BOOST_CONCEPT_ASSERT((
 | 
|---|
| 60 |     test_concepts<boost::mutable_forward_iterator_archetype<dummy> >
 | 
|---|
| 61 | ));
 | 
|---|
| 62 | BOOST_CONCEPT_ASSERT((
 | 
|---|
| 63 |     test_concepts<boost::mutable_bidirectional_iterator_archetype<dummy> >
 | 
|---|
| 64 | ));
 | 
|---|
| 65 | BOOST_CONCEPT_ASSERT((
 | 
|---|
| 66 |     test_concepts<boost::mutable_random_access_iterator_archetype<dummy> >
 | 
|---|
| 67 | ));
 | 
|---|
| 68 | 
 | 
|---|
| 69 | template <typename T = int>
 | 
|---|
| 70 | struct Multiply {
 | 
|---|
| 71 |     T n_;
 | 
|---|
| 72 |     Multiply(T n) : n_(n) { }
 | 
|---|
| 73 |     T operator()(T val) const {
 | 
|---|
| 74 |         return val * n_;
 | 
|---|
| 75 |     }
 | 
|---|
| 76 | };
 | 
|---|
| 77 | 
 | 
|---|
| 78 | template <typename T = int>
 | 
|---|
| 79 | struct Add {
 | 
|---|
| 80 |     T n_;
 | 
|---|
| 81 |     Add(T n) : n_(n) { }
 | 
|---|
| 82 |     T operator()(T val) const {
 | 
|---|
| 83 |         return val + n_;
 | 
|---|
| 84 |     }
 | 
|---|
| 85 | };
 | 
|---|
| 86 | 
 | 
|---|
| 87 | void should_transform_output() {
 | 
|---|
| 88 |     std::vector<int> actual, expected;
 | 
|---|
| 89 |     std::copy(boost::counting_iterator<int>(0),
 | 
|---|
| 90 |               boost::counting_iterator<int>(10),
 | 
|---|
| 91 |               boost::make_transform_output_iterator(
 | 
|---|
| 92 |                                     Add<>(10), std::back_inserter(actual)));
 | 
|---|
| 93 | 
 | 
|---|
| 94 |     std::copy(boost::counting_iterator<int>(10),
 | 
|---|
| 95 |               boost::counting_iterator<int>(20),
 | 
|---|
| 96 |               std::back_inserter(expected));
 | 
|---|
| 97 | 
 | 
|---|
| 98 |     assert(actual == expected);
 | 
|---|
| 99 | }
 | 
|---|
| 100 | 
 | 
|---|
| 101 | void should_allow_chaining() {
 | 
|---|
| 102 |     std::vector<int> actual, expected;
 | 
|---|
| 103 | 
 | 
|---|
| 104 |     boost::transform_output_iterator<Multiply<>,
 | 
|---|
| 105 |         boost::transform_output_iterator<Add<>,
 | 
|---|
| 106 |             std::back_insert_iterator<std::vector<int> > > > output =
 | 
|---|
| 107 |             boost::make_transform_output_iterator(
 | 
|---|
| 108 |                 Multiply<>(2),std::back_inserter(actual)).and_then(Add<>(10));
 | 
|---|
| 109 | 
 | 
|---|
| 110 |     std::copy(boost::counting_iterator<int>(0),
 | 
|---|
| 111 |               boost::counting_iterator<int>(5),
 | 
|---|
| 112 |               output);
 | 
|---|
| 113 | 
 | 
|---|
| 114 |     expected.push_back(0 * 2 + 10);
 | 
|---|
| 115 |     expected.push_back(1 * 2 + 10);
 | 
|---|
| 116 |     expected.push_back(2 * 2 + 10);
 | 
|---|
| 117 |     expected.push_back(3 * 2 + 10);
 | 
|---|
| 118 |     expected.push_back(4 * 2 + 10);
 | 
|---|
| 119 | 
 | 
|---|
| 120 |     assert(actual == expected);
 | 
|---|
| 121 | }
 | 
|---|
| 122 | 
 | 
|---|
| 123 | void should_work_for_const_iterator_if_wrapped_iter_has_const_deref() {
 | 
|---|
| 124 |     typedef boost::transform_output_iterator<Multiply<>,
 | 
|---|
| 125 |                 std::vector<int>::iterator> OutputIter;
 | 
|---|
| 126 |     std::vector<int> actual(1), expected;
 | 
|---|
| 127 |     OutputIter const out(Multiply<>(2), actual.begin());
 | 
|---|
| 128 |     *out = 3;
 | 
|---|
| 129 | 
 | 
|---|
| 130 |     expected.push_back(2 * 3);
 | 
|---|
| 131 | 
 | 
|---|
| 132 |     assert(actual == expected);
 | 
|---|
| 133 | }
 | 
|---|
| 134 | 
 | 
|---|
| 135 | void chain_performs_operation_in_right_order() {
 | 
|---|
| 136 |     std::string actual;
 | 
|---|
| 137 |     typedef Add<std::string> Append;
 | 
|---|
| 138 |     *boost::make_transform_output_iterator(Append("a"), &actual).
 | 
|---|
| 139 |                                   and_then(Append("b"))
 | 
|---|
| 140 |                                  .and_then(Append("c"))
 | 
|---|
| 141 |                                  .and_then(Append("d")) = "";
 | 
|---|
| 142 | 
 | 
|---|
| 143 |     assert(actual == "abcd");
 | 
|---|
| 144 | }
 | 
|---|
| 145 | 
 | 
|---|
| 146 | } // end transform_output_iterator_test namespace
 | 
|---|
| 147 | 
 | 
|---|
| 148 | 
 | 
|---|
| 149 | int main() {
 | 
|---|
| 150 |     using namespace transform_output_iterator_test;
 | 
|---|
| 151 |     should_transform_output();
 | 
|---|
| 152 |     should_allow_chaining();
 | 
|---|
| 153 |     should_work_for_const_iterator_if_wrapped_iter_has_const_deref();
 | 
|---|
| 154 |     chain_performs_operation_in_right_order();
 | 
|---|
| 155 |     return 0;
 | 
|---|
| 156 | }
 | 
|---|