From dec7d0f24c01938a32c41104fcb3cb6a0cf2cdc5 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 27 Jan 2025 00:04:13 +0300 Subject: [PATCH] Extracted min_category as a variadic metafunction. The new min_category is similar to minimum_category but accepts variable number of iterator categories on input instead of just two, and also does not depend on Boost.MPL for lambda placeholders. The existing minimum_category trait has been reimplemented in terms of min_category and deprecated. We don't yet emit deprecation warnings as there is still code that uses the old trait which we first need to update. Eventually, minimum_category will emit warnings and will be removed. --- doc/quickbook/type_traits.qbk | 6 +- include/boost/iterator/min_category.hpp | 83 +++++++++++++++++++++ include/boost/iterator/minimum_category.hpp | 49 ++---------- test/Jamfile.v2 | 3 + test/min_category.cpp | 33 ++++++++ test/min_category_compile_fail1.cpp | 19 +++++ test/min_category_compile_fail2.cpp | 16 ++++ test/test_cmake/main.cpp | 1 + 8 files changed, 165 insertions(+), 45 deletions(-) create mode 100644 include/boost/iterator/min_category.hpp create mode 100644 test/min_category.cpp create mode 100644 test/min_category_compile_fail1.cpp create mode 100644 test/min_category_compile_fail2.cpp diff --git a/doc/quickbook/type_traits.qbk b/doc/quickbook/type_traits.qbk index 090d357..d4cf9cd 100644 --- a/doc/quickbook/type_traits.qbk +++ b/doc/quickbook/type_traits.qbk @@ -48,14 +48,14 @@ information is needed, call on `indirect_reference`. Both of these templates are essential to the correct functioning of [link iterator.specialized.indirect `indirect_iterator`]. -[h2 `minimum_category`] +[h2 `min_category`] -`minimum_category` takes two iterator categories or two iterator traversal tags +`min_category` takes one or more iterator categories or iterator traversal tags and returns the one that is the weakest (i.e. least advanced). For example: static_assert( is_same< - minimum_category< + min_category< std::forward_iterator_tag, std::random_access_iterator_tag >::type, diff --git a/include/boost/iterator/min_category.hpp b/include/boost/iterator/min_category.hpp new file mode 100644 index 0000000..67be58c --- /dev/null +++ b/include/boost/iterator/min_category.hpp @@ -0,0 +1,83 @@ +// Copyright Andrey Semashev 2025. +// +// 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) + +#ifndef BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_ +#define BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_ + +#include + +namespace boost { +namespace iterators { +namespace detail { + +template< + typename T1, + typename T2, + bool GreaterEqual = std::is_convertible< T1, T2 >::value, + bool LessEqual = std::is_convertible< T2, T1 >::value +> +struct min_category_impl +{ + static_assert(GreaterEqual || LessEqual, "Iterator category types must be related through convertibility."); +}; + +template< typename T1, typename T2 > +struct min_category_impl< T1, T2, true, false > +{ + using type = T2; +}; + +template< typename T1, typename T2 > +struct min_category_impl< T1, T2, false, true > +{ + using type = T1; +}; + +template< typename T1, typename T2 > +struct min_category_impl< T1, T2, true, true > +{ + static_assert(std::is_same< T1, T2 >::value, "Iterator category types must be the same when they are equivalent."); + using type = T1; +}; + +} // namespace detail + +// +// Returns the minimum iterator category type in the list +// or fails to compile if any of the categories are unrelated. +// +template< typename... Categories > +struct min_category; + +template< typename T > +struct min_category< T > +{ + using type = T; +}; + +template< typename T1, typename T2, typename... Tail > +struct min_category< T1, T2, Tail... > +{ + using type = typename min_category< + typename iterators::detail::min_category_impl< T1, T2 >::type, + Tail... + >::type; +}; + +// Shortcut to slightly optimize compilation speed +template< typename T1, typename T2 > +struct min_category< T1, T2 > +{ + using type = typename iterators::detail::min_category_impl< T1, T2 >::type; +}; + +template< typename... Categories > +using min_category_t = typename min_category< Categories... >::type; + +} // namespace iterators +} // namespace boost + +#endif // BOOST_ITERATOR_MIN_CATEGORY_HPP_INCLUDED_ diff --git a/include/boost/iterator/minimum_category.hpp b/include/boost/iterator/minimum_category.hpp index 7b16d61..4d8a93f 100644 --- a/include/boost/iterator/minimum_category.hpp +++ b/include/boost/iterator/minimum_category.hpp @@ -4,61 +4,26 @@ #ifndef BOOST_ITERATOR_MINIMUM_CATEGORY_HPP_INCLUDED_ #define BOOST_ITERATOR_MINIMUM_CATEGORY_HPP_INCLUDED_ -#include #include +#include namespace boost { namespace iterators { -namespace detail { -template -struct minimum_category_impl; - -template -struct minimum_category_impl -{ - using type = T2; -}; - -template -struct minimum_category_impl -{ - using type = T1; -}; - -template -struct minimum_category_impl -{ - static_assert(std::is_same::value, "Iterator category types must be the same when they are equivalent."); - using type = T1; -}; - -} // namespace detail - -// -// Returns the minimum category type or fails to compile -// if T1 and T2 are unrelated. -// +// Deprecated metafunction for selecting minimum iterator category, +// use min_category instead. template< class T1 = mpl::arg<1>, class T2 = mpl::arg<2> > -struct minimum_category +struct minimum_category : + public min_category { - static_assert( - std::is_convertible::value || std::is_convertible::value, - "Iterator category types must be related through convertibility."); - - using type = typename boost::iterators::detail::minimum_category_impl< - T1, - T2, - std::is_convertible::value, - std::is_convertible::value - >::type; }; template <> struct minimum_category< mpl::arg<1>, mpl::arg<2> > { template - struct apply : minimum_category + struct apply : + public min_category {}; }; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3f1356e..5d8330f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -61,6 +61,9 @@ test-suite iterator [ run generator_iterator_test.cpp ] + [ run min_category.cpp ] + [ compile-fail min_category_compile_fail1.cpp ] + [ compile-fail min_category_compile_fail2.cpp ] [ run minimum_category.cpp ] [ compile-fail minimum_category_compile_fail.cpp ] diff --git a/test/min_category.cpp b/test/min_category.cpp new file mode 100644 index 0000000..830824e --- /dev/null +++ b/test/min_category.cpp @@ -0,0 +1,33 @@ +// Copyright Andrey Semashev 2025. +// +// 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) + +#include +#include +#include +#include + +using std::is_same; +using boost::iterators::min_category; +using boost::iterators::min_category_t; + +int main(int, char*[]) +{ + BOOST_TEST_TRAIT_TRUE((is_same::type, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same::type, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same::type, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same::type, std::random_access_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same::type, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same::type, std::forward_iterator_tag>)); + + BOOST_TEST_TRAIT_TRUE((is_same, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same, std::random_access_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same, std::forward_iterator_tag>)); + BOOST_TEST_TRAIT_TRUE((is_same, std::forward_iterator_tag>)); + + return boost::report_errors(); +} diff --git a/test/min_category_compile_fail1.cpp b/test/min_category_compile_fail1.cpp new file mode 100644 index 0000000..0751de5 --- /dev/null +++ b/test/min_category_compile_fail1.cpp @@ -0,0 +1,19 @@ +// Copyright Andrey Semashev 2025. +// +// Distributed under 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) + +#include + +using boost::iterators::min_category; + +struct A {}; +struct B {}; + +int main(int, char*[]) +{ + min_category::type cat; + + return 0; +} diff --git a/test/min_category_compile_fail2.cpp b/test/min_category_compile_fail2.cpp new file mode 100644 index 0000000..6516093 --- /dev/null +++ b/test/min_category_compile_fail2.cpp @@ -0,0 +1,16 @@ +// Copyright Andrey Semashev 2025. +// +// Distributed under 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) + +#include + +using boost::iterators::min_category; + +int main(int, char*[]) +{ + min_category<>::type cat; + + return 0; +} diff --git a/test/test_cmake/main.cpp b/test/test_cmake/main.cpp index 5cf0e59..21de84f 100644 --- a/test/test_cmake/main.cpp +++ b/test/test_cmake/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include