blob: c990c169d5c0e8c0a0c3bf8923ff65384343a81f [file] [log] [blame]
Jeff Thompsonef2d5a42013-08-22 19:09:24 -07001// 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
Jeff Thompson3d613fd2013-10-15 15:39:04 -070016#ifndef NDNBOOST_RANGE_CONCEPTS_HPP
17#define NDNBOOST_RANGE_CONCEPTS_HPP
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070018
19#include <ndnboost/concept_check.hpp>
20#include <ndnboost/iterator/iterator_concepts.hpp>
21#include <ndnboost/range/begin.hpp>
22#include <ndnboost/range/end.hpp>
23#include <ndnboost/range/iterator.hpp>
24#include <ndnboost/range/value_type.hpp>
25#include <ndnboost/range/detail/misc_concept.hpp>
26
27/*!
28 * \file
29 * \brief Concept checks for the Boost Range library.
30 *
31 * The structures in this file may be used in conjunction with the
32 * Boost Concept Check library to insure that the type of a function
33 * parameter is compatible with a range concept. If not, a meaningful
34 * compile time error is generated. Checks are provided for the range
35 * concepts related to iterator traversal categories. For example, the
36 * following line checks that the type T models the ForwardRange
37 * concept.
38 *
39 * \code
Jeff Thompson3d613fd2013-10-15 15:39:04 -070040 * NDNBOOST_CONCEPT_ASSERT((ForwardRangeConcept<T>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070041 * \endcode
42 *
43 * A different concept check is required to ensure writeable value
44 * access. For example to check for a ForwardRange that can be written
45 * to, the following code is required.
46 *
47 * \code
Jeff Thompson3d613fd2013-10-15 15:39:04 -070048 * NDNBOOST_CONCEPT_ASSERT((WriteableForwardRangeConcept<T>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070049 * \endcode
50 *
51 * \see http://www.boost.org/libs/range/doc/range.html for details
52 * about range concepts.
53 * \see http://www.boost.org/libs/iterator/doc/iterator_concepts.html
54 * for details about iterator concepts.
55 * \see http://www.boost.org/libs/concept_check/concept_check.htm for
56 * details about concept checks.
57 */
58
59namespace ndnboost {
60
61 namespace range_detail {
62
Jeff Thompson3d613fd2013-10-15 15:39:04 -070063#ifndef NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070064
65// List broken compiler versions here:
66 #ifdef __GNUC__
67 // GNUC 4.2 has strange issues correctly detecting compliance with the Concepts
68 // hence the least disruptive approach is to turn-off the concept checking for
69 // this version of the compiler.
70 #if __GNUC__ == 4 && __GNUC_MINOR__ == 2
Jeff Thompson3d613fd2013-10-15 15:39:04 -070071 #define NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070072 #endif
73 #endif
74
75 #ifdef __BORLANDC__
Jeff Thompson3d613fd2013-10-15 15:39:04 -070076 #define NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070077 #endif
78
79 #ifdef __PATHCC__
Jeff Thompson3d613fd2013-10-15 15:39:04 -070080 #define NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070081 #endif
82
83// Default to using the concept asserts unless we have defined it off
84// during the search for black listed compilers.
Jeff Thompson3d613fd2013-10-15 15:39:04 -070085 #ifndef NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
86 #define NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT 1
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070087 #endif
88
89#endif
90
Jeff Thompson3d613fd2013-10-15 15:39:04 -070091#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
92 #define NDNBOOST_RANGE_CONCEPT_ASSERT( x ) NDNBOOST_CONCEPT_ASSERT( x )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070093#else
Jeff Thompson3d613fd2013-10-15 15:39:04 -070094 #define NDNBOOST_RANGE_CONCEPT_ASSERT( x )
Jeff Thompsonef2d5a42013-08-22 19:09:24 -070095#endif
96
97 // Rationale for the inclusion of redefined iterator concept
98 // classes:
99 //
100 // The Range algorithms often do not require that the iterators are
101 // Assignable or default constructable, but the correct standard
102 // conformant iterators do require the iterators to be a model of the
103 // Assignable concept.
104 // Iterators that contains a functor that is not assignable therefore
105 // are not correct models of the standard iterator concepts,
106 // despite being adequate for most algorithms. An example of this
107 // use case is the combination of the ndnboost::adaptors::filtered
108 // class with a ndnboost::lambda::bind generated functor.
109 // Ultimately modeling the range concepts using composition
110 // with the Boost.Iterator concepts would render the library
111 // incompatible with many common Boost.Lambda expressions.
112 template<class Iterator>
113 struct IncrementableIteratorConcept : CopyConstructible<Iterator>
114 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700115#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
116 typedef NDNBOOST_DEDUCED_TYPENAME iterator_traversal<Iterator>::type traversal_category;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700117
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700118 NDNBOOST_RANGE_CONCEPT_ASSERT((
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700119 Convertible<
120 traversal_category,
121 incrementable_traversal_tag
122 >));
123
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700124 NDNBOOST_CONCEPT_USAGE(IncrementableIteratorConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700125 {
126 ++i;
127 (void)i++;
128 }
129 private:
130 Iterator i;
131#endif
132 };
133
134 template<class Iterator>
135 struct SinglePassIteratorConcept
136 : IncrementableIteratorConcept<Iterator>
137 , EqualityComparable<Iterator>
138 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700139#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
140 NDNBOOST_RANGE_CONCEPT_ASSERT((
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700141 Convertible<
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700142 NDNBOOST_DEDUCED_TYPENAME SinglePassIteratorConcept::traversal_category,
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700143 single_pass_traversal_tag
144 >));
145
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700146 NDNBOOST_CONCEPT_USAGE(SinglePassIteratorConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700147 {
148 Iterator i2(++i);
149 ndnboost::ignore_unused_variable_warning(i2);
150
151 // deliberately we are loose with the postfix version for the single pass
152 // iterator due to the commonly poor adherence to the specification means that
153 // many algorithms would be unusable, whereas actually without the check they
154 // work
155 (void)(i++);
156
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700157 NDNBOOST_DEDUCED_TYPENAME ndnboost::detail::iterator_traits<Iterator>::reference r1(*i);
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700158 ndnboost::ignore_unused_variable_warning(r1);
159
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700160 NDNBOOST_DEDUCED_TYPENAME ndnboost::detail::iterator_traits<Iterator>::reference r2(*(++i));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700161 ndnboost::ignore_unused_variable_warning(r2);
162 }
163 private:
164 Iterator i;
165#endif
166 };
167
168 template<class Iterator>
169 struct ForwardIteratorConcept
170 : SinglePassIteratorConcept<Iterator>
171 , DefaultConstructible<Iterator>
172 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700173#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
174 typedef NDNBOOST_DEDUCED_TYPENAME ndnboost::detail::iterator_traits<Iterator>::difference_type difference_type;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700175
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700176 NDNBOOST_MPL_ASSERT((is_integral<difference_type>));
177 NDNBOOST_MPL_ASSERT_RELATION(std::numeric_limits<difference_type>::is_signed, ==, true);
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700178
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700179 NDNBOOST_RANGE_CONCEPT_ASSERT((
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700180 Convertible<
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700181 NDNBOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category,
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700182 forward_traversal_tag
183 >));
184
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700185 NDNBOOST_CONCEPT_USAGE(ForwardIteratorConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700186 {
187 // See the above note in the SinglePassIteratorConcept about the handling of the
188 // postfix increment. Since with forward and better iterators there is no need
189 // for a proxy, we can sensibly require that the dereference result
190 // is convertible to reference.
191 Iterator i2(i++);
192 ndnboost::ignore_unused_variable_warning(i2);
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700193 NDNBOOST_DEDUCED_TYPENAME ndnboost::detail::iterator_traits<Iterator>::reference r(*(i++));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700194 ndnboost::ignore_unused_variable_warning(r);
195 }
196 private:
197 Iterator i;
198#endif
199 };
200
201 template<class Iterator>
202 struct BidirectionalIteratorConcept
203 : ForwardIteratorConcept<Iterator>
204 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700205 #if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
206 NDNBOOST_RANGE_CONCEPT_ASSERT((
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700207 Convertible<
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700208 NDNBOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept::traversal_category,
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700209 bidirectional_traversal_tag
210 >));
211
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700212 NDNBOOST_CONCEPT_USAGE(BidirectionalIteratorConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700213 {
214 --i;
215 (void)i--;
216 }
217 private:
218 Iterator i;
219 #endif
220 };
221
222 template<class Iterator>
223 struct RandomAccessIteratorConcept
224 : BidirectionalIteratorConcept<Iterator>
225 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700226 #if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
227 NDNBOOST_RANGE_CONCEPT_ASSERT((
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700228 Convertible<
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700229 NDNBOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::traversal_category,
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700230 random_access_traversal_tag
231 >));
232
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700233 NDNBOOST_CONCEPT_USAGE(RandomAccessIteratorConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700234 {
235 i += n;
236 i = i + n;
237 i = n + i;
238 i -= n;
239 i = i - n;
240 n = i - j;
241 }
242 private:
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700243 NDNBOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::difference_type n;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700244 Iterator i;
245 Iterator j;
246 #endif
247 };
248
249 } // namespace range_detail
250
251 //! Check if a type T models the SinglePassRange range concept.
252 template<class T>
253 struct SinglePassRangeConcept
254 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700255#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
256 typedef NDNBOOST_DEDUCED_TYPENAME range_iterator<T const>::type const_iterator;
257 typedef NDNBOOST_DEDUCED_TYPENAME range_iterator<T>::type iterator;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700258
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700259 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept<iterator>));
260 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept<const_iterator>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700261
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700262 NDNBOOST_CONCEPT_USAGE(SinglePassRangeConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700263 {
264 // This has been modified from assigning to this->i
265 // (where i was a member variable) to improve
266 // compatibility with Boost.Lambda
267 iterator i1 = ndnboost::begin(*m_range);
268 iterator i2 = ndnboost::end(*m_range);
269
270 ignore_unused_variable_warning(i1);
271 ignore_unused_variable_warning(i2);
272
273 const_constraints(*m_range);
274 }
275
276 private:
277 void const_constraints(const T& const_range)
278 {
279 const_iterator ci1 = ndnboost::begin(const_range);
280 const_iterator ci2 = ndnboost::end(const_range);
281
282 ignore_unused_variable_warning(ci1);
283 ignore_unused_variable_warning(ci2);
284 }
285
286 // Rationale:
287 // The type of m_range is T* rather than T because it allows
288 // T to be an abstract class. The other obvious alternative of
289 // T& produces a warning on some compilers.
290 T* m_range;
291#endif
292 };
293
294 //! Check if a type T models the ForwardRange range concept.
295 template<class T>
296 struct ForwardRangeConcept : SinglePassRangeConcept<T>
297 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700298#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
299 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<NDNBOOST_DEDUCED_TYPENAME ForwardRangeConcept::iterator>));
300 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<NDNBOOST_DEDUCED_TYPENAME ForwardRangeConcept::const_iterator>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700301#endif
302 };
303
304 template<class Range>
305 struct WriteableRangeConcept
306 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700307#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
308 typedef NDNBOOST_DEDUCED_TYPENAME range_iterator<Range>::type iterator;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700309
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700310 NDNBOOST_CONCEPT_USAGE(WriteableRangeConcept)
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700311 {
312 *i = v;
313 }
314 private:
315 iterator i;
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700316 NDNBOOST_DEDUCED_TYPENAME range_value<Range>::type v;
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700317#endif
318 };
319
320 //! Check if a type T models the WriteableForwardRange range concept.
321 template<class T>
322 struct WriteableForwardRangeConcept
323 : ForwardRangeConcept<T>
324 , WriteableRangeConcept<T>
325 {
326 };
327
328 //! Check if a type T models the BidirectionalRange range concept.
329 template<class T>
330 struct BidirectionalRangeConcept : ForwardRangeConcept<T>
331 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700332#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
333 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<NDNBOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::iterator>));
334 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<NDNBOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::const_iterator>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700335#endif
336 };
337
338 //! Check if a type T models the WriteableBidirectionalRange range concept.
339 template<class T>
340 struct WriteableBidirectionalRangeConcept
341 : BidirectionalRangeConcept<T>
342 , WriteableRangeConcept<T>
343 {
344 };
345
346 //! Check if a type T models the RandomAccessRange range concept.
347 template<class T>
348 struct RandomAccessRangeConcept : BidirectionalRangeConcept<T>
349 {
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700350#if NDNBOOST_RANGE_ENABLE_CONCEPT_ASSERT
351 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<NDNBOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::iterator>));
352 NDNBOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<NDNBOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::const_iterator>));
Jeff Thompsonef2d5a42013-08-22 19:09:24 -0700353#endif
354 };
355
356 //! Check if a type T models the WriteableRandomAccessRange range concept.
357 template<class T>
358 struct WriteableRandomAccessRangeConcept
359 : RandomAccessRangeConcept<T>
360 , WriteableRangeConcept<T>
361 {
362 };
363
364} // namespace ndnboost
365
Jeff Thompson3d613fd2013-10-15 15:39:04 -0700366#endif // NDNBOOST_RANGE_CONCEPTS_HPP