1 //  (C) Copyright Jeremy Siek 2002.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  Revision History
7 //  22 Nov 2002 Thomas Witt
8 //       Added interoperability check.
9 //  28 Oct 2002   Jeremy Siek
10 //       Updated for new iterator adaptors.
11 //  08 Mar 2001   Jeremy Siek
12 //       Moved test of transform iterator into its own file. It to
13 //       to be in iterator_adaptor_test.cpp.
14 
15 #include <boost/assert.hpp>
16 #include <boost/config.hpp>
17 #include <algorithm>
18 #include <boost/iterator/transform_iterator.hpp>
19 #include <boost/iterator/iterator_concepts.hpp>
20 #include <boost/iterator/new_iterator_tests.hpp>
21 #include <boost/pending/iterator_tests.hpp>
22 #include <boost/bind.hpp>
23 #include <boost/concept_check.hpp>
24 
25 #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
26 namespace boost { namespace detail
27 {
28   template<> struct function_object_result<int (*)(int)>
29   {
30       typedef int type;
31   };
32 }}
33 #endif
34 
35 struct mult_functor {
36   // Functors used with transform_iterator must be
37   // DefaultConstructible, as the transform_iterator must be
38   // DefaultConstructible to satisfy the requirements for
39   // TrivialIterator.
mult_functormult_functor40   mult_functor() { }
mult_functormult_functor41   mult_functor(int aa) : a(aa) { }
operator ()mult_functor42   int operator()(int b) const { return a * b; }
43   int a;
44 };
45 
46 struct adaptable_mult_functor
47  : mult_functor
48 {
49   typedef int result_type;
50   typedef int argument_type;
51   // Functors used with transform_iterator must be
52   // DefaultConstructible, as the transform_iterator must be
53   // DefaultConstructible to satisfy the requirements for
54   // TrivialIterator.
adaptable_mult_functoradaptable_mult_functor55   adaptable_mult_functor() { }
adaptable_mult_functoradaptable_mult_functor56   adaptable_mult_functor(int aa) : mult_functor(aa) { }
57 };
58 
59 
60 struct const_select_first
61 {
62   typedef int const& result_type;
63 
operator ()const_select_first64   int const& operator()(std::pair<int, int>const& p) const
65   {
66     return p.first;
67   }
68 };
69 
70 struct select_first
71   : const_select_first // derivation to allow conversions
72 {
73   typedef int& result_type;
74 
operator ()select_first75   int& operator()(std::pair<int, int>& p) const
76   {
77     return p.first;
78   }
79 };
80 
81 struct select_second
82 {
83   typedef int& result_type;
84 
operator ()select_second85   int& operator()(std::pair<int, int>& p) const
86   {
87     return p.second;
88   }
89 };
90 
91 struct value_select_first
92 {
93   typedef int result_type;
94 
operator ()value_select_first95   int operator()(std::pair<int, int>const& p) const
96   {
97     return p.first;
98   }
99 };
100 
mult_2(int arg)101 int mult_2(int arg)
102 {
103   return arg*2;
104 }
105 
106 struct polymorphic_mult_functor
107 {
108     //Implement result_of protocol
109     template <class FArgs> struct result;
110     template <class F, class T> struct result<const F(T       )> {typedef T type;};
111     template <class F, class T> struct result<const F(T&      )> {typedef T type;};
112     template <class F, class T> struct result<const F(const T&)> {typedef T type;};
113     template <class F, class T> struct result<F(T       )> {typedef void type;};
114     template <class F, class T> struct result<F(T&      )> {typedef void type;};
115     template <class F, class T> struct result<F(const T&)> {typedef void type;};
116 
117     template <class T>
operator ()polymorphic_mult_functor118     T operator()(const T& _arg) const {return _arg*2;}
119     template <class T>
operator ()polymorphic_mult_functor120     void operator()(const T& _arg) { BOOST_ASSERT(0); }
121 };
122 
123 int
main()124 main()
125 {
126   const int N = 10;
127 
128   // Concept checks
129   {
130     typedef boost::transform_iterator<adaptable_mult_functor, int*>       iter_t;
131     typedef boost::transform_iterator<adaptable_mult_functor, int const*> c_iter_t;
132 
133     boost::function_requires< boost_concepts::InteroperableIteratorConcept<iter_t, c_iter_t> >();
134   }
135 
136   // Test transform_iterator
137   {
138     int x[N], y[N];
139     for (int k = 0; k < N; ++k)
140       x[k] = k;
141     std::copy(x, x + N, y);
142 
143     for (int k2 = 0; k2 < N; ++k2)
144       x[k2] = x[k2] * 2;
145 
146     typedef boost::transform_iterator<adaptable_mult_functor, int*> iter_t;
147     iter_t i(y, adaptable_mult_functor(2));
148     boost::input_iterator_test(i, x[0], x[1]);
149     boost::input_iterator_test(iter_t(&y[0], adaptable_mult_functor(2)), x[0], x[1]);
150 
151     boost::random_access_readable_iterator_test(i, N, x);
152   }
153 
154   // Test transform_iterator non adaptable functor
155   {
156     int x[N], y[N];
157     for (int k = 0; k < N; ++k)
158       x[k] = k;
159     std::copy(x, x + N, y);
160 
161     for (int k2 = 0; k2 < N; ++k2)
162       x[k2] = x[k2] * 2;
163 
164     typedef boost::transform_iterator<mult_functor, int*, int> iter_t;
165     iter_t i(y, mult_functor(2));
166     boost::input_iterator_test(i, x[0], x[1]);
167     boost::input_iterator_test(iter_t(&y[0], mult_functor(2)), x[0], x[1]);
168 
169     boost::random_access_readable_iterator_test(i, N, x);
170   }
171 
172   // Test transform_iterator default argument handling
173   {
174     {
175       typedef boost::transform_iterator<adaptable_mult_functor, int*, float> iter_t;
176       BOOST_STATIC_ASSERT((boost::is_same<iter_t::reference,  float>::value));
177       BOOST_STATIC_ASSERT((boost::is_same<iter_t::value_type, float>::value));
178     }
179 
180     {
181       typedef boost::transform_iterator<adaptable_mult_functor, int*, boost::use_default, float> iter_t;
182       BOOST_STATIC_ASSERT((boost::is_same<iter_t::reference,  int>::value));
183       BOOST_STATIC_ASSERT((boost::is_same<iter_t::value_type, float>::value));
184     }
185 
186     {
187       typedef boost::transform_iterator<adaptable_mult_functor, int*, float, double> iter_t;
188       BOOST_STATIC_ASSERT((boost::is_same<iter_t::reference,  float>::value));
189       BOOST_STATIC_ASSERT((boost::is_same<iter_t::value_type, double>::value));
190     }
191   }
192 
193   // Test transform_iterator with function pointers
194   {
195     int x[N], y[N];
196     for (int k = 0; k < N; ++k)
197       x[k] = k;
198     std::copy(x, x + N, y);
199 
200     for (int k2 = 0; k2 < N; ++k2)
201       x[k2] = x[k2] * 2;
202 
203     boost::input_iterator_test(
204         boost::make_transform_iterator(y, mult_2), x[0], x[1]);
205 
206     boost::input_iterator_test(
207         boost::make_transform_iterator(&y[0], mult_2), x[0], x[1]);
208 
209     boost::random_access_readable_iterator_test(
210         boost::make_transform_iterator(y, mult_2), N, x);
211 
212   }
213 
214   // Test transform_iterator as projection iterator
215   {
216     typedef std::pair<int, int> pair_t;
217 
218     int    x[N];
219     int    y[N];
220     pair_t values[N];
221 
222     for(int i = 0; i < N; ++i) {
223 
224       x[i]             = i;
225       y[i]             = N - (i + 1);
226 
227     }
228 
229     std::copy(
230         x
231       , x + N
232       , boost::make_transform_iterator((pair_t*)values, select_first())
233     );
234 
235     std::copy(
236         y
237       , y + N
238       , boost::make_transform_iterator((pair_t*)values, select_second())
239     );
240 
241     boost::random_access_readable_iterator_test(
242         boost::make_transform_iterator((pair_t*)values, value_select_first())
243       , N
244       , x
245     );
246 
247     boost::random_access_readable_iterator_test(
248         boost::make_transform_iterator((pair_t*)values, const_select_first())
249       , N, x
250     );
251 
252     boost::constant_lvalue_iterator_test(
253         boost::make_transform_iterator((pair_t*)values, const_select_first()), x[0]);
254 
255     boost::non_const_lvalue_iterator_test(
256         boost::make_transform_iterator((pair_t*)values, select_first()), x[0], 17);
257 
258     boost::const_nonconst_iterator_test(
259         ++boost::make_transform_iterator((pair_t*)values, select_first())
260       , boost::make_transform_iterator((pair_t*)values, const_select_first())
261     );
262   }
263 
264   // Test transform_iterator with polymorphic object function
265   {
266     int x[N], y[N];
267     for (int k = 0; k < N; ++k)
268       x[k] = k;
269     std::copy(x, x + N, y);
270 
271     for (int k2 = 0; k2 < N; ++k2)
272       x[k2] = x[k2] * 2;
273 
274     boost::input_iterator_test(
275         boost::make_transform_iterator(y, polymorphic_mult_functor()), x[0], x[1]);
276 
277     boost::input_iterator_test(
278         boost::make_transform_iterator(&y[0], polymorphic_mult_functor()), x[0], x[1]);
279 
280     boost::random_access_readable_iterator_test(
281         boost::make_transform_iterator(y, polymorphic_mult_functor()), N, x);
282   }
283 
284   return boost::report_errors();
285 }
286