concepts.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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, but the correct standard conformant iterators
  89. // do require the iterators to be a model of the Assignable concept.
  90. // Iterators that contains a functor that is not assignable therefore
  91. // are not correct models of the standard iterator concepts,
  92. // despite being adequate for most algorithms. An example of this
  93. // use case is the combination of the boost::adaptors::filtered
  94. // class with a boost::lambda::bind generated functor.
  95. // Ultimately modeling the range concepts using composition
  96. // with the Boost.Iterator concepts would render the library
  97. // incompatible with many common Boost.Lambda expressions.
  98. template<class Iterator>
  99. struct IncrementableIteratorConcept : CopyConstructible<Iterator>
  100. {
  101. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  102. typedef BOOST_DEDUCED_TYPENAME iterator_traversal<Iterator>::type traversal_category;
  103. BOOST_RANGE_CONCEPT_ASSERT((
  104. Convertible<
  105. traversal_category,
  106. incrementable_traversal_tag
  107. >));
  108. BOOST_CONCEPT_USAGE(IncrementableIteratorConcept)
  109. {
  110. ++i;
  111. (void)i++;
  112. }
  113. private:
  114. Iterator i;
  115. #endif
  116. };
  117. template<class Iterator>
  118. struct SinglePassIteratorConcept
  119. : IncrementableIteratorConcept<Iterator>
  120. , EqualityComparable<Iterator>
  121. {
  122. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  123. BOOST_RANGE_CONCEPT_ASSERT((
  124. Convertible<
  125. BOOST_DEDUCED_TYPENAME SinglePassIteratorConcept::traversal_category,
  126. single_pass_traversal_tag
  127. >));
  128. #endif
  129. };
  130. template<class Iterator>
  131. struct ForwardIteratorConcept
  132. : SinglePassIteratorConcept<Iterator>
  133. , DefaultConstructible<Iterator>
  134. {
  135. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  136. typedef BOOST_DEDUCED_TYPENAME boost::detail::iterator_traits<Iterator>::difference_type difference_type;
  137. BOOST_MPL_ASSERT((is_integral<difference_type>));
  138. BOOST_MPL_ASSERT_RELATION(std::numeric_limits<difference_type>::is_signed, ==, true);
  139. BOOST_RANGE_CONCEPT_ASSERT((
  140. Convertible<
  141. BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category,
  142. forward_traversal_tag
  143. >));
  144. #endif
  145. };
  146. template<class Iterator>
  147. struct BidirectionalIteratorConcept
  148. : ForwardIteratorConcept<Iterator>
  149. {
  150. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  151. BOOST_RANGE_CONCEPT_ASSERT((
  152. Convertible<
  153. BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept::traversal_category,
  154. bidirectional_traversal_tag
  155. >));
  156. BOOST_CONCEPT_USAGE(BidirectionalIteratorConcept)
  157. {
  158. --i;
  159. (void)i--;
  160. }
  161. private:
  162. Iterator i;
  163. #endif
  164. };
  165. template<class Iterator>
  166. struct RandomAccessIteratorConcept
  167. : BidirectionalIteratorConcept<Iterator>
  168. {
  169. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  170. BOOST_RANGE_CONCEPT_ASSERT((
  171. Convertible<
  172. BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::traversal_category,
  173. random_access_traversal_tag
  174. >));
  175. BOOST_CONCEPT_USAGE(RandomAccessIteratorConcept)
  176. {
  177. i += n;
  178. i = i + n;
  179. i = n + i;
  180. i -= n;
  181. i = i - n;
  182. n = i - j;
  183. }
  184. private:
  185. BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::difference_type n;
  186. Iterator i;
  187. Iterator j;
  188. #endif
  189. };
  190. } // namespace range_detail
  191. //! Check if a type T models the SinglePassRange range concept.
  192. template<class T>
  193. struct SinglePassRangeConcept
  194. {
  195. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  196. typedef BOOST_DEDUCED_TYPENAME range_iterator<T const>::type const_iterator;
  197. typedef BOOST_DEDUCED_TYPENAME range_iterator<T>::type iterator;
  198. BOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept<iterator>));
  199. BOOST_RANGE_CONCEPT_ASSERT((range_detail::SinglePassIteratorConcept<const_iterator>));
  200. BOOST_CONCEPT_USAGE(SinglePassRangeConcept)
  201. {
  202. // This has been modified from assigning to this->i
  203. // (where i was a member variable) to improve
  204. // compatibility with Boost.Lambda
  205. iterator i1 = boost::begin(*m_range);
  206. iterator i2 = boost::end(*m_range);
  207. ignore_unused_variable_warning(i1);
  208. ignore_unused_variable_warning(i2);
  209. const_constraints(*m_range);
  210. }
  211. private:
  212. void const_constraints(const T& const_range)
  213. {
  214. const_iterator ci1 = boost::begin(const_range);
  215. const_iterator ci2 = boost::end(const_range);
  216. ignore_unused_variable_warning(ci1);
  217. ignore_unused_variable_warning(ci2);
  218. }
  219. // Rationale:
  220. // The type of m_range is T* rather than T because it allows
  221. // T to be an abstract class. The other obvious alternative of
  222. // T& produces a warning on some compilers.
  223. T* m_range;
  224. #endif
  225. };
  226. //! Check if a type T models the ForwardRange range concept.
  227. template<class T>
  228. struct ForwardRangeConcept : SinglePassRangeConcept<T>
  229. {
  230. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  231. BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::iterator>));
  232. BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::const_iterator>));
  233. #endif
  234. };
  235. template<class Range>
  236. struct WriteableRangeConcept
  237. {
  238. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  239. typedef BOOST_DEDUCED_TYPENAME range_iterator<Range>::type iterator;
  240. BOOST_CONCEPT_USAGE(WriteableRangeConcept)
  241. {
  242. *i = v;
  243. }
  244. private:
  245. iterator i;
  246. BOOST_DEDUCED_TYPENAME range_value<Range>::type v;
  247. #endif
  248. };
  249. //! Check if a type T models the WriteableForwardRange range concept.
  250. template<class T>
  251. struct WriteableForwardRangeConcept
  252. : ForwardRangeConcept<T>
  253. , WriteableRangeConcept<T>
  254. {
  255. };
  256. //! Check if a type T models the BidirectionalRange range concept.
  257. template<class T>
  258. struct BidirectionalRangeConcept : ForwardRangeConcept<T>
  259. {
  260. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  261. BOOST_RANGE_CONCEPT_ASSERT((BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::iterator>));
  262. BOOST_RANGE_CONCEPT_ASSERT((BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::const_iterator>));
  263. #endif
  264. };
  265. //! Check if a type T models the WriteableBidirectionalRange range concept.
  266. template<class T>
  267. struct WriteableBidirectionalRangeConcept
  268. : BidirectionalRangeConcept<T>
  269. , WriteableRangeConcept<T>
  270. {
  271. };
  272. //! Check if a type T models the RandomAccessRange range concept.
  273. template<class T>
  274. struct RandomAccessRangeConcept : BidirectionalRangeConcept<T>
  275. {
  276. #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
  277. BOOST_RANGE_CONCEPT_ASSERT((RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::iterator>));
  278. BOOST_RANGE_CONCEPT_ASSERT((RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::const_iterator>));
  279. #endif
  280. };
  281. //! Check if a type T models the WriteableRandomAccessRange range concept.
  282. template<class T>
  283. struct WriteableRandomAccessRangeConcept
  284. : RandomAccessRangeConcept<T>
  285. , WriteableRangeConcept<T>
  286. {
  287. };
  288. } // namespace boost
  289. #endif // BOOST_RANGE_CONCEPTS_HPP