concepts.hpp 13 KB

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