From 6e60ea7a8865729625b23f9e59a266cfce3d12df Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 4 Feb 2025 01:32:04 +0300 Subject: [PATCH] Extracted and unified default template parameter handling helpers. The new eval_if_default helper replaces both ia_dflt_help and ia_eval_if_default helpers. Additionally, added a new if_default helper, which expands to the type or the default parameter directly. The new helpers are placed in separate headers which can be used without the iterator_adaptor template. --- include/boost/iterator/counting_iterator.hpp | 137 ++++++++++-------- .../boost/iterator/detail/eval_if_default.hpp | 44 ++++++ include/boost/iterator/detail/if_default.hpp | 41 ++++++ include/boost/iterator/indirect_iterator.hpp | 7 +- include/boost/iterator/iterator_adaptor.hpp | 52 +------ include/boost/iterator/transform_iterator.hpp | 33 +++-- 6 files changed, 190 insertions(+), 124 deletions(-) create mode 100644 include/boost/iterator/detail/eval_if_default.hpp create mode 100644 include/boost/iterator/detail/if_default.hpp diff --git a/include/boost/iterator/counting_iterator.hpp b/include/boost/iterator/counting_iterator.hpp index 1bac414..2e5b3ef 100644 --- a/include/boost/iterator/counting_iterator.hpp +++ b/include/boost/iterator/counting_iterator.hpp @@ -2,8 +2,8 @@ // 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) -#ifndef COUNTING_ITERATOR_DWA200348_HPP -#define COUNTING_ITERATOR_DWA200348_HPP +#ifndef BOOST_ITERATOR_COUNTING_ITERATOR_DWA200348_HPP +#define BOOST_ITERATOR_COUNTING_ITERATOR_DWA200348_HPP #include #include @@ -13,15 +13,17 @@ #include #include #include +#include +#include #include namespace boost { namespace iterators { template< - class Incrementable, - class CategoryOrTraversal, - class Difference + typename Incrementable, + typename CategoryOrTraversal, + typename Difference > class counting_iterator; @@ -29,97 +31,109 @@ namespace detail { // Try to detect numeric types at compile time in ways compatible // with the limitations of the compiler and library. -template +template< typename T > struct is_numeric : - public std::integral_constant::is_specialized> + public std::integral_constant< bool, std::numeric_limits< T >::is_specialized > {}; -template <> -struct is_numeric : +template<> +struct is_numeric< long long > : public std::true_type {}; -template <> -struct is_numeric : +template<> +struct is_numeric< unsigned long long > : public std::true_type {}; #if defined(BOOST_HAS_INT128) -template <> -struct is_numeric : +template<> +struct is_numeric< boost::int128_type > : public std::true_type {}; -template <> -struct is_numeric : +template<> +struct is_numeric< boost::uint128_type > : public std::true_type {}; #endif // Some compilers fail to have a numeric_limits specialization -template <> -struct is_numeric : +template<> +struct is_numeric< wchar_t > : public std::true_type {}; -template +template< typename T > struct numeric_difference { - using type = typename boost::detail::numeric_traits::difference_type; + using type = typename boost::detail::numeric_traits< T >::difference_type; }; #if defined(BOOST_HAS_INT128) // std::numeric_limits, which is used by numeric_traits, is not specialized for __int128 in some standard libraries -template <> -struct numeric_difference +template<> +struct numeric_difference< boost::int128_type > { using type = boost::int128_type; }; -template <> -struct numeric_difference +template<> +struct numeric_difference< boost::uint128_type > { using type = boost::int128_type; }; #endif -template +template< typename Incrementable, typename CategoryOrTraversal, typename Difference, bool IsNumeric = is_numeric< Incrementable >::value > +struct counting_iterator_types +{ + using traversal = detail::eval_if_default_t< + CategoryOrTraversal, + iterator_traversal< Incrementable > + >; + + using difference = detail::eval_if_default_t< + Difference, + iterator_difference< Incrementable > + >; +}; + +template< typename Incrementable, typename CategoryOrTraversal, typename Difference > +struct counting_iterator_types< Incrementable, CategoryOrTraversal, Difference, true > +{ + using traversal = detail::if_default_t< + CategoryOrTraversal, + random_access_traversal_tag + >; + + using difference = detail::eval_if_default_t< + Difference, + numeric_difference< Incrementable > + >; +}; + +template< typename Incrementable, typename CategoryOrTraversal, typename Difference > struct counting_iterator_base { - using traversal = typename detail::ia_dflt_help< - CategoryOrTraversal, - typename std::conditional< - is_numeric::value, - iterators::detail::type_identity, - iterator_traversal - >::type - >::type; - - using difference = typename detail::ia_dflt_help< - Difference, - typename std::conditional< - is_numeric::value, - numeric_difference, - iterator_difference - >::type - >::type; + using iterator_types = counting_iterator_types< Incrementable, CategoryOrTraversal, Difference >; using type = iterator_adaptor< - counting_iterator, // self + counting_iterator< Incrementable, CategoryOrTraversal, Difference >, // self Incrementable, // Base #ifndef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY const // MSVC won't strip this. Instead we enable Thomas' // criterion (see boost/iterator/detail/facade_iterator_category.hpp) #endif Incrementable, // Value - traversal, + typename iterator_types::traversal, Incrementable const&, // reference - difference + typename iterator_types::difference >; }; // A distance calculation policy for wrapped iterators -template +template< typename Difference, typename Incrementable1, typename Incrementable2 > struct iterator_distance { static Difference distance(Incrementable1 x, Incrementable2 y) @@ -129,7 +143,7 @@ struct iterator_distance }; // A distance calculation policy for wrapped numbers -template +template< typename Difference, typename Incrementable1, typename Incrementable2 > struct number_distance { static Difference distance(Incrementable1 x, Incrementable2 y) @@ -141,19 +155,20 @@ struct number_distance } // namespace detail template< - class Incrementable, - class CategoryOrTraversal = use_default, - class Difference = use_default + typename Incrementable, + typename CategoryOrTraversal = use_default, + typename Difference = use_default > class counting_iterator : - public detail::counting_iterator_base::type + public detail::counting_iterator_base< Incrementable, CategoryOrTraversal, Difference >::type { + friend class iterator_core_access; + +private: using super_t = typename detail::counting_iterator_base< Incrementable, CategoryOrTraversal, Difference >::type; - friend class iterator_core_access; - public: using reference = typename super_t::reference; using difference_type = typename super_t::difference_type; @@ -174,14 +189,14 @@ private: return this->base_reference(); } - template + template< typename OtherIncrementable > difference_type - distance_to(counting_iterator const& y) const + distance_to(counting_iterator< OtherIncrementable, CategoryOrTraversal, Difference > const& y) const { using distance_traits = typename std::conditional< - detail::is_numeric::value, - detail::number_distance, - detail::iterator_distance + detail::is_numeric< Incrementable >::value, + detail::number_distance< difference_type, Incrementable, OtherIncrementable >, + detail::iterator_distance< difference_type, Incrementable, OtherIncrementable > >::type; return distance_traits::distance(this->base(), y.base()); @@ -189,10 +204,10 @@ private: }; // Manufacture a counting iterator for an arbitrary incrementable type -template -inline counting_iterator make_counting_iterator(Incrementable x) +template< typename Incrementable > +inline counting_iterator< Incrementable > make_counting_iterator(Incrementable x) { - return counting_iterator(x); + return counting_iterator< Incrementable >(x); } } // namespace iterators @@ -202,4 +217,4 @@ using iterators::make_counting_iterator; } // namespace boost -#endif // COUNTING_ITERATOR_DWA200348_HPP +#endif // BOOST_ITERATOR_COUNTING_ITERATOR_DWA200348_HPP diff --git a/include/boost/iterator/detail/eval_if_default.hpp b/include/boost/iterator/detail/eval_if_default.hpp new file mode 100644 index 0000000..e737bc9 --- /dev/null +++ b/include/boost/iterator/detail/eval_if_default.hpp @@ -0,0 +1,44 @@ +/* + * 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) 2025 Andrey Semashev + */ + +#ifndef BOOST_ITERATOR_DETAIL_EVAL_IF_DEFAULT_HPP_INCLUDED_ +#define BOOST_ITERATOR_DETAIL_EVAL_IF_DEFAULT_HPP_INCLUDED_ + +#include +#include + +namespace boost { +namespace iterators { +namespace detail { + +// If T is use_default, return the result of invoking +// DefaultNullaryFn, otherwise - of NondefaultNullaryFn. +// By default, NondefaultNullaryFn returns T, which means +// the metafunction can be called with just two parameters +// and in that case will return either T or the result of +// invoking DefaultNullaryFn. +template< typename T, typename DefaultNullaryFn, typename NondefaultNullaryFn = detail::type_identity< T > > +struct eval_if_default +{ + using type = typename NondefaultNullaryFn::type; +}; + +template< typename DefaultNullaryFn, typename NondefaultNullaryFn > +struct eval_if_default< use_default, DefaultNullaryFn, NondefaultNullaryFn > +{ + using type = typename DefaultNullaryFn::type; +}; + +template< typename T, typename DefaultNullaryFn, typename NondefaultNullaryFn = detail::type_identity< T > > +using eval_if_default_t = typename eval_if_default< T, DefaultNullaryFn, NondefaultNullaryFn >::type; + +} // namespace detail +} // namespace iterators +} // namespace boost + +#endif // BOOST_ITERATOR_DETAIL_EVAL_IF_DEFAULT_HPP_INCLUDED_ diff --git a/include/boost/iterator/detail/if_default.hpp b/include/boost/iterator/detail/if_default.hpp new file mode 100644 index 0000000..1b5126b --- /dev/null +++ b/include/boost/iterator/detail/if_default.hpp @@ -0,0 +1,41 @@ +/* + * 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) 2025 Andrey Semashev + */ + +#ifndef BOOST_ITERATOR_DETAIL_IF_DEFAULT_HPP_INCLUDED_ +#define BOOST_ITERATOR_DETAIL_IF_DEFAULT_HPP_INCLUDED_ + +#include + +namespace boost { +namespace iterators { +namespace detail { + +// If T is use_default, return Default, otherwise - Nondefault. +// By default, Nondefault is T, which means +// the metafunction can be called with just two parameters +// and in that case will return either T or Default. +template< typename T, typename Default, typename Nondefault = T > +struct if_default +{ + using type = Nondefault; +}; + +template< typename Default, typename Nondefault > +struct if_default< use_default, Default, Nondefault > +{ + using type = Default; +}; + +template< typename T, typename Default, typename Nondefault = T > +using if_default_t = typename if_default< T, Default, Nondefault >::type; + +} // namespace detail +} // namespace iterators +} // namespace boost + +#endif // BOOST_ITERATOR_DETAIL_IF_DEFAULT_HPP_INCLUDED_ diff --git a/include/boost/iterator/indirect_iterator.hpp b/include/boost/iterator/indirect_iterator.hpp index ab25e36..8641db1 100644 --- a/include/boost/iterator/indirect_iterator.hpp +++ b/include/boost/iterator/indirect_iterator.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -34,14 +35,14 @@ struct indirect_base using type = iterator_adaptor< indirect_iterator< Iter, Value, Category, Reference, Difference >, Iter, - detail::ia_dflt_help_t< + detail::eval_if_default_t< Value, pointee< dereferenceable > >, Category, - detail::ia_dflt_help_t< + detail::eval_if_default_t< Reference, - detail::ia_eval_if_default< + detail::eval_if_default< Value, indirect_reference< dereferenceable >, std::add_lvalue_reference< Value > diff --git a/include/boost/iterator/iterator_adaptor.hpp b/include/boost/iterator/iterator_adaptor.hpp index a424236..4ebcd3c 100644 --- a/include/boost/iterator/iterator_adaptor.hpp +++ b/include/boost/iterator/iterator_adaptor.hpp @@ -15,6 +15,7 @@ #include #include #include // for backward compatibility; remove once downstream users are updated +#include #include @@ -26,45 +27,8 @@ namespace iterators { // explicitly in order to specify that the default should be used. using boost::use_default; -// -// Default template argument handling for iterator_adaptor -// namespace detail { -// If T is use_default, return the result of invoking -// DefaultNullaryFn, otherwise return T. -template< typename T, typename DefaultNullaryFn > -struct ia_dflt_help -{ - using type = T; -}; - -template< typename DefaultNullaryFn > -struct ia_dflt_help< use_default, DefaultNullaryFn > -{ - using type = typename DefaultNullaryFn::type; -}; - -template< typename T, typename DefaultNullaryFn > -using ia_dflt_help_t = typename ia_dflt_help< T, DefaultNullaryFn >::type; - -// If T is use_default, return the result of invoking -// DefaultNullaryFn, otherwise - of NondefaultNullaryFn. -template< typename T, typename DefaultNullaryFn, typename NondefaultNullaryFn > -struct ia_eval_if_default -{ - using type = typename NondefaultNullaryFn::type; -}; - -template< typename DefaultNullaryFn, typename NondefaultNullaryFn > -struct ia_eval_if_default< use_default, DefaultNullaryFn, NondefaultNullaryFn > -{ - using type = typename DefaultNullaryFn::type; -}; - -template< typename T, typename DefaultNullaryFn, typename NondefaultNullaryFn > -using ia_eval_if_default_t = typename ia_eval_if_default< T, DefaultNullaryFn, NondefaultNullaryFn >::type; - // A metafunction which computes an iterator_adaptor's base class, // a specialization of iterator_facade. template< @@ -79,36 +43,36 @@ using iterator_adaptor_base_t = iterator_facade< Derived, #ifdef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY - detail::ia_dflt_help_t< + detail::eval_if_default_t< Value, - detail::ia_eval_if_default< + detail::eval_if_default< Reference, iterator_value< Base >, std::remove_reference< Reference > > >, #else - detail::ia_dflt_help_t< + detail::eval_if_default_t< Value, iterator_value< Base > >, #endif - detail::ia_dflt_help_t< + detail::eval_if_default_t< Traversal, iterator_traversal< Base > >, - detail::ia_dflt_help_t< + detail::eval_if_default_t< Reference, - detail::ia_eval_if_default< + detail::eval_if_default< Value, iterator_reference< Base >, std::add_lvalue_reference< Value > > >, - detail::ia_dflt_help_t< + detail::eval_if_default_t< Difference, iterator_difference< Base > > diff --git a/include/boost/iterator/transform_iterator.hpp b/include/boost/iterator/transform_iterator.hpp index 4ddf929..a5b23f1 100644 --- a/include/boost/iterator/transform_iterator.hpp +++ b/include/boost/iterator/transform_iterator.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -35,33 +36,33 @@ namespace iterators { private: // By default, dereferencing the iterator yields the same as // the function. - typedef typename ia_dflt_help< - Reference + using reference = detail::eval_if_default_t< + Reference, #ifdef BOOST_RESULT_OF_USE_TR1 - , result_of::reference)> + result_of::reference)> #else - , result_of::reference)> + result_of::reference)> #endif - >::type reference; + >; // To get the default for Value: remove any reference on the // result type, but retain any constness to signal // non-writability. Note that if we adopt Thomas' suggestion // to key non-writability *only* on the Reference argument, // we'd need to strip constness here as well. - typedef typename ia_dflt_help< - Value - , remove_reference - >::type cv_value_type; + using cv_value_type = detail::eval_if_default_t< + Value, + remove_reference + >; public: - typedef iterator_adaptor< - transform_iterator - , Iterator - , cv_value_type - , use_default // Leave the traversal category alone - , reference - > type; + using type = iterator_adaptor< + transform_iterator, + Iterator, + cv_value_type, + use_default, // Leave the traversal category alone + reference + >; }; }