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>
13 #include <boost/utility/enable_if.hpp>
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:
counter_iterator()28 counter_iterator() {}
counter_iterator(int * state)29 counter_iterator(int* state) : state(state) {}
30
increment()31 void increment()
32 {
33 ++*state;
34 }
35
36 Ref
dereference() const37 dereference() const
38 {
39 return *state;
40 }
41
equal(counter_iterator const & y) const42 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 {
proxyproxy52 proxy(int& x) : state(x) {}
53
operator int const&proxy54 operator int const&() const
55 {
56 return state;
57 }
58
operator =proxy59 int& operator=(int x) { state = x; return state; }
60
61 int& state;
62 };
63
64 struct value
65 {
mutatorvalue66 void mutator() {} // non-const member function
67 };
68
69 struct input_iter
70 : boost::iterator_facade<
71 input_iter
72 , value
73 , boost::single_pass_traversal_tag
74 , value
75 >
76 {
77 public:
input_iterinput_iter78 input_iter() {}
79
incrementinput_iter80 void increment()
81 {
82 }
83 value
dereferenceinput_iter84 dereference() const
85 {
86 return value();
87 }
88
equalinput_iter89 bool equal(input_iter const&) const
90 {
91 return false;
92 }
93 };
94
95 template <class T>
96 struct wrapper
97 {
98 T m_x;
wrapperwrapper99 explicit wrapper(typename boost::call_traits<T>::param_type x)
100 : m_x(x)
101 { }
102 template <class U>
wrapperwrapper103 wrapper(const wrapper<U>& other,
104 typename boost::enable_if< boost::is_convertible<U,T> >::type* = 0)
105 : m_x(other.m_x)
106 { }
107 };
108
109 struct iterator_with_proxy_reference
110 : boost::iterator_facade<
111 iterator_with_proxy_reference
112 , wrapper<int>
113 , boost::incrementable_traversal_tag
114 , wrapper<int&>
115 >
116 {
117 int& m_x;
iterator_with_proxy_referenceiterator_with_proxy_reference118 explicit iterator_with_proxy_reference(int& x)
119 : m_x(x)
120 { }
121
incrementiterator_with_proxy_reference122 void increment()
123 { }
dereferenceiterator_with_proxy_reference124 wrapper<int&> dereference() const
125 { return wrapper<int&>(m_x); }
126 };
127
128 template <class T, class U>
same_type(U const &)129 void same_type(U const&)
130 { BOOST_MPL_ASSERT((boost::is_same<T,U>)); }
131
132 template <class I, class A>
133 struct abstract_iterator
134 : boost::iterator_facade<
135 abstract_iterator<I, A>
136 , A &
137 // In order to be value type as a reference, traversal category has
138 // to satisfy least forward traversal.
139 , boost::forward_traversal_tag
140 , A &
141 >
142 {
abstract_iteratorabstract_iterator143 abstract_iterator(I iter) : iter(iter) {}
144
incrementabstract_iterator145 void increment()
146 { ++iter; }
147
dereferenceabstract_iterator148 A & dereference() const
149 { return *iter; }
150
equalabstract_iterator151 bool equal(abstract_iterator const& y) const
152 { return iter == y.iter; }
153
154 I iter;
155 };
156
157 struct base
158 {
159 virtual void assign(const base &) = 0;
160 virtual bool equal(const base &) const = 0;
161 };
162
163 struct derived : base
164 {
derivedderived165 derived(int state) : state(state) { }
derivedderived166 derived(const derived &d) : state(d.state) { }
derivedderived167 derived(const base &b) { derived::assign(b); }
168
assignderived169 virtual void assign(const base &b)
170 {
171 state = boost::polymorphic_cast<const derived *>(&b)->state;
172 }
173
equalderived174 virtual bool equal(const base &b) const
175 {
176 return state == boost::polymorphic_cast<const derived *>(&b)->state;
177 }
178
179 int state;
180 };
181
operator ==(const base & lhs,const base & rhs)182 inline bool operator==(const base &lhs, const base &rhs)
183 {
184 return lhs.equal(rhs);
185 }
186
main()187 int main()
188 {
189 {
190 int state = 0;
191 boost::readable_iterator_test(counter_iterator<int const&>(&state), 0);
192 state = 3;
193 boost::readable_iterator_test(counter_iterator<proxy>(&state), 3);
194 boost::writable_iterator_test(counter_iterator<proxy>(&state), 9, 7);
195 BOOST_TEST(state == 8);
196 }
197
198 {
199 // test for a fix to http://tinyurl.com/zuohe
200 // These two lines should be equivalent (and both compile)
201 input_iter p;
202 (*p).mutator();
203 p->mutator();
204
205 same_type<input_iter::pointer>(p.operator->());
206 }
207
208 {
209 int x = 0;
210 iterator_with_proxy_reference i(x);
211 BOOST_TEST(x == 0);
212 BOOST_TEST(i.m_x == 0);
213 ++(*i).m_x;
214 BOOST_TEST(x == 1);
215 BOOST_TEST(i.m_x == 1);
216 ++i->m_x;
217 BOOST_TEST(x == 2);
218 BOOST_TEST(i.m_x == 2);
219 }
220
221 {
222 derived d(1);
223 boost::readable_iterator_test(abstract_iterator<derived *, base>(&d), derived(1));
224 }
225
226 return boost::report_errors();
227 }
228