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: |
22 | MockType() |
23 | : m_x(0) |
24 | { |
25 | } |
26 | |
27 | MockType(boost::int32_t x) |
28 | : m_x(x) |
29 | { |
30 | } |
31 | |
32 | boost::int32_t get() const { return m_x; } |
33 | |
34 | inline bool operator==(const MockType& other) const |
35 | { |
36 | return m_x == other.m_x; |
37 | } |
38 | |
39 | 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: |
51 | MockType2() {} |
52 | MockType2(boost::int32_t x) : MockType(x) { } |
53 | MockType2(const MockType& other) : MockType(other) { } |
54 | }; |
55 | |
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> |
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> |
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> |
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 | > |
114 | void test_writeable(Container&, boost::single_pass_traversal_tag) |
115 | {} |
116 | |
117 | template< |
118 | class Traversal |
119 | , class Container |
120 | > |
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 | > |
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; |
260 | void operator()() |
261 | { |
262 | test_type_erased_impl< Container, Traversal, Buffer >(); |
263 | } |
264 | }; |
265 | |
266 | template< |
267 | class Container |
268 | , class Traversal |
269 | > |
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 | |