/src/boost/boost/range/concepts.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Boost.Range library concept checks |
2 | | // |
3 | | // Copyright Neil Groves 2009. Use, modification and distribution |
4 | | // are subject to the Boost Software License, Version 1.0. (See |
5 | | // accompanying file LICENSE_1_0.txt or copy at |
6 | | // http://www.boost.org/LICENSE_1_0.txt) |
7 | | // |
8 | | // Copyright Daniel Walker 2006. Use, modification and distribution |
9 | | // are subject to the Boost Software License, Version 1.0. (See |
10 | | // accompanying file LICENSE_1_0.txt or copy at |
11 | | // http://www.boost.org/LICENSE_1_0.txt) |
12 | | // |
13 | | // For more information, see http://www.boost.org/libs/range/ |
14 | | // |
15 | | |
16 | | #ifndef BOOST_RANGE_CONCEPTS_HPP |
17 | | #define BOOST_RANGE_CONCEPTS_HPP |
18 | | |
19 | | #include <boost/concept_check.hpp> |
20 | | #include <boost/iterator/iterator_concepts.hpp> |
21 | | #include <boost/range/begin.hpp> |
22 | | #include <boost/range/end.hpp> |
23 | | #include <boost/range/iterator.hpp> |
24 | | #include <boost/range/value_type.hpp> |
25 | | #include <boost/range/detail/misc_concept.hpp> |
26 | | #include <boost/type_traits/remove_reference.hpp> |
27 | | |
28 | | #include <iterator> |
29 | | |
30 | | /*! |
31 | | * \file |
32 | | * \brief Concept checks for the Boost Range library. |
33 | | * |
34 | | * The structures in this file may be used in conjunction with the |
35 | | * Boost Concept Check library to insure that the type of a function |
36 | | * parameter is compatible with a range concept. If not, a meaningful |
37 | | * compile time error is generated. Checks are provided for the range |
38 | | * concepts related to iterator traversal categories. For example, the |
39 | | * following line checks that the type T models the ForwardRange |
40 | | * concept. |
41 | | * |
42 | | * \code |
43 | | * BOOST_CONCEPT_ASSERT((ForwardRangeConcept<T>)); |
44 | | * \endcode |
45 | | * |
46 | | * A different concept check is required to ensure writeable value |
47 | | * access. For example to check for a ForwardRange that can be written |
48 | | * to, the following code is required. |
49 | | * |
50 | | * \code |
51 | | * BOOST_CONCEPT_ASSERT((WriteableForwardRangeConcept<T>)); |
52 | | * \endcode |
53 | | * |
54 | | * \see http://www.boost.org/libs/range/doc/range.html for details |
55 | | * about range concepts. |
56 | | * \see http://www.boost.org/libs/iterator/doc/iterator_concepts.html |
57 | | * for details about iterator concepts. |
58 | | * \see http://www.boost.org/libs/concept_check/concept_check.htm for |
59 | | * details about concept checks. |
60 | | */ |
61 | | |
62 | | namespace boost { |
63 | | |
64 | | namespace range_detail { |
65 | | |
66 | | #ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
67 | | |
68 | | // List broken compiler versions here: |
69 | | #ifndef __clang__ |
70 | | #ifdef __GNUC__ |
71 | | // GNUC 4.2 has strange issues correctly detecting compliance with the Concepts |
72 | | // hence the least disruptive approach is to turn-off the concept checking for |
73 | | // this version of the compiler. |
74 | | #if __GNUC__ == 4 && __GNUC_MINOR__ == 2 |
75 | | #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 |
76 | | #endif |
77 | | #endif |
78 | | |
79 | | #ifdef __GCCXML__ |
80 | | // GCC XML, unsurprisingly, has the same issues |
81 | | #if __GCCXML_GNUC__ == 4 && __GCCXML_GNUC_MINOR__ == 2 |
82 | | #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 |
83 | | #endif |
84 | | #endif |
85 | | #endif |
86 | | |
87 | | #ifdef BOOST_BORLANDC |
88 | | #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 |
89 | | #endif |
90 | | |
91 | | #ifdef __PATHCC__ |
92 | | #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0 |
93 | | #endif |
94 | | |
95 | | // Default to using the concept asserts unless we have defined it off |
96 | | // during the search for black listed compilers. |
97 | | #ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
98 | | #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 1 |
99 | | #endif |
100 | | |
101 | | #endif |
102 | | |
103 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
104 | 0 | #define BOOST_RANGE_CONCEPT_ASSERT( x ) BOOST_CONCEPT_ASSERT( x ) |
105 | | #else |
106 | | #define BOOST_RANGE_CONCEPT_ASSERT( x ) |
107 | | #endif |
108 | | |
109 | | // Rationale for the inclusion of redefined iterator concept |
110 | | // classes: |
111 | | // |
112 | | // The Range algorithms often do not require that the iterators are |
113 | | // Assignable or default constructable, but the correct standard |
114 | | // conformant iterators do require the iterators to be a model of the |
115 | | // Assignable concept. |
116 | | // Iterators that contains a functor that is not assignable therefore |
117 | | // are not correct models of the standard iterator concepts, |
118 | | // despite being adequate for most algorithms. An example of this |
119 | | // use case is the combination of the boost::adaptors::filtered |
120 | | // class with a boost::lambda::bind generated functor. |
121 | | // Ultimately modeling the range concepts using composition |
122 | | // with the Boost.Iterator concepts would render the library |
123 | | // incompatible with many common Boost.Lambda expressions. |
124 | | template<class Iterator> |
125 | | struct IncrementableIteratorConcept : CopyConstructible<Iterator> |
126 | | { |
127 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
128 | | typedef BOOST_DEDUCED_TYPENAME iterator_traversal<Iterator>::type traversal_category; |
129 | | |
130 | | BOOST_RANGE_CONCEPT_ASSERT(( |
131 | | Convertible< |
132 | | traversal_category, |
133 | | incrementable_traversal_tag |
134 | | >)); |
135 | | |
136 | | BOOST_CONCEPT_USAGE(IncrementableIteratorConcept) |
137 | | { |
138 | | ++i; |
139 | | (void)i++; |
140 | | } |
141 | | private: |
142 | | Iterator i; |
143 | | #endif |
144 | | }; |
145 | | |
146 | | template<class Iterator> |
147 | | struct SinglePassIteratorConcept |
148 | | : IncrementableIteratorConcept<Iterator> |
149 | | , EqualityComparable<Iterator> |
150 | | { |
151 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
152 | | BOOST_RANGE_CONCEPT_ASSERT(( |
153 | | Convertible< |
154 | | BOOST_DEDUCED_TYPENAME SinglePassIteratorConcept::traversal_category, |
155 | | single_pass_traversal_tag |
156 | | >)); |
157 | | |
158 | | BOOST_CONCEPT_USAGE(SinglePassIteratorConcept) |
159 | | { |
160 | | Iterator i2(++i); |
161 | | boost::ignore_unused_variable_warning(i2); |
162 | | |
163 | | // deliberately we are loose with the postfix version for the single pass |
164 | | // iterator due to the commonly poor adherence to the specification means that |
165 | | // many algorithms would be unusable, whereas actually without the check they |
166 | | // work |
167 | | (void)(i++); |
168 | | |
169 | | BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r1(*i); |
170 | | boost::ignore_unused_variable_warning(r1); |
171 | | |
172 | | BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r2(*(++i)); |
173 | | boost::ignore_unused_variable_warning(r2); |
174 | | } |
175 | | private: |
176 | | Iterator i; |
177 | | #endif |
178 | | }; |
179 | | |
180 | | template<class Iterator> |
181 | | struct ForwardIteratorConcept |
182 | | : SinglePassIteratorConcept<Iterator> |
183 | | , DefaultConstructible<Iterator> |
184 | | { |
185 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
186 | | typedef BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::difference_type difference_type; |
187 | | |
188 | | BOOST_MPL_ASSERT((is_integral<difference_type>)); |
189 | | BOOST_MPL_ASSERT_RELATION(std::numeric_limits<difference_type>::is_signed, ==, true); |
190 | | |
191 | | BOOST_RANGE_CONCEPT_ASSERT(( |
192 | | Convertible< |
193 | | BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category, |
194 | | forward_traversal_tag |
195 | | >)); |
196 | | |
197 | | BOOST_CONCEPT_USAGE(ForwardIteratorConcept) |
198 | | { |
199 | | // See the above note in the SinglePassIteratorConcept about the handling of the |
200 | | // postfix increment. Since with forward and better iterators there is no need |
201 | | // for a proxy, we can sensibly require that the dereference result |
202 | | // is convertible to reference. |
203 | | Iterator i2(i++); |
204 | | boost::ignore_unused_variable_warning(i2); |
205 | | BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r(*(i++)); |
206 | | boost::ignore_unused_variable_warning(r); |
207 | | } |
208 | | private: |
209 | | Iterator i; |
210 | | #endif |
211 | | }; |
212 | | |
213 | | template<class Iterator> |
214 | | struct BidirectionalIteratorConcept |
215 | | : ForwardIteratorConcept<Iterator> |
216 | | { |
217 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
218 | | BOOST_RANGE_CONCEPT_ASSERT(( |
219 | | Convertible< |
220 | | BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept::traversal_category, |
221 | | bidirectional_traversal_tag |
222 | | >)); |
223 | | |
224 | | BOOST_CONCEPT_USAGE(BidirectionalIteratorConcept) |
225 | | { |
226 | | --i; |
227 | | (void)i--; |
228 | | } |
229 | | private: |
230 | | Iterator i; |
231 | | #endif |
232 | | }; |
233 | | |
234 | | template<class Iterator> |
235 | | struct RandomAccessIteratorConcept |
236 | | : BidirectionalIteratorConcept<Iterator> |
237 | | { |
238 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
239 | | BOOST_RANGE_CONCEPT_ASSERT(( |
240 | | Convertible< |
241 | | BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::traversal_category, |
242 | | random_access_traversal_tag |
243 | | >)); |
244 | | |
245 | | BOOST_CONCEPT_USAGE(RandomAccessIteratorConcept) |
246 | | { |
247 | | i += n; |
248 | | i = i + n; |
249 | | i = n + i; |
250 | | i -= n; |
251 | | i = i - n; |
252 | | n = i - j; |
253 | | } |
254 | | private: |
255 | | BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept<Iterator>::difference_type n; |
256 | | Iterator i; |
257 | | Iterator j; |
258 | | #endif |
259 | | }; |
260 | | |
261 | | } // namespace range_detail |
262 | | |
263 | | //! Check if a type T models the SinglePassRange range concept. |
264 | | template<class T> |
265 | | struct SinglePassRangeConcept |
266 | | { |
267 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
268 | | // A few compilers don't like the rvalue reference T types so just |
269 | | // remove it. |
270 | | typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type Rng; |
271 | | |
272 | | typedef BOOST_DEDUCED_TYPENAME range_iterator< |
273 | | Rng const |
274 | | >::type const_iterator; |
275 | | |
276 | | typedef BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type iterator; |
277 | | |
278 | | BOOST_RANGE_CONCEPT_ASSERT(( |
279 | | range_detail::SinglePassIteratorConcept<iterator>)); |
280 | | |
281 | | BOOST_RANGE_CONCEPT_ASSERT(( |
282 | | range_detail::SinglePassIteratorConcept<const_iterator>)); |
283 | | |
284 | | BOOST_CONCEPT_USAGE(SinglePassRangeConcept) |
285 | | { |
286 | | // This has been modified from assigning to this->i |
287 | | // (where i was a member variable) to improve |
288 | | // compatibility with Boost.Lambda |
289 | | iterator i1 = boost::begin(*m_range); |
290 | | iterator i2 = boost::end(*m_range); |
291 | | |
292 | | boost::ignore_unused_variable_warning(i1); |
293 | | boost::ignore_unused_variable_warning(i2); |
294 | | |
295 | | const_constraints(*m_range); |
296 | | } |
297 | | |
298 | | private: |
299 | | void const_constraints(const Rng& const_range) |
300 | 0 | { |
301 | 0 | const_iterator ci1 = boost::begin(const_range); |
302 | 0 | const_iterator ci2 = boost::end(const_range); |
303 | 0 |
|
304 | 0 | boost::ignore_unused_variable_warning(ci1); |
305 | 0 | boost::ignore_unused_variable_warning(ci2); |
306 | 0 | } |
307 | | |
308 | | // Rationale: |
309 | | // The type of m_range is T* rather than T because it allows |
310 | | // T to be an abstract class. The other obvious alternative of |
311 | | // T& produces a warning on some compilers. |
312 | | Rng* m_range; |
313 | | #endif |
314 | | }; |
315 | | |
316 | | //! Check if a type T models the ForwardRange range concept. |
317 | | template<class T> |
318 | | struct ForwardRangeConcept : SinglePassRangeConcept<T> |
319 | | { |
320 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
321 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::iterator>)); |
322 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::const_iterator>)); |
323 | | #endif |
324 | | }; |
325 | | |
326 | | template<class T> |
327 | | struct WriteableRangeConcept |
328 | | { |
329 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
330 | | typedef BOOST_DEDUCED_TYPENAME range_iterator<T>::type iterator; |
331 | | |
332 | | BOOST_CONCEPT_USAGE(WriteableRangeConcept) |
333 | | { |
334 | | *i = v; |
335 | | } |
336 | | private: |
337 | | iterator i; |
338 | | BOOST_DEDUCED_TYPENAME range_value<T>::type v; |
339 | | #endif |
340 | | }; |
341 | | |
342 | | //! Check if a type T models the WriteableForwardRange range concept. |
343 | | template<class T> |
344 | | struct WriteableForwardRangeConcept |
345 | | : ForwardRangeConcept<T> |
346 | | , WriteableRangeConcept<T> |
347 | | { |
348 | | }; |
349 | | |
350 | | //! Check if a type T models the BidirectionalRange range concept. |
351 | | template<class T> |
352 | | struct BidirectionalRangeConcept : ForwardRangeConcept<T> |
353 | | { |
354 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
355 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::iterator>)); |
356 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::const_iterator>)); |
357 | | #endif |
358 | | }; |
359 | | |
360 | | //! Check if a type T models the WriteableBidirectionalRange range concept. |
361 | | template<class T> |
362 | | struct WriteableBidirectionalRangeConcept |
363 | | : BidirectionalRangeConcept<T> |
364 | | , WriteableRangeConcept<T> |
365 | | { |
366 | | }; |
367 | | |
368 | | //! Check if a type T models the RandomAccessRange range concept. |
369 | | template<class T> |
370 | | struct RandomAccessRangeConcept : BidirectionalRangeConcept<T> |
371 | | { |
372 | | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT |
373 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::iterator>)); |
374 | | BOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::const_iterator>)); |
375 | | #endif |
376 | | }; |
377 | | |
378 | | //! Check if a type T models the WriteableRandomAccessRange range concept. |
379 | | template<class T> |
380 | | struct WriteableRandomAccessRangeConcept |
381 | | : RandomAccessRangeConcept<T> |
382 | | , WriteableRangeConcept<T> |
383 | | { |
384 | | }; |
385 | | |
386 | | } // namespace boost |
387 | | |
388 | | #endif // BOOST_RANGE_CONCEPTS_HPP |