1 // Boost.Range library
2 //
3 //  Copyright Neil Groves 2010. Use, modification and
4 //  distribution is subject to the Boost Software License, Version
5 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_RANGE_ADAPTOR_TEST_TYPE_ERASED_TEST_HPP
9 #define BOOST_RANGE_ADAPTOR_TEST_TYPE_ERASED_TEST_HPP
10 
11 #include <boost/range/algorithm/fill.hpp>
12 #include <boost/range/algorithm_ext/push_back.hpp>
13 #include <boost/assign.hpp>
14 #include <boost/test/test_tools.hpp>
15 
16 namespace boost_range_adaptor_type_erased_test
17 {
18 
19 class MockType
20 {
21 public:
MockType()22     MockType()
23         : m_x(0)
24     {
25     }
26 
MockType(boost::int32_t x)27     MockType(boost::int32_t x)
28         : m_x(x)
29     {
30     }
31 
get() const32     boost::int32_t get() const { return m_x; }
33 
operator ==(const MockType & other) const34     inline bool operator==(const MockType& other) const
35     {
36         return m_x == other.m_x;
37     }
38 
operator !=(const MockType & other) const39     inline bool operator!=(const MockType& other) const
40     {
41         return m_x != other.m_x;
42     }
43 
44 private:
45     boost::int32_t m_x;
46 };
47 
48 class MockType2 : public MockType
49 {
50 public:
MockType2()51     MockType2() {}
MockType2(boost::int32_t x)52     MockType2(boost::int32_t x) : MockType(x) { }
MockType2(const MockType & other)53     MockType2(const MockType& other) : MockType(other) { }
54 };
55 
operator <<(std::ostream & out,const MockType & obj)56 inline std::ostream& operator<<(std::ostream& out, const MockType& obj)
57 {
58     out << obj.get();
59     return out;
60 }
61 
62 template<class Container>
test_type_erased_impl(Container & c)63 void test_type_erased_impl(Container& c)
64 {
65     using namespace boost::adaptors;
66     typedef typename boost::range_value<Container>::type value_type;
67     typedef typename boost::adaptors::type_erased<> type_erased_t;
68 
69 
70     std::vector<value_type> output;
71 
72     boost::push_back(output, boost::adaptors::type_erase(c, type_erased_t()));
73 
74     BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(),
75                                    c.begin(), c.end() );
76 
77     output.clear();
78     boost::push_back(output, c | type_erased_t());
79 
80     BOOST_CHECK_EQUAL_COLLECTIONS( output.begin(), output.end(),
81                                    c.begin(), c.end() );
82 }
83 
84 template<class Container>
test_const_and_mutable(Container & c)85 void test_const_and_mutable(Container& c)
86 {
87     test_type_erased_impl(c);
88 
89     const Container& const_c = c;
90     test_type_erased_impl(const_c);
91 }
92 
93 template<class Container>
test_driver()94 void test_driver()
95 {
96     using namespace boost::assign;
97 
98     typedef typename boost::range_value<Container>::type value_type;
99 
100     Container c;
101     test_const_and_mutable(c);
102 
103     c += value_type(1);
104     test_const_and_mutable(c);
105 
106     c += value_type(2);
107     test_const_and_mutable(c);
108 }
109 
110 template<
111     class Traversal
112   , class Container
113 >
test_writeable(Container &,boost::single_pass_traversal_tag)114 void test_writeable(Container&, boost::single_pass_traversal_tag)
115 {}
116 
117 template<
118     class Traversal
119   , class Container
120 >
test_writeable(Container & source,boost::forward_traversal_tag)121 void test_writeable(Container& source, boost::forward_traversal_tag)
122 {
123     using namespace boost::adaptors;
124 
125     typedef typename boost::range_value<Container>::type value_type;
126     typedef typename boost::range_difference<Container>::type difference_type;
127     typedef typename boost::range_reference<Container>::type mutable_reference_type;
128     typedef boost::any_range<
129                 value_type
130               , Traversal
131               , mutable_reference_type
132               , difference_type
133             > mutable_any_range;
134 
135     mutable_any_range r = source | boost::adaptors::type_erased<>();
136     std::vector<value_type> output_test;
137     boost::fill(r, value_type(1));
138     BOOST_CHECK_EQUAL( boost::distance(r), boost::distance(source) );
139     std::vector<value_type> reference_output(source.size(), value_type(1));
140     BOOST_CHECK_EQUAL_COLLECTIONS( reference_output.begin(), reference_output.end(),
141                                    r.begin(), r.end() );
142 
143 }
144 
145 template<
146     class Container
147   , class Traversal
148   , class Buffer
149 >
test_type_erased_impl()150 void test_type_erased_impl()
151 {
152     using namespace boost::adaptors;
153 
154     typedef typename boost::range_value<Container>::type value_type;
155 
156     typedef typename boost::any_range_type_generator<
157         Container
158       , boost::use_default
159       , Traversal
160       , boost::use_default
161       , boost::use_default
162       , Buffer
163     >::type mutable_any_range;
164 
165     typedef typename boost::any_range_type_generator<
166         const Container
167       , boost::use_default
168       , Traversal
169       , boost::use_default
170       , boost::use_default
171       , Buffer
172     >::type const_any_range;
173 
174     typedef boost::adaptors::type_erased<
175                 boost::use_default
176               , Traversal
177               , boost::use_default
178               , boost::use_default
179               , Buffer
180             > type_erased_t;
181 
182     Container source;
183     for (int i = 0; i < 10; ++i)
184         source.push_back(value_type(i));
185 
186     mutable_any_range r(source);
187     BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(),
188                                    r.begin(), r.end() );
189 
190     r = mutable_any_range();
191     BOOST_CHECK_EQUAL( r.empty(), true );
192 
193     r = source | type_erased_t();
194     BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(),
195                                    r.begin(), r.end() );
196     r = mutable_any_range();
197 
198     r = boost::adaptors::type_erase(source, type_erased_t());
199     BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(),
200                                    r.begin(), r.end() );
201     r = mutable_any_range();
202 
203     test_writeable<Traversal>(source, Traversal());
204 
205     // convert and construct a const any_range from a mutable source
206     // range
207     const_any_range cr(source);
208     BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(),
209                                    cr.begin(), cr.end() );
210     // assign an empty range and ensure that this correctly results
211     // in an empty range. This is important for the validity of
212     // the rest of the tests.
213     cr = const_any_range();
214     BOOST_CHECK_EQUAL( cr.empty(), true );
215 
216     // Test the pipe type_erased adaptor from a constant source
217     // range to a constant any_range
218     const Container& const_source = source;
219     cr = const_any_range();
220     cr = const_source | type_erased_t();
221     BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(),
222                                    cr.begin(), cr.end() );
223 
224     // Test the pipe type erased adaptor from a mutable source
225     // range to a constant any_range
226     cr = const_any_range();
227     cr = source | type_erased_t();
228     BOOST_CHECK_EQUAL_COLLECTIONS( source.begin(), source.end(),
229                                    cr.begin(), cr.end() );
230 
231     // Use the function form of the type_erase adaptor from a constant
232     // source range
233     cr = const_any_range();
234     cr = boost::adaptors::type_erase(const_source, type_erased_t());
235     BOOST_CHECK_EQUAL_COLLECTIONS( const_source.begin(), const_source.end(),
236                                    cr.begin(), cr.end() );
237 
238     // Assignment from mutable to const...
239     cr = const_any_range();
240     cr = r;
241     BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(),
242                                    r.begin(), r.end() );
243 
244     // Converting copy from mutable to const...
245     cr = const_any_range();
246     cr = const_any_range(r);
247     BOOST_CHECK_EQUAL_COLLECTIONS( cr.begin(), cr.end(),
248                                    r.begin(), r.end() );
249 }
250 
251 template<
252     class Container
253   , class Traversal
254   , class Buffer
255 >
256 class test_type_erased_impl_fn
257 {
258 public:
259     typedef void result_type;
operator ()()260     void operator()()
261     {
262         test_type_erased_impl< Container, Traversal, Buffer >();
263     }
264 };
265 
266 template<
267     class Container
268   , class Traversal
269 >
test_type_erased_exercise_buffer_types()270 void test_type_erased_exercise_buffer_types()
271 {
272     using boost::any_iterator_default_buffer;
273     using boost::any_iterator_buffer;
274     using boost::any_iterator_heap_only_buffer;
275     using boost::any_iterator_stack_only_buffer;
276 
277     test_type_erased_impl_fn< Container, Traversal, any_iterator_default_buffer >()();
278     test_type_erased_impl_fn< Container, Traversal, any_iterator_heap_only_buffer >()();
279     test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<1> >()();
280     test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<2> >()();
281     test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<32> >()();
282     test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<64> >()();
283     test_type_erased_impl_fn< Container, Traversal, any_iterator_buffer<128> >()();
284     test_type_erased_impl_fn< Container, Traversal, any_iterator_stack_only_buffer<128> >()();
285 }
286 
287 } // namespace boost_range_adaptor_type_erased_test
288 
289 #endif // include guard
290