From 364e850719a1560f2e4758a65d24ffa29bb0e964 Mon Sep 17 00:00:00 2001 From: Georgy Guminov Date: Wed, 23 Apr 2025 01:42:28 +0300 Subject: [PATCH 1/3] Make transform iterator save underlying iterator category. - operator[] in iterator facade now returns a reference, because its return type must be the same as dereference type for random_access_iterator concept. - add tests for categories checks. - change trait to determine transform_iterator reference type. --- include/boost/iterator/iterator_facade.hpp | 44 +------ include/boost/iterator/transform_iterator.hpp | 3 +- test/transform_iterator_test.cpp | 117 ++++++++++++++++++ 3 files changed, 123 insertions(+), 41 deletions(-) diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index 2c23fb9ab..795d6f4ba 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -368,41 +368,6 @@ class operator_brackets_proxy Iterator m_iter; }; -// A metafunction that determines whether operator[] must return a -// proxy, or whether it can simply return a copy of the value_type. -template< typename ValueType, typename Reference > -struct use_operator_brackets_proxy : - public detail::negation< - detail::conjunction< - std::is_copy_constructible< ValueType >, - std::is_trivial< ValueType >, - iterator_writability_disabled< ValueType, Reference > - > - > -{}; - -template< typename Iterator, typename Value, typename Reference > -struct operator_brackets_result -{ - using type = typename std::conditional< - use_operator_brackets_proxy::value, - operator_brackets_proxy, - Value - >::type; -}; - -template< typename Iterator > -inline operator_brackets_proxy make_operator_brackets_result(Iterator const& iter, std::true_type) -{ - return operator_brackets_proxy< Iterator >(iter); -} - -template< typename Iterator > -inline typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, std::false_type) -{ - return *iter; -} - // A binary metafunction class that always returns bool. template< typename Iterator1, typename Iterator2 > using always_bool_t = bool; @@ -679,13 +644,12 @@ class iterator_facade_base< Derived, Value, CategoryOrTraversal, Reference, Diff using difference_type = typename base_type::difference_type; public: - typename boost::iterators::detail::operator_brackets_result< Derived, Value, reference >::type + Reference operator[](difference_type n) const { - return boost::iterators::detail::make_operator_brackets_result< Derived >( - this->derived() + n, - std::integral_constant< bool, boost::iterators::detail::use_operator_brackets_proxy< Value, Reference >::value >{} - ); + Derived derived = this->derived(); + iterator_core_access::advance(derived, n); + return iterator_core_access::dereference(derived); } Derived& operator+=(difference_type n) diff --git a/include/boost/iterator/transform_iterator.hpp b/include/boost/iterator/transform_iterator.hpp index d15e6ddeb..612116588 100644 --- a/include/boost/iterator/transform_iterator.hpp +++ b/include/boost/iterator/transform_iterator.hpp @@ -32,7 +32,7 @@ namespace detail { template< typename UnaryFunc, typename Iterator > struct transform_iterator_default_reference { - using type = decltype(std::declval< UnaryFunc const& >()(std::declval< typename std::iterator_traits< Iterator >::reference >())); + using type = decltype(std::declval< UnaryFunc const& >()(*std::declval< Iterator >())); }; // Compute the iterator_adaptor instantiation to be used for transform_iterator @@ -81,6 +81,7 @@ class transform_iterator : using functor_base = boost::empty_value< UnaryFunc >; public: + transform_iterator() = default; transform_iterator(Iterator const& x, UnaryFunc f) : diff --git a/test/transform_iterator_test.cpp b/test/transform_iterator_test.cpp index d9b8a66ec..077423a2d 100644 --- a/test/transform_iterator_test.cpp +++ b/test/transform_iterator_test.cpp @@ -15,12 +15,18 @@ #include #include #include +#include +#include #include #include #include #include #include +#if defined(__cpp_lib_ranges) && ( __cpp_lib_ranges >= 202002L ) +#include +#endif + #include "static_assert_same.hpp" struct mult_functor { @@ -47,6 +53,19 @@ struct adaptable_mult_functor adaptable_mult_functor(int aa) : mult_functor(aa) { } }; +struct identity { + template + T&& operator()(T&& x) const { + return static_cast(x); + } +}; + +struct reference_to_value { + template + typename std::remove_reference::type operator()(T&& x) const { + return x; + } +}; struct const_select_first { @@ -272,5 +291,103 @@ main() boost::make_transform_iterator(y, polymorphic_mult_functor()), N, x); } + + { + using Iter = boost::iterators::transform_iterator::iterator>; + using ConstIter = boost::iterators::transform_iterator::const_iterator>; + + static_assert( + std::is_same()), int&>::value, + "Transform iterator with identity must dereference into int reference." + ); + + static_assert( + std::is_same()), const int&>::value, + "Transform iterator with identity must dereference into const int reference." + ); + + static_assert( + std::is_same()[std::declval()]), int&>::value, + "Transform iterator over iterator with identity must return int reference for operator[] call." + ); + + static_assert( + std::is_same()[std::declval()]), const int&>::value, + "Transform iterator over const iterator with identity must return int reference for operator[] call." + ); + + #if defined(__cpp_lib_concepts) && ( __cpp_lib_concepts >= 202002L ) + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(std::output_iterator); + static_assert(std::input_iterator); + static_assert(!std::output_iterator); + static_assert(std::input_iterator); + #endif + + auto nums = std::vector{1, 2, 3, 4, 5, 6}; + + auto iter1 = boost::iterators::make_transform_iterator(nums.begin()); + auto iter2 = boost::iterators::make_transform_iterator(nums.end()); + + const auto found3 = std::lower_bound(iter1, iter2, 3); + BOOST_TEST(*found3 == 3); + + #if defined(__cpp_lib_ranges) + auto found3rng = std::ranges::lower_bound(iter1, iter2, 3); + BOOST_TEST(*found3rng == 3); + #endif + + *std::prev(iter2) = 7; + BOOST_TEST(nums.back() == 7); + } + + { + using Iter = boost::iterators::transform_iterator::iterator>; + using ConstIter = boost::iterators::transform_iterator::const_iterator>; + + static_assert( + std::is_same()), int>::value, + "Transform iterator with identity must dereference into int reference." + ); + + static_assert( + std::is_same()), int>::value, + "Transform iterator with identity must dereference into const int reference." + ); + + static_assert( + std::is_same()[std::declval()]), int>::value, + "Transform iterator over iterator with identity must return int reference for operator[] call." + ); + + static_assert( + std::is_same()[std::declval()]), int>::value, + "Transform iterator over const iterator with identity must return int reference for operator[] call." + ); + + #if defined(__cpp_lib_concepts) && ( __cpp_lib_concepts >= 202002L ) + static_assert(std::random_access_iterator); + static_assert(std::random_access_iterator); + static_assert(!std::output_iterator); + static_assert(std::input_iterator); + static_assert(!std::output_iterator); + static_assert(std::input_iterator); + #endif + + auto nums = std::vector{1, 2, 3, 4, 5, 6}; + + auto iter1 = boost::iterators::make_transform_iterator(nums.begin()); + auto iter2 = boost::iterators::make_transform_iterator(nums.end()); + + const auto found3 = std::lower_bound(iter1, iter2, 3); + BOOST_TEST(*found3 == 3); + + #if defined(__cpp_lib_ranges) && ( __cpp_lib_ranges >= 202002L ) + auto found3rng = std::ranges::lower_bound(iter1, iter2, 3); + BOOST_TEST(*found3rng == 3); + #endif + } + return boost::report_errors(); } From 8c72b93ef4fbd4584890e1df3941bea3b0fab8ca Mon Sep 17 00:00:00 2001 From: Georgy Guminov Date: Wed, 23 Apr 2025 04:16:13 +0300 Subject: [PATCH 2/3] Fix counting iterator. --- include/boost/iterator/counting_iterator.hpp | 6 ++++++ include/boost/iterator/iterator_facade.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/include/boost/iterator/counting_iterator.hpp b/include/boost/iterator/counting_iterator.hpp index 2e5b3ef27..9bdc62dd9 100644 --- a/include/boost/iterator/counting_iterator.hpp +++ b/include/boost/iterator/counting_iterator.hpp @@ -171,6 +171,7 @@ class counting_iterator : public: using reference = typename super_t::reference; + using value_type = typename super_t::value_type; using difference_type = typename super_t::difference_type; counting_iterator() = default; @@ -183,6 +184,11 @@ class counting_iterator : { } + value_type operator[](difference_type n) const { + auto ret_iter = *this; + return *(ret_iter + n); + } + private: reference dereference() const { diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index 795d6f4ba..b89b0eda1 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -641,6 +641,7 @@ class iterator_facade_base< Derived, Value, CategoryOrTraversal, Reference, Diff public: using reference = typename base_type::reference; + using value_type = typename base_type::value_type; using difference_type = typename base_type::difference_type; public: From d47f2523ebd4c0b015d8322d09d13216046a234f Mon Sep 17 00:00:00 2001 From: Georgy Guminov Date: Wed, 23 Apr 2025 05:29:26 +0300 Subject: [PATCH 3/3] Force to inherit transform_iterator_tag. --- include/boost/iterator/transform_iterator.hpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/boost/iterator/transform_iterator.hpp b/include/boost/iterator/transform_iterator.hpp index 612116588..578a47040 100644 --- a/include/boost/iterator/transform_iterator.hpp +++ b/include/boost/iterator/transform_iterator.hpp @@ -35,6 +35,34 @@ struct transform_iterator_default_reference using type = decltype(std::declval< UnaryFunc const& >()(*std::declval< Iterator >())); }; +template < typename Iterator, class Enable = void > +struct transform_iterator_category_base { +}; + +template +struct transform_iterator_category_base_impl { + using type = IterCategory; +}; + +template <> +struct transform_iterator_category_base_impl { + using type = std::input_iterator_tag; +}; + +template +struct enable_if_type { using type = R; }; + +template < typename Iterator > +struct transform_iterator_category_base< + Iterator, + typename enable_if_type::iterator_category>::type +> +{ + using type = typename transform_iterator_category_base_impl< + typename std::iterator_traits::iterator_category + >::type; +}; + // Compute the iterator_adaptor instantiation to be used for transform_iterator template< typename UnaryFunc, typename Iterator, typename Reference, typename Value > struct transform_iterator_base @@ -82,6 +110,8 @@ class transform_iterator : public: + using iterator_category = typename detail::transform_iterator_category_base< Iterator >::type; + transform_iterator() = default; transform_iterator(Iterator const& x, UnaryFunc f) :