]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright David Abrahams 2004. Distributed under the Boost |
2 | // Software License, Version 1.0. (See accompanying | |
3 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
4 | ||
5 | // This is really an incomplete test; should be fleshed out. | |
6 | ||
7 | #include <boost/iterator/iterator_facade.hpp> | |
8 | #include <boost/iterator/new_iterator_tests.hpp> | |
9 | ||
10 | #include <boost/call_traits.hpp> | |
11 | #include <boost/polymorphic_cast.hpp> | |
12 | #include <boost/type_traits/is_convertible.hpp> | |
f51cf556 | 13 | #include <boost/core/enable_if.hpp> |
7c673cae FG |
14 | |
15 | // This is a really, really limited test so far. All we're doing | |
16 | // right now is checking that the postfix++ proxy for single-pass | |
17 | // iterators works properly. | |
18 | template <class Ref> | |
19 | class counter_iterator | |
20 | : public boost::iterator_facade< | |
21 | counter_iterator<Ref> | |
22 | , int const | |
23 | , boost::single_pass_traversal_tag | |
24 | , Ref | |
25 | > | |
26 | { | |
27 | public: | |
28 | counter_iterator() {} | |
29 | counter_iterator(int* state) : state(state) {} | |
30 | ||
31 | void increment() | |
32 | { | |
33 | ++*state; | |
34 | } | |
35 | ||
36 | Ref | |
37 | dereference() const | |
38 | { | |
39 | return *state; | |
40 | } | |
41 | ||
42 | bool equal(counter_iterator const& y) const | |
43 | { | |
44 | return *this->state == *y.state; | |
45 | } | |
46 | ||
47 | int* state; | |
48 | }; | |
49 | ||
50 | struct proxy | |
51 | { | |
52 | proxy(int& x) : state(x) {} | |
53 | ||
54 | operator int const&() const | |
55 | { | |
56 | return state; | |
57 | } | |
58 | ||
59 | int& operator=(int x) { state = x; return state; } | |
60 | ||
61 | int& state; | |
62 | }; | |
63 | ||
64 | struct value | |
65 | { | |
f51cf556 TL |
66 | int increment_count; |
67 | int private_mutator_count; | |
68 | int& shared_mutator_count; | |
69 | ||
70 | explicit value(int& shared_mutator_count) : | |
71 | increment_count(0), | |
72 | private_mutator_count(0), | |
73 | shared_mutator_count(shared_mutator_count) | |
74 | { | |
75 | } | |
76 | ||
77 | // non-const member function | |
78 | void mutator() | |
79 | { | |
80 | ++private_mutator_count; | |
81 | ++shared_mutator_count; | |
82 | } | |
7c673cae FG |
83 | }; |
84 | ||
85 | struct input_iter | |
86 | : boost::iterator_facade< | |
87 | input_iter | |
88 | , value | |
89 | , boost::single_pass_traversal_tag | |
90 | , value | |
91 | > | |
92 | { | |
93 | public: | |
f51cf556 | 94 | explicit input_iter(value& val) : state(&val) {} |
7c673cae FG |
95 | |
96 | void increment() | |
97 | { | |
f51cf556 | 98 | ++(state->increment_count); |
7c673cae FG |
99 | } |
100 | value | |
101 | dereference() const | |
102 | { | |
f51cf556 | 103 | return *state; |
7c673cae FG |
104 | } |
105 | ||
b32b8144 | 106 | bool equal(input_iter const&) const |
7c673cae FG |
107 | { |
108 | return false; | |
109 | } | |
f51cf556 TL |
110 | |
111 | private: | |
112 | value* state; | |
7c673cae FG |
113 | }; |
114 | ||
115 | template <class T> | |
116 | struct wrapper | |
117 | { | |
118 | T m_x; | |
119 | explicit wrapper(typename boost::call_traits<T>::param_type x) | |
120 | : m_x(x) | |
121 | { } | |
122 | template <class U> | |
123 | wrapper(const wrapper<U>& other, | |
124 | typename boost::enable_if< boost::is_convertible<U,T> >::type* = 0) | |
125 | : m_x(other.m_x) | |
126 | { } | |
127 | }; | |
128 | ||
129 | struct iterator_with_proxy_reference | |
130 | : boost::iterator_facade< | |
131 | iterator_with_proxy_reference | |
132 | , wrapper<int> | |
133 | , boost::incrementable_traversal_tag | |
134 | , wrapper<int&> | |
135 | > | |
136 | { | |
137 | int& m_x; | |
138 | explicit iterator_with_proxy_reference(int& x) | |
139 | : m_x(x) | |
140 | { } | |
141 | ||
142 | void increment() | |
143 | { } | |
144 | wrapper<int&> dereference() const | |
145 | { return wrapper<int&>(m_x); } | |
146 | }; | |
147 | ||
148 | template <class T, class U> | |
149 | void same_type(U const&) | |
150 | { BOOST_MPL_ASSERT((boost::is_same<T,U>)); } | |
151 | ||
152 | template <class I, class A> | |
153 | struct abstract_iterator | |
154 | : boost::iterator_facade< | |
155 | abstract_iterator<I, A> | |
156 | , A & | |
157 | // In order to be value type as a reference, traversal category has | |
158 | // to satisfy least forward traversal. | |
159 | , boost::forward_traversal_tag | |
160 | , A & | |
161 | > | |
162 | { | |
163 | abstract_iterator(I iter) : iter(iter) {} | |
164 | ||
165 | void increment() | |
166 | { ++iter; } | |
167 | ||
168 | A & dereference() const | |
169 | { return *iter; } | |
170 | ||
171 | bool equal(abstract_iterator const& y) const | |
172 | { return iter == y.iter; } | |
173 | ||
174 | I iter; | |
175 | }; | |
176 | ||
177 | struct base | |
178 | { | |
179 | virtual void assign(const base &) = 0; | |
180 | virtual bool equal(const base &) const = 0; | |
181 | }; | |
182 | ||
183 | struct derived : base | |
184 | { | |
185 | derived(int state) : state(state) { } | |
186 | derived(const derived &d) : state(d.state) { } | |
187 | derived(const base &b) { derived::assign(b); } | |
188 | ||
189 | virtual void assign(const base &b) | |
190 | { | |
191 | state = boost::polymorphic_cast<const derived *>(&b)->state; | |
192 | } | |
193 | ||
194 | virtual bool equal(const base &b) const | |
195 | { | |
196 | return state == boost::polymorphic_cast<const derived *>(&b)->state; | |
197 | } | |
198 | ||
199 | int state; | |
200 | }; | |
201 | ||
202 | inline bool operator==(const base &lhs, const base &rhs) | |
203 | { | |
204 | return lhs.equal(rhs); | |
205 | } | |
206 | ||
207 | int main() | |
208 | { | |
209 | { | |
210 | int state = 0; | |
211 | boost::readable_iterator_test(counter_iterator<int const&>(&state), 0); | |
212 | state = 3; | |
213 | boost::readable_iterator_test(counter_iterator<proxy>(&state), 3); | |
214 | boost::writable_iterator_test(counter_iterator<proxy>(&state), 9, 7); | |
215 | BOOST_TEST(state == 8); | |
216 | } | |
217 | ||
218 | { | |
219 | // test for a fix to http://tinyurl.com/zuohe | |
220 | // These two lines should be equivalent (and both compile) | |
f51cf556 TL |
221 | int shared_mutator_count = 0; |
222 | value val(shared_mutator_count); | |
223 | input_iter p(val); | |
7c673cae FG |
224 | (*p).mutator(); |
225 | p->mutator(); | |
f51cf556 TL |
226 | BOOST_TEST_EQ(val.increment_count, 0); |
227 | BOOST_TEST_EQ(val.private_mutator_count, 0); // mutator() should be invoked on an object returned by value | |
228 | BOOST_TEST_EQ(shared_mutator_count, 2); | |
7c673cae FG |
229 | |
230 | same_type<input_iter::pointer>(p.operator->()); | |
231 | } | |
232 | ||
f51cf556 TL |
233 | { |
234 | // Test that accessing dereferenced value of a post-incremented iterator works | |
235 | int shared_mutator_count = 0; | |
236 | value val(shared_mutator_count); | |
237 | input_iter p(val); | |
238 | (*p++).mutator(); | |
239 | (p++)->mutator(); | |
240 | BOOST_TEST_EQ(val.increment_count, 2); | |
241 | BOOST_TEST_EQ(val.private_mutator_count, 0); // mutator() should be invoked on an object returned by value | |
242 | BOOST_TEST_EQ(shared_mutator_count, 2); | |
243 | } | |
244 | ||
7c673cae FG |
245 | { |
246 | int x = 0; | |
247 | iterator_with_proxy_reference i(x); | |
248 | BOOST_TEST(x == 0); | |
249 | BOOST_TEST(i.m_x == 0); | |
250 | ++(*i).m_x; | |
251 | BOOST_TEST(x == 1); | |
252 | BOOST_TEST(i.m_x == 1); | |
253 | ++i->m_x; | |
254 | BOOST_TEST(x == 2); | |
255 | BOOST_TEST(i.m_x == 2); | |
256 | } | |
257 | ||
258 | { | |
259 | derived d(1); | |
260 | boost::readable_iterator_test(abstract_iterator<derived *, base>(&d), derived(1)); | |
261 | } | |
262 | ||
263 | return boost::report_errors(); | |
264 | } |