diff --git a/include/boost/iterator/is_iterator.hpp b/include/boost/iterator/is_iterator.hpp new file mode 100644 index 0000000..5740b19 --- /dev/null +++ b/include/boost/iterator/is_iterator.hpp @@ -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 +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX17_ITERATOR_TRAITS) +#include +#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::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_ diff --git a/include/boost/next_prior.hpp b/include/boost/next_prior.hpp index 5de705f..d943b97 100644 --- a/include/boost/next_prior.hpp +++ b/include/boost/next_prior.hpp @@ -15,13 +15,12 @@ #ifndef BOOST_NEXT_PRIOR_HPP_INCLUDED #define BOOST_NEXT_PRIOR_HPP_INCLUDED -#include #include -#include #include #include #include #include +#include #include #include @@ -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::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 > { diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 96e440b..0cd9b7f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -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 ] diff --git a/test/is_iterator.cpp b/test/is_iterator.cpp new file mode 100644 index 0000000..7d67dda --- /dev/null +++ b/test/is_iterator.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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(); +}