Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/boost/iterator/counting_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
{
Expand Down
45 changes: 5 additions & 40 deletions include/boost/iterator/iterator_facade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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, Reference>::value,
operator_brackets_proxy<Iterator>,
Value
>::type;
};

template< typename Iterator >
inline operator_brackets_proxy<Iterator> 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;
Expand Down Expand Up @@ -676,16 +641,16 @@ 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:
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)
Expand Down
33 changes: 32 additions & 1 deletion include/boost/iterator/transform_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,35 @@ 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 >()));
};

template < typename Iterator, class Enable = void >
struct transform_iterator_category_base {
};

template <class IterCategory>
struct transform_iterator_category_base_impl {
using type = IterCategory;
};

template <>
struct transform_iterator_category_base_impl<std::output_iterator_tag> {
using type = std::input_iterator_tag;
};

template<class T, class R = void>
struct enable_if_type { using type = R; };

template < typename Iterator >
struct transform_iterator_category_base<
Iterator,
typename enable_if_type<typename std::iterator_traits<Iterator>::iterator_category>::type
>
{
using type = typename transform_iterator_category_base_impl<
typename std::iterator_traits<Iterator>::iterator_category
>::type;
};

// Compute the iterator_adaptor instantiation to be used for transform_iterator
Expand Down Expand Up @@ -81,6 +109,9 @@ class transform_iterator :
using functor_base = boost::empty_value< UnaryFunc >;

public:

using iterator_category = typename detail::transform_iterator_category_base< Iterator >::type;

transform_iterator() = default;

transform_iterator(Iterator const& x, UnaryFunc f) :
Expand Down
117 changes: 117 additions & 0 deletions test/transform_iterator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <iterator>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_concepts.hpp>
#include <boost/iterator/new_iterator_tests.hpp>
#include <boost/pending/iterator_tests.hpp>
#include <boost/concept_check.hpp>

#if defined(__cpp_lib_ranges) && ( __cpp_lib_ranges >= 202002L )
#include <ranges>
#endif

#include "static_assert_same.hpp"

struct mult_functor {
Expand All @@ -47,6 +53,19 @@ struct adaptable_mult_functor
adaptable_mult_functor(int aa) : mult_functor(aa) { }
};

struct identity {
template <class T>
T&& operator()(T&& x) const {
return static_cast<T&&>(x);
}
};

struct reference_to_value {
template <class T>
typename std::remove_reference<T>::type operator()(T&& x) const {
return x;
}
};

struct const_select_first
{
Expand Down Expand Up @@ -272,5 +291,103 @@ main()
boost::make_transform_iterator(y, polymorphic_mult_functor()), N, x);
}


{
using Iter = boost::iterators::transform_iterator<identity, typename std::vector<int>::iterator>;
using ConstIter = boost::iterators::transform_iterator<identity, typename std::vector<int>::const_iterator>;

static_assert(
std::is_same<decltype(*std::declval<Iter>()), int&>::value,
"Transform iterator with identity must dereference into int reference."
);

static_assert(
std::is_same<decltype(*std::declval<ConstIter>()), const int&>::value,
"Transform iterator with identity must dereference into const int reference."
);

static_assert(
std::is_same<decltype(std::declval<Iter>()[std::declval<std::size_t>()]), int&>::value,
"Transform iterator over iterator with identity must return int reference for operator[] call."
);

static_assert(
std::is_same<decltype(std::declval<ConstIter>()[std::declval<std::size_t>()]), 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<Iter>);
static_assert(std::random_access_iterator<ConstIter>);
static_assert(std::output_iterator<Iter, int>);
static_assert(std::input_iterator<Iter>);
static_assert(!std::output_iterator<ConstIter, int>);
static_assert(std::input_iterator<ConstIter>);
#endif

auto nums = std::vector<int>{1, 2, 3, 4, 5, 6};

auto iter1 = boost::iterators::make_transform_iterator<identity>(nums.begin());
auto iter2 = boost::iterators::make_transform_iterator<identity>(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<reference_to_value, typename std::vector<int>::iterator>;
using ConstIter = boost::iterators::transform_iterator<reference_to_value, typename std::vector<int>::const_iterator>;

static_assert(
std::is_same<decltype(*std::declval<Iter>()), int>::value,
"Transform iterator with identity must dereference into int reference."
);

static_assert(
std::is_same<decltype(*std::declval<ConstIter>()), int>::value,
"Transform iterator with identity must dereference into const int reference."
);

static_assert(
std::is_same<decltype(std::declval<Iter>()[std::declval<std::size_t>()]), int>::value,
"Transform iterator over iterator with identity must return int reference for operator[] call."
);

static_assert(
std::is_same<decltype(std::declval<ConstIter>()[std::declval<std::size_t>()]), 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<Iter>);
static_assert(std::random_access_iterator<ConstIter>);
static_assert(!std::output_iterator<Iter, int>);
static_assert(std::input_iterator<Iter>);
static_assert(!std::output_iterator<ConstIter, int>);
static_assert(std::input_iterator<ConstIter>);
#endif

auto nums = std::vector<int>{1, 2, 3, 4, 5, 6};

auto iter1 = boost::iterators::make_transform_iterator<identity>(nums.begin());
auto iter2 = boost::iterators::make_transform_iterator<identity>(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();
}