mirror of
https://github.com/boostorg/iterator.git
synced 2025-07-29 20:37:17 +02:00
Extracted is_iterator trait to a separate header.
Also, reworked is_iterator to be more robust against various corner cases and added dedicated tests for the type trait.
This commit is contained in:
148
include/boost/iterator/is_iterator.hpp
Normal file
148
include/boost/iterator/is_iterator.hpp
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* https://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2023 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file iterator/is_iterator.hpp
|
||||
*
|
||||
* This header contains definition of the \c is_iterator type trait.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_ITERATOR_IS_ITERATOR_HPP_INCLUDED_
|
||||
#define BOOST_ITERATOR_IS_ITERATOR_HPP_INCLUDED_
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/negation.hpp>
|
||||
#include <boost/type_traits/conjunction.hpp>
|
||||
#include <boost/type_traits/is_complete.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#if !defined(BOOST_NO_CXX17_ITERATOR_TRAITS)
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace iterators {
|
||||
namespace detail {
|
||||
|
||||
// The trait attempts to detect if the T type is an iterator class. Class-type iterators are assumed
|
||||
// to have the nested type iterator_category. Strictly speaking, this is not required to be the
|
||||
// case (e.g. a user can specialize iterator_traits for T without defining T::iterator_category).
|
||||
// Still, this is a good heuristic in practice, and we can't do anything better anyway.
|
||||
// Since C++17 we can test for iterator_traits<T>::iterator_category presence instead as it is
|
||||
// required to be only present for iterators.
|
||||
namespace has_iterator_category_detail {
|
||||
|
||||
typedef char yes_type;
|
||||
struct no_type { char padding[2]; };
|
||||
|
||||
template< typename T >
|
||||
yes_type check(
|
||||
#if !defined(BOOST_NO_CXX17_ITERATOR_TRAITS)
|
||||
typename std::iterator_traits< T >::iterator_category*
|
||||
#else
|
||||
typename T::iterator_category*
|
||||
#endif
|
||||
);
|
||||
template< typename >
|
||||
no_type check(...);
|
||||
|
||||
} // namespace has_iterator_category_detail
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator_impl :
|
||||
public boost::integral_constant<
|
||||
bool,
|
||||
sizeof(has_iterator_category_detail::check< T >(0)) == sizeof(has_iterator_category_detail::yes_type)
|
||||
>
|
||||
{
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator_impl< T* > :
|
||||
public boost::conjunction<
|
||||
boost::is_complete< T >,
|
||||
boost::negation< boost::is_function< T > >
|
||||
>::type
|
||||
{
|
||||
};
|
||||
|
||||
template< typename T, typename U >
|
||||
struct is_iterator_impl< T U::* > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator_impl< T& > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template< typename T, std::size_t N >
|
||||
struct is_iterator_impl< T[N] > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
#if !defined(BOOST_TT_HAS_WORKING_IS_COMPLETE)
|
||||
template< typename T >
|
||||
struct is_iterator_impl< T[] > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template< >
|
||||
struct is_iterator_impl< void > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template< >
|
||||
struct is_iterator_impl< void* > :
|
||||
public boost::false_type
|
||||
{
|
||||
};
|
||||
#endif // !defined(BOOST_TT_HAS_WORKING_IS_COMPLETE)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/*!
|
||||
* \brief The type trait detects whether the type \c T is an iterator type.
|
||||
*
|
||||
* The type trait yields \c true if its argument type \c T, after stripping top level
|
||||
* cv qualifiers, is one of the following:
|
||||
*
|
||||
* - A pointer type, other than a pointer to function, a pointer to a class member,
|
||||
* or a pointer to an incomplete type, including `void`.
|
||||
* - A class type for which an iterator category is obtainable. Prior to C++17,
|
||||
* the iterator category must be defined as a public `T::iterator_category` type.
|
||||
* Since C++17, the expression `std::iterator_traits< T >::iterator_category` must
|
||||
* be valid and produce the iterator category type.
|
||||
*
|
||||
* Otherwise, the type trait yields \c false.
|
||||
*/
|
||||
template< typename T >
|
||||
struct is_iterator : public detail::is_iterator_impl< T >::type {};
|
||||
template< typename T >
|
||||
struct is_iterator< const T > : public detail::is_iterator_impl< T >::type {};
|
||||
template< typename T >
|
||||
struct is_iterator< volatile T > : public detail::is_iterator_impl< T >::type {};
|
||||
template< typename T >
|
||||
struct is_iterator< const volatile T > : public detail::is_iterator_impl< T >::type {};
|
||||
|
||||
} // namespace iterators
|
||||
|
||||
using iterators::is_iterator;
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_ITERATOR_IS_ITERATOR_HPP_INCLUDED_
|
@ -15,13 +15,12 @@
|
||||
#ifndef BOOST_NEXT_PRIOR_HPP_INCLUDED
|
||||
#define BOOST_NEXT_PRIOR_HPP_INCLUDED
|
||||
|
||||
#include <iterator>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/type_traits/has_plus.hpp>
|
||||
#include <boost/type_traits/has_plus_assign.hpp>
|
||||
#include <boost/type_traits/has_minus.hpp>
|
||||
#include <boost/type_traits/has_minus_assign.hpp>
|
||||
#include <boost/iterator/is_iterator.hpp>
|
||||
#include <boost/iterator/advance.hpp>
|
||||
#include <boost/iterator/reverse_iterator.hpp>
|
||||
|
||||
@ -39,46 +38,6 @@ namespace boost {
|
||||
|
||||
namespace next_prior_detail {
|
||||
|
||||
// The trait attempts to detect if the T type is an iterator. Class-type iterators are assumed
|
||||
// to have the nested type iterator_category. Strictly speaking, this is not required to be the
|
||||
// case (e.g. a user can specialize iterator_traits for T without defining T::iterator_category).
|
||||
// Still, this is a good heuristic in practice, and we can't do anything better anyway.
|
||||
// Since C++17 we can test for iterator_traits<T>::iterator_category presence instead as it is
|
||||
// required to be only present for iterators.
|
||||
template< typename T, typename Void = void >
|
||||
struct is_iterator_class
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST bool value = false;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator_class<
|
||||
T,
|
||||
typename enable_if_has_type<
|
||||
#if !defined(BOOST_NO_CXX17_ITERATOR_TRAITS)
|
||||
typename std::iterator_traits< T >::iterator_category
|
||||
#else
|
||||
typename T::iterator_category
|
||||
#endif
|
||||
>::type
|
||||
>
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST bool value = true;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator :
|
||||
public is_iterator_class< T >
|
||||
{
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct is_iterator< T* >
|
||||
{
|
||||
static BOOST_CONSTEXPR_OR_CONST bool value = true;
|
||||
};
|
||||
|
||||
|
||||
template< typename T, typename Distance, bool HasPlus = has_plus< T, Distance >::value >
|
||||
struct next_plus_impl;
|
||||
|
||||
@ -107,7 +66,7 @@ struct next_plus_assign_impl< T, Distance, true >
|
||||
}
|
||||
};
|
||||
|
||||
template< typename T, typename Distance, bool IsIterator = is_iterator< T >::value >
|
||||
template< typename T, typename Distance, bool IsIterator = boost::iterators::is_iterator< T >::value >
|
||||
struct next_advance_impl :
|
||||
public next_plus_assign_impl< T, Distance >
|
||||
{
|
||||
@ -152,7 +111,7 @@ struct prior_minus_assign_impl< T, Distance, true >
|
||||
}
|
||||
};
|
||||
|
||||
template< typename T, typename Distance, bool IsIterator = is_iterator< T >::value >
|
||||
template< typename T, typename Distance, bool IsIterator = boost::iterators::is_iterator< T >::value >
|
||||
struct prior_advance_impl :
|
||||
public prior_minus_assign_impl< T, Distance >
|
||||
{
|
||||
|
@ -26,6 +26,8 @@ test-suite iterator
|
||||
[ run zip_iterator_test_std_tuple.cpp ]
|
||||
[ run zip_iterator_test_std_pair.cpp ]
|
||||
|
||||
[ run is_iterator.cpp ]
|
||||
|
||||
# These tests should work for just about everything.
|
||||
[ compile is_lvalue_iterator.cpp ]
|
||||
[ compile is_readable_iterator.cpp ]
|
||||
|
164
test/is_iterator.cpp
Normal file
164
test/is_iterator.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* https://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* Copyright (c) 2023 Andrey Semashev
|
||||
*/
|
||||
/*!
|
||||
* \file is_iterator.cpp
|
||||
*
|
||||
* This header contains tests for the \c is_iterator type trait.
|
||||
*/
|
||||
|
||||
#include <boost/iterator/is_iterator.hpp>
|
||||
#include <cstddef>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
template< typename T >
|
||||
struct value_iterator
|
||||
{
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef T value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
|
||||
value_type operator*() const;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct proxy_iterator
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef std::output_iterator_tag iterator_category;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
|
||||
struct proxy
|
||||
{
|
||||
operator value_type&() const;
|
||||
proxy& operator=(value_type) const;
|
||||
};
|
||||
|
||||
proxy operator*() const;
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct lvalue_iterator
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T difference_type;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef T* pointer;
|
||||
|
||||
T& operator*() const;
|
||||
lvalue_iterator& operator++();
|
||||
lvalue_iterator operator++(int);
|
||||
};
|
||||
|
||||
template< typename T >
|
||||
struct constant_lvalue_iterator
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T const& reference;
|
||||
typedef T difference_type;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef T const* pointer;
|
||||
|
||||
T const& operator*() const;
|
||||
constant_lvalue_iterator& operator++();
|
||||
constant_lvalue_iterator operator++(int);
|
||||
};
|
||||
|
||||
template< typename Iterator >
|
||||
class adapted_iterator :
|
||||
public boost::iterators::iterator_adaptor< adapted_iterator< Iterator >, Iterator >
|
||||
{
|
||||
friend class iterator_core_access;
|
||||
|
||||
private:
|
||||
typedef boost::iterators::iterator_adaptor< adapted_iterator< Iterator >, Iterator > base_type;
|
||||
|
||||
private:
|
||||
typename base_type::reference dereference() const;
|
||||
void increment();
|
||||
void decrement();
|
||||
void advance(typename base_type::difference_type n);
|
||||
template< typename OtherIterator >
|
||||
typename base_type::difference_type distance_to(adapted_iterator< OtherIterator > const& y) const;
|
||||
};
|
||||
|
||||
struct complete {};
|
||||
struct incomplete;
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_TEST(boost::iterators::is_iterator< int* >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< const int* >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< complete* >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::reverse_iterator< int* > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::reverse_iterator< complete* > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< adapted_iterator< int* > >::value);
|
||||
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::string::iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::string::const_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::string::reverse_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::string::const_reverse_iterator >::value);
|
||||
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::list< int >::iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::list< int >::const_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::list< int >::reverse_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::list< int >::const_reverse_iterator >::value);
|
||||
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::vector< int >::iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::vector< int >::const_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::vector< int >::reverse_iterator >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::vector< int >::const_reverse_iterator >::value);
|
||||
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::insert_iterator< std::vector< int > > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::back_insert_iterator< std::vector< int > > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::front_insert_iterator< std::vector< int > > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::istream_iterator< int > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::ostream_iterator< int > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::istreambuf_iterator< char > >::value);
|
||||
BOOST_TEST(boost::iterators::is_iterator< std::ostreambuf_iterator< char > >::value);
|
||||
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< complete >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< void >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< const void >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< void* >::value);
|
||||
#if defined(BOOST_TT_HAS_WORKING_IS_COMPLETE)
|
||||
BOOST_TEST(!boost::iterators::is_iterator< incomplete >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< incomplete* >::value);
|
||||
#endif
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (int) >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (*)(int) >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int complete::* >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (complete::*)(int) >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (complete::*)(int) const >::value);
|
||||
#if defined(__cpp_noexcept_function_type) && (__cpp_noexcept_function_type >= 201510L)
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (*)(int) noexcept >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (complete::*)(int) noexcept >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (complete::*)(int) const noexcept >::value);
|
||||
#endif
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int[] >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int[10] >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int*[] >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int*[10] >::value);
|
||||
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int& >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int*& >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (&)(int) >::value);
|
||||
BOOST_TEST(!boost::iterators::is_iterator< int (&)[10] >::value);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
Reference in New Issue
Block a user