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
|