389 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			389 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | // Boost.Range library concept checks
 | ||
|  | //
 | ||
|  | //  Copyright Neil Groves 2009. Use, modification and distribution
 | ||
|  | //  are subject to the Boost Software License, Version 1.0. (See
 | ||
|  | //  accompanying file LICENSE_1_0.txt or copy at
 | ||
|  | //  http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | //
 | ||
|  | //  Copyright Daniel Walker 2006. Use, modification and distribution
 | ||
|  | //  are subject to the Boost Software License, Version 1.0. (See
 | ||
|  | //  accompanying file LICENSE_1_0.txt or copy at
 | ||
|  | //  http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | //
 | ||
|  | // For more information, see http://www.boost.org/libs/range/
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #ifndef BOOST_RANGE_CONCEPTS_HPP
 | ||
|  | #define BOOST_RANGE_CONCEPTS_HPP
 | ||
|  | 
 | ||
|  | #include <boost/concept_check.hpp>
 | ||
|  | #include <boost/iterator/iterator_concepts.hpp>
 | ||
|  | #include <boost/range/begin.hpp>
 | ||
|  | #include <boost/range/end.hpp>
 | ||
|  | #include <boost/range/iterator.hpp>
 | ||
|  | #include <boost/range/value_type.hpp>
 | ||
|  | #include <boost/range/detail/misc_concept.hpp>
 | ||
|  | #include <boost/type_traits/remove_reference.hpp>
 | ||
|  | 
 | ||
|  | #include <iterator>
 | ||
|  | 
 | ||
|  | /*!
 | ||
|  |  * \file | ||
|  |  * \brief Concept checks for the Boost Range library. | ||
|  |  * | ||
|  |  * The structures in this file may be used in conjunction with the | ||
|  |  * Boost Concept Check library to insure that the type of a function | ||
|  |  * parameter is compatible with a range concept. If not, a meaningful | ||
|  |  * compile time error is generated. Checks are provided for the range | ||
|  |  * concepts related to iterator traversal categories. For example, the | ||
|  |  * following line checks that the type T models the ForwardRange | ||
|  |  * concept. | ||
|  |  * | ||
|  |  * \code | ||
|  |  * BOOST_CONCEPT_ASSERT((ForwardRangeConcept<T>)); | ||
|  |  * \endcode | ||
|  |  * | ||
|  |  * A different concept check is required to ensure writeable value | ||
|  |  * access. For example to check for a ForwardRange that can be written | ||
|  |  * to, the following code is required. | ||
|  |  * | ||
|  |  * \code | ||
|  |  * BOOST_CONCEPT_ASSERT((WriteableForwardRangeConcept<T>)); | ||
|  |  * \endcode | ||
|  |  * | ||
|  |  * \see http://www.boost.org/libs/range/doc/range.html for details
 | ||
|  |  * about range concepts. | ||
|  |  * \see http://www.boost.org/libs/iterator/doc/iterator_concepts.html
 | ||
|  |  * for details about iterator concepts. | ||
|  |  * \see http://www.boost.org/libs/concept_check/concept_check.htm for
 | ||
|  |  * details about concept checks. | ||
|  |  */ | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | 
 | ||
|  |     namespace range_detail { | ||
|  | 
 | ||
|  | #ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  | 
 | ||
|  | // List broken compiler versions here:
 | ||
|  | #ifndef __clang__
 | ||
|  |     #ifdef __GNUC__
 | ||
|  |         // GNUC 4.2 has strange issues correctly detecting compliance with the Concepts
 | ||
|  |         // hence the least disruptive approach is to turn-off the concept checking for
 | ||
|  |         // this version of the compiler.
 | ||
|  |         #if __GNUC__ == 4 && __GNUC_MINOR__ == 2
 | ||
|  |             #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
 | ||
|  |         #endif
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  |     #ifdef __GCCXML__
 | ||
|  |         // GCC XML, unsurprisingly, has the same issues
 | ||
|  |         #if __GCCXML_GNUC__ == 4 && __GCCXML_GNUC_MINOR__ == 2
 | ||
|  |             #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
 | ||
|  |         #endif
 | ||
|  |     #endif
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     #ifdef BOOST_BORLANDC
 | ||
|  |         #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  |     #ifdef __PATHCC__
 | ||
|  |         #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 0
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  | // Default to using the concept asserts unless we have defined it off
 | ||
|  | // during the search for black listed compilers.
 | ||
|  |     #ifndef BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         #define BOOST_RANGE_ENABLE_CONCEPT_ASSERT 1
 | ||
|  |     #endif
 | ||
|  | 
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |     #define BOOST_RANGE_CONCEPT_ASSERT( x ) BOOST_CONCEPT_ASSERT( x )
 | ||
|  | #else
 | ||
|  |     #define BOOST_RANGE_CONCEPT_ASSERT( x )
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |         // Rationale for the inclusion of redefined iterator concept
 | ||
|  |         // classes:
 | ||
|  |         //
 | ||
|  |         // The Range algorithms often do not require that the iterators are
 | ||
|  |         // Assignable or default constructable, but the correct standard
 | ||
|  |         // conformant iterators do require the iterators to be a model of the
 | ||
|  |         // Assignable concept.
 | ||
|  |         // Iterators that contains a functor that is not assignable therefore
 | ||
|  |         // are not correct models of the standard iterator concepts,
 | ||
|  |         // despite being adequate for most algorithms. An example of this
 | ||
|  |         // use case is the combination of the boost::adaptors::filtered
 | ||
|  |         // class with a boost::lambda::bind generated functor.
 | ||
|  |         // Ultimately modeling the range concepts using composition
 | ||
|  |         // with the Boost.Iterator concepts would render the library
 | ||
|  |         // incompatible with many common Boost.Lambda expressions.
 | ||
|  |         template<class Iterator> | ||
|  |         struct IncrementableIteratorConcept : CopyConstructible<Iterator> | ||
|  |         { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |             typedef BOOST_DEDUCED_TYPENAME iterator_traversal<Iterator>::type traversal_category; | ||
|  | 
 | ||
|  |             BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                 Convertible< | ||
|  |                     traversal_category, | ||
|  |                     incrementable_traversal_tag | ||
|  |                 >)); | ||
|  | 
 | ||
|  |             BOOST_CONCEPT_USAGE(IncrementableIteratorConcept) | ||
|  |             { | ||
|  |                 ++i; | ||
|  |                 (void)i++; | ||
|  |             } | ||
|  |         private: | ||
|  |             Iterator i; | ||
|  | #endif
 | ||
|  |         }; | ||
|  | 
 | ||
|  |         template<class Iterator> | ||
|  |         struct SinglePassIteratorConcept | ||
|  |             : IncrementableIteratorConcept<Iterator> | ||
|  |             , EqualityComparable<Iterator> | ||
|  |         { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |             BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                 Convertible< | ||
|  |                     BOOST_DEDUCED_TYPENAME SinglePassIteratorConcept::traversal_category, | ||
|  |                     single_pass_traversal_tag | ||
|  |                 >)); | ||
|  | 
 | ||
|  |             BOOST_CONCEPT_USAGE(SinglePassIteratorConcept) | ||
|  |             { | ||
|  |                 Iterator i2(++i); | ||
|  |                 boost::ignore_unused_variable_warning(i2); | ||
|  | 
 | ||
|  |                 // deliberately we are loose with the postfix version for the single pass
 | ||
|  |                 // iterator due to the commonly poor adherence to the specification means that
 | ||
|  |                 // many algorithms would be unusable, whereas actually without the check they
 | ||
|  |                 // work
 | ||
|  |                 (void)(i++); | ||
|  | 
 | ||
|  |                 BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r1(*i); | ||
|  |                 boost::ignore_unused_variable_warning(r1); | ||
|  | 
 | ||
|  |                 BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r2(*(++i)); | ||
|  |                 boost::ignore_unused_variable_warning(r2); | ||
|  |             } | ||
|  |         private: | ||
|  |             Iterator i; | ||
|  | #endif
 | ||
|  |         }; | ||
|  | 
 | ||
|  |         template<class Iterator> | ||
|  |         struct ForwardIteratorConcept | ||
|  |             : SinglePassIteratorConcept<Iterator> | ||
|  |             , DefaultConstructible<Iterator> | ||
|  |         { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |             typedef BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::difference_type difference_type; | ||
|  | 
 | ||
|  |             BOOST_MPL_ASSERT((is_integral<difference_type>)); | ||
|  |             BOOST_MPL_ASSERT_RELATION(std::numeric_limits<difference_type>::is_signed, ==, true); | ||
|  | 
 | ||
|  |             BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                 Convertible< | ||
|  |                     BOOST_DEDUCED_TYPENAME ForwardIteratorConcept::traversal_category, | ||
|  |                     forward_traversal_tag | ||
|  |                 >)); | ||
|  | 
 | ||
|  |             BOOST_CONCEPT_USAGE(ForwardIteratorConcept) | ||
|  |             { | ||
|  |                 // See the above note in the SinglePassIteratorConcept about the handling of the
 | ||
|  |                 // postfix increment. Since with forward and better iterators there is no need
 | ||
|  |                 // for a proxy, we can sensibly require that the dereference result
 | ||
|  |                 // is convertible to reference.
 | ||
|  |                 Iterator i2(i++); | ||
|  |                 boost::ignore_unused_variable_warning(i2); | ||
|  |                 BOOST_DEDUCED_TYPENAME std::iterator_traits<Iterator>::reference r(*(i++)); | ||
|  |                 boost::ignore_unused_variable_warning(r); | ||
|  |             } | ||
|  |         private: | ||
|  |             Iterator i; | ||
|  | #endif
 | ||
|  |          }; | ||
|  | 
 | ||
|  |          template<class Iterator> | ||
|  |          struct BidirectionalIteratorConcept | ||
|  |              : ForwardIteratorConcept<Iterator> | ||
|  |          { | ||
|  |  #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |              BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                  Convertible< | ||
|  |                      BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept::traversal_category, | ||
|  |                      bidirectional_traversal_tag | ||
|  |                  >)); | ||
|  | 
 | ||
|  |              BOOST_CONCEPT_USAGE(BidirectionalIteratorConcept) | ||
|  |              { | ||
|  |                  --i; | ||
|  |                  (void)i--; | ||
|  |              } | ||
|  |          private: | ||
|  |              Iterator i; | ||
|  |  #endif
 | ||
|  |          }; | ||
|  | 
 | ||
|  |          template<class Iterator> | ||
|  |          struct RandomAccessIteratorConcept | ||
|  |              : BidirectionalIteratorConcept<Iterator> | ||
|  |          { | ||
|  |  #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |              BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                  Convertible< | ||
|  |                      BOOST_DEDUCED_TYPENAME RandomAccessIteratorConcept::traversal_category, | ||
|  |                      random_access_traversal_tag | ||
|  |                  >)); | ||
|  | 
 | ||
|  |              BOOST_CONCEPT_USAGE(RandomAccessIteratorConcept) | ||
|  |              { | ||
|  |                  i += n; | ||
|  |                  i = i + n; | ||
|  |                  i = n + i; | ||
|  |                  i -= n; | ||
|  |                  i = i - n; | ||
|  |                  n = i - j; | ||
|  |              } | ||
|  |          private: | ||
|  |              BOOST_DEDUCED_TYPENAME BidirectionalIteratorConcept<Iterator>::difference_type n; | ||
|  |              Iterator i; | ||
|  |              Iterator j; | ||
|  |  #endif
 | ||
|  |          }; | ||
|  | 
 | ||
|  |     } // namespace range_detail
 | ||
|  | 
 | ||
|  |     //! Check if a type T models the SinglePassRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct SinglePassRangeConcept | ||
|  |     { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         // A few compilers don't like the rvalue reference T types so just
 | ||
|  |         // remove it.
 | ||
|  |         typedef BOOST_DEDUCED_TYPENAME remove_reference<T>::type Rng; | ||
|  | 
 | ||
|  |         typedef BOOST_DEDUCED_TYPENAME range_iterator< | ||
|  |             Rng const | ||
|  |         >::type const_iterator; | ||
|  | 
 | ||
|  |         typedef BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type iterator; | ||
|  | 
 | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                 range_detail::SinglePassIteratorConcept<iterator>)); | ||
|  | 
 | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT(( | ||
|  |                 range_detail::SinglePassIteratorConcept<const_iterator>)); | ||
|  | 
 | ||
|  |         BOOST_CONCEPT_USAGE(SinglePassRangeConcept) | ||
|  |         { | ||
|  |             // This has been modified from assigning to this->i
 | ||
|  |             // (where i was a member variable) to improve
 | ||
|  |             // compatibility with Boost.Lambda
 | ||
|  |             iterator i1 = boost::begin(*m_range); | ||
|  |             iterator i2 = boost::end(*m_range); | ||
|  | 
 | ||
|  |             boost::ignore_unused_variable_warning(i1); | ||
|  |             boost::ignore_unused_variable_warning(i2); | ||
|  | 
 | ||
|  |             const_constraints(*m_range); | ||
|  |         } | ||
|  | 
 | ||
|  |     private: | ||
|  |         void const_constraints(const Rng& const_range) | ||
|  |         { | ||
|  |             const_iterator ci1 = boost::begin(const_range); | ||
|  |             const_iterator ci2 = boost::end(const_range); | ||
|  | 
 | ||
|  |             boost::ignore_unused_variable_warning(ci1); | ||
|  |             boost::ignore_unused_variable_warning(ci2); | ||
|  |         } | ||
|  | 
 | ||
|  |        // Rationale:
 | ||
|  |        // The type of m_range is T* rather than T because it allows
 | ||
|  |        // T to be an abstract class. The other obvious alternative of
 | ||
|  |        // T& produces a warning on some compilers.
 | ||
|  |        Rng* m_range; | ||
|  | #endif
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the ForwardRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct ForwardRangeConcept : SinglePassRangeConcept<T> | ||
|  |     { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::iterator>)); | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::ForwardIteratorConcept<BOOST_DEDUCED_TYPENAME ForwardRangeConcept::const_iterator>)); | ||
|  | #endif
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     template<class T> | ||
|  |     struct WriteableRangeConcept | ||
|  |     { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         typedef BOOST_DEDUCED_TYPENAME range_iterator<T>::type iterator; | ||
|  | 
 | ||
|  |         BOOST_CONCEPT_USAGE(WriteableRangeConcept) | ||
|  |         { | ||
|  |             *i = v; | ||
|  |         } | ||
|  |     private: | ||
|  |         iterator i; | ||
|  |         BOOST_DEDUCED_TYPENAME range_value<T>::type v; | ||
|  | #endif
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the WriteableForwardRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct WriteableForwardRangeConcept | ||
|  |         : ForwardRangeConcept<T> | ||
|  |         , WriteableRangeConcept<T> | ||
|  |     { | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the BidirectionalRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct BidirectionalRangeConcept : ForwardRangeConcept<T> | ||
|  |     { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::iterator>)); | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::BidirectionalIteratorConcept<BOOST_DEDUCED_TYPENAME BidirectionalRangeConcept::const_iterator>)); | ||
|  | #endif
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the WriteableBidirectionalRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct WriteableBidirectionalRangeConcept | ||
|  |         : BidirectionalRangeConcept<T> | ||
|  |         , WriteableRangeConcept<T> | ||
|  |     { | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the RandomAccessRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct RandomAccessRangeConcept : BidirectionalRangeConcept<T> | ||
|  |     { | ||
|  | #if BOOST_RANGE_ENABLE_CONCEPT_ASSERT
 | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::iterator>)); | ||
|  |         BOOST_RANGE_CONCEPT_ASSERT((range_detail::RandomAccessIteratorConcept<BOOST_DEDUCED_TYPENAME RandomAccessRangeConcept::const_iterator>)); | ||
|  | #endif
 | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Check if a type T models the WriteableRandomAccessRange range concept.
 | ||
|  |     template<class T> | ||
|  |     struct WriteableRandomAccessRangeConcept | ||
|  |         : RandomAccessRangeConcept<T> | ||
|  |         , WriteableRangeConcept<T> | ||
|  |     { | ||
|  |     }; | ||
|  | 
 | ||
|  | } // namespace boost
 | ||
|  | 
 | ||
|  | #endif // BOOST_RANGE_CONCEPTS_HPP
 |