concepts.hpp 13 KB

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