axmol/thirdparty/range-v3/include/range/v3/view/transform.hpp

619 lines
24 KiB
C++

/// \file
// Range v3 library
//
// Copyright Eric Niebler 2013-present
//
// Use, modification and distribution is subject to 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)
//
// Project home: https://github.com/ericniebler/range-v3
//
#ifndef RANGES_V3_VIEW_TRANSFORM_HPP
#define RANGES_V3_VIEW_TRANSFORM_HPP
#include <iterator>
#include <type_traits>
#include <utility>
#include <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/algorithm/max.hpp>
#include <range/v3/algorithm/min.hpp>
#include <range/v3/functional/bind_back.hpp>
#include <range/v3/functional/indirect.hpp>
#include <range/v3/functional/invoke.hpp>
#include <range/v3/iterator/operations.hpp>
#include <range/v3/range/access.hpp>
#include <range/v3/range/primitives.hpp>
#include <range/v3/range/traits.hpp>
#include <range/v3/utility/move.hpp>
#include <range/v3/utility/semiregular_box.hpp>
#include <range/v3/utility/static_const.hpp>
#include <range/v3/view/adaptor.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/view.hpp>
#include <range/v3/detail/prologue.hpp>
namespace ranges
{
/// \cond
namespace detail
{
constexpr cardinality transform2_cardinality(cardinality c1, cardinality c2)
{
return c1 >= 0 || c2 >= 0
? (c1 >= 0 && c2 >= 0 ? (c1 < c2 ? c1 : c2) : finite)
: c1 == finite || c2 == finite
? finite
: c1 == unknown || c2 == unknown ? unknown : infinite;
}
// clang-format off
/// \concept iter_transform_1_readable_
/// \brief The \c iter_transform_1_readable_ concept
template(typename Fun, typename Rng)(
concept (iter_transform_1_readable_)(Fun, Rng),
regular_invocable<Fun &, iterator_t<Rng>> AND
regular_invocable<Fun &, copy_tag, iterator_t<Rng>> AND
regular_invocable<Fun &, move_tag, iterator_t<Rng>> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> &> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng>> &&,
invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&> AND
common_reference_with<
invoke_result_t<Fun &, move_tag, iterator_t<Rng>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng>> const &>
);
/// \concept iter_transform_1_readable
/// \brief The \c iter_transform_1_readable concept
template<typename Fun, typename Rng>
CPP_concept iter_transform_1_readable =
CPP_concept_ref(detail::iter_transform_1_readable_, Fun, Rng);
/// \concept iter_transform_2_readable_
/// \brief The \c iter_transform_2_readable_ concept
template(typename Fun, typename Rng1, typename Rng2)(
concept (iter_transform_2_readable_)(Fun, Rng1, Rng2),
regular_invocable<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> AND
regular_invocable<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
regular_invocable<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> &> AND
common_reference_with<
invoke_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&> AND
common_reference_with<
invoke_result_t<Fun &, move_tag, iterator_t<Rng1>, iterator_t<Rng2>> &&,
invoke_result_t<Fun &, copy_tag, iterator_t<Rng1>, iterator_t<Rng2>> const &>
);
/// \concept iter_transform_2_readable
/// \brief The \c iter_transform_2_readable concept
template<typename Fun, typename Rng1, typename Rng2>
CPP_concept iter_transform_2_readable =
CPP_concept_ref(detail::iter_transform_2_readable_, Fun, Rng1, Rng2);
// clang-format on
} // namespace detail
/// \endcond
/// \addtogroup group-views
/// @{
template<typename Rng, typename Fun>
struct iter_transform_view : view_adaptor<iter_transform_view<Rng, Fun>, Rng>
{
private:
friend range_access;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
template<bool Const>
using use_sentinel_t =
meta::bool_<!common_range<meta::const_if_c<Const, Rng>> ||
single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng>>>>;
template<bool IsConst>
struct adaptor : adaptor_base
{
private:
friend struct adaptor<!IsConst>;
using CRng = meta::const_if_c<IsConst, Rng>;
using fun_ref_ = semiregular_box_ref_or_val_t<Fun, IsConst>;
RANGES_NO_UNIQUE_ADDRESS fun_ref_ fun_;
public:
using value_type =
detail::decay_t<invoke_result_t<Fun &, copy_tag, iterator_t<CRng>>>;
adaptor() = default;
adaptor(fun_ref_ fun)
: fun_(std::move(fun))
{}
template(bool Other)(
requires IsConst AND CPP_NOT(Other)) //
adaptor(adaptor<Other> that)
: fun_(std::move(that.fun_))
{}
// clang-format off
auto CPP_auto_fun(read)(iterator_t<CRng> it)(const)
(
return invoke(fun_, it)
)
auto CPP_auto_fun(iter_move)(iterator_t<CRng> it)(const)
(
return invoke(fun_, move_tag{}, it)
)
// clang-format on
};
adaptor<false> begin_adaptor()
{
return {fun_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
detail::iter_transform_1_readable<Fun const,
meta::const_if_c<Const, Rng>>)
adaptor<Const> begin_adaptor() const
{
return {fun_};
}
meta::if_<use_sentinel_t<false>, adaptor_base, adaptor<false>> end_adaptor()
{
return {fun_};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng>> AND
detail::iter_transform_1_readable<Fun const,
meta::const_if_c<Const, Rng>>)
meta::if_<use_sentinel_t<Const>, adaptor_base, adaptor<Const>> end_adaptor() const
{
return {fun_};
}
public:
iter_transform_view() = default;
iter_transform_view(Rng rng, Fun fun)
: iter_transform_view::view_adaptor{std::move(rng)}
, fun_(std::move(fun))
{}
CPP_auto_member
constexpr auto CPP_fun(size)()(
requires sized_range<Rng>)
{
return ranges::size(this->base());
}
CPP_auto_member
constexpr auto CPP_fun(size)()(const //
requires sized_range<Rng const>)
{
return ranges::size(this->base());
}
};
template<typename Rng, typename Fun>
struct transform_view : iter_transform_view<Rng, indirected<Fun>>
{
transform_view() = default;
transform_view(Rng rng, Fun fun)
: iter_transform_view<Rng, indirected<Fun>>{std::move(rng),
indirect(std::move(fun))}
{}
};
#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
template(typename Rng, typename Fun)(
requires copy_constructible<Fun>)
transform_view(Rng &&, Fun)
-> transform_view<views::all_t<Rng>, Fun>;
#endif
template<typename Rng1, typename Rng2, typename Fun>
struct iter_transform2_view
: view_facade<iter_transform2_view<Rng1, Rng2, Fun>,
detail::transform2_cardinality(range_cardinality<Rng1>::value,
range_cardinality<Rng2>::value)>
{
private:
friend range_access;
RANGES_NO_UNIQUE_ADDRESS semiregular_box_t<Fun> fun_;
Rng1 rng1_;
Rng2 rng2_;
using difference_type_ =
common_type_t<range_difference_t<Rng1>, range_difference_t<Rng2>>;
static constexpr cardinality my_cardinality = detail::transform2_cardinality(
range_cardinality<Rng1>::value, range_cardinality<Rng2>::value);
template<bool>
struct cursor;
template<bool Const>
struct sentinel
{
private:
friend struct cursor<Const>;
sentinel_t<meta::const_if_c<Const, Rng1>> end1_;
sentinel_t<meta::const_if_c<Const, Rng2>> end2_;
public:
sentinel() = default;
sentinel(meta::const_if_c<Const, iter_transform2_view> * parent,
decltype(ranges::end))
: end1_(end(parent->rng1_))
, end2_(end(parent->rng2_))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
sentinel(sentinel<Other> that)
: end1_(std::move(that.end1_))
, end2_(std::move(that.end2_))
{}
};
template<bool Const>
struct cursor
{
private:
using fun_ref_ = semiregular_box_ref_or_val_t<Fun, Const>;
using R1 = meta::const_if_c<Const, Rng1>;
using R2 = meta::const_if_c<Const, Rng2>;
fun_ref_ fun_;
iterator_t<R1> it1_;
iterator_t<R2> it2_;
public:
using difference_type = difference_type_;
using single_pass = meta::or_c<(bool)single_pass_iterator_<iterator_t<R1>>,
(bool)single_pass_iterator_<iterator_t<R2>>>;
using value_type =
detail::decay_t<invoke_result_t<meta::const_if_c<Const, Fun> &, copy_tag,
iterator_t<R1>, iterator_t<R2>>>;
cursor() = default;
template<typename BeginEndFn>
cursor(meta::const_if_c<Const, iter_transform2_view> * parent,
BeginEndFn begin_end)
: fun_(parent->fun_)
, it1_(begin_end(parent->rng1_))
, it2_(begin_end(parent->rng2_))
{}
template(bool Other)(
requires Const AND CPP_NOT(Other)) //
cursor(cursor<Other> that)
: fun_(std::move(that.fun_))
, it1_(std::move(that.end1_))
, it2_(std::move(that.end2_))
{}
// clang-format off
auto CPP_auto_fun(read)()(const)
(
return invoke(fun_, it1_, it2_)
)
// clang-format on
void next()
{
++it1_;
++it2_;
}
CPP_member
auto equal(cursor const & that) const //
-> CPP_ret(bool)(
requires forward_range<Rng1> && forward_range<Rng2>)
{
// By returning true if *any* of the iterators are equal, we allow
// transformed ranges to be of different lengths, stopping when the first
// one reaches the last.
return it1_ == that.it1_ || it2_ == that.it2_;
}
bool equal(sentinel<Const> const & s) const
{
// By returning true if *any* of the iterators are equal, we allow
// transformed ranges to be of different lengths, stopping when the first
// one reaches the last.
return it1_ == s.end1_ || it2_ == s.end2_;
}
CPP_member
auto prev() //
-> CPP_ret(void)(
requires bidirectional_range<R1> && bidirectional_range<R2>)
{
--it1_;
--it2_;
}
CPP_member
auto advance(difference_type n) -> CPP_ret(void)(
requires random_access_range<R1> && random_access_range<R2>)
{
ranges::advance(it1_, n);
ranges::advance(it2_, n);
}
CPP_member
auto distance_to(cursor const & that) const //
-> CPP_ret(difference_type)(
requires sized_sentinel_for<iterator_t<R1>, iterator_t<R1>> &&
sized_sentinel_for<iterator_t<R2>, iterator_t<R2>>)
{
// Return the smallest distance (in magnitude) of any of the iterator
// pairs. This is to accommodate zippers of sequences of different length.
difference_type d1 = that.it1_ - it1_, d2 = that.it2_ - it2_;
return 0 < d1 ? ranges::min(d1, d2) : ranges::max(d1, d2);
}
// clang-format off
auto CPP_auto_fun(move)()(const)
(
return invoke(fun_, move_tag{}, it1_, it2_)
)
// clang-format on
};
template<bool Const>
using end_cursor_t = meta::if_c<
common_range<meta::const_if_c<Const, Rng1>> &&
common_range<meta::const_if_c<Const, Rng2>> &&
!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng1>>> &&
!single_pass_iterator_<iterator_t<meta::const_if_c<Const, Rng2>>>,
cursor<Const>, sentinel<Const>>;
cursor<simple_view<Rng1>() && simple_view<Rng2>()> begin_cursor()
{
return {this, ranges::begin};
}
end_cursor_t<simple_view<Rng1>() && simple_view<Rng2>()> end_cursor()
{
return {this, ranges::end};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng1>> AND
range<meta::const_if_c<Const, Rng2>> AND
detail::iter_transform_2_readable< //
Fun const, //
meta::const_if_c<Const, Rng1>, //
meta::const_if_c<Const, Rng2>>)
cursor<true> begin_cursor() const
{
return {this, ranges::begin};
}
template(bool Const = true)(
requires Const AND range<meta::const_if_c<Const, Rng1>> AND
range<meta::const_if_c<Const, Rng2>> AND
detail::iter_transform_2_readable< //
Fun const, //
meta::const_if_c<Const, Rng1>, //
meta::const_if_c<Const, Rng2>>)
end_cursor_t<Const> end_cursor() const
{
return {this, ranges::end};
}
template<typename Self>
static constexpr auto size_(Self & self)
{
using size_type = common_type_t<range_size_t<Rng1>, range_size_t<Rng2>>;
return ranges::min(static_cast<size_type>(ranges::size(self.rng1_)),
static_cast<size_type>(ranges::size(self.rng2_)));
}
template<bool B>
using R1 = meta::invoke<detail::dependent_<B>, Rng1>;
template<bool B>
using R2 = meta::invoke<detail::dependent_<B>, Rng2>;
public:
iter_transform2_view() = default;
constexpr iter_transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
: fun_(std::move(fun))
, rng1_(std::move(rng1))
, rng2_(std::move(rng2))
{}
CPP_member
static constexpr auto size() //
-> CPP_ret(std::size_t)(
requires (my_cardinality >= 0))
{
return static_cast<std::size_t>(my_cardinality);
}
template(bool True = true)(
requires (my_cardinality < 0) AND sized_range<Rng1 const> AND
sized_range<Rng2 const> AND
common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
constexpr auto size() const
{
return size_(*this);
}
template(bool True = true)(
requires (my_cardinality < 0) AND sized_range<Rng1> AND sized_range<Rng2> AND
common_with<range_size_t<R1<True>>, range_size_t<R2<True>>>)
constexpr auto size()
{
return size_(*this);
}
};
template<typename Rng1, typename Rng2, typename Fun>
struct transform2_view : iter_transform2_view<Rng1, Rng2, indirected<Fun>>
{
transform2_view() = default;
constexpr transform2_view(Rng1 rng1, Rng2 rng2, Fun fun)
: iter_transform2_view<Rng1, Rng2, indirected<Fun>>{std::move(rng1),
std::move(rng2),
indirect(std::move(fun))}
{}
};
namespace views
{
struct iter_transform_base_fn
{
template(typename Rng, typename Fun)(
requires viewable_range<Rng> AND input_range<Rng> AND
copy_constructible<Fun> AND
detail::iter_transform_1_readable<Fun, Rng>)
constexpr iter_transform_view<all_t<Rng>, Fun> //
operator()(Rng && rng, Fun fun) const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
template(typename Rng1, typename Rng2, typename Fun)(
requires viewable_range<Rng1> AND input_range<Rng1> AND
viewable_range<Rng2> AND input_range<Rng2> AND
copy_constructible<Fun> AND
common_with<range_difference_t<Rng1>, range_difference_t<Rng1>> AND
detail::iter_transform_2_readable<Fun, Rng1, Rng2>)
constexpr iter_transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(fun)};
}
};
struct iter_transform_fn : iter_transform_base_fn
{
using iter_transform_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(
bind_back(iter_transform_base_fn{}, std::move(fun)));
}
};
/// \relates iter_transform_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(iter_transform_fn, iter_transform)
// Don't forget to update views::for_each whenever this set
// of concepts changes
// clang-format off
/// \concept transformable_range_
/// \brief The \c transformable_range_ concept
template(typename Rng, typename Fun)(
concept (transformable_range_)(Rng, Fun),
regular_invocable<Fun &, range_reference_t<Rng>> AND
(!std::is_void<indirect_result_t<Fun &, iterator_t<Rng>>>::value)
);
/// \concept transformable_range
/// \brief The \c transformable_range concept
template<typename Rng, typename Fun>
CPP_concept transformable_range =
viewable_range<Rng> && input_range<Rng> &&
copy_constructible<Fun> &&
CPP_concept_ref(views::transformable_range_, Rng, Fun);
/// \concept transformable_ranges_
/// \brief The \c transformable_ranges_ concept
template(typename Rng1, typename Rng2, typename Fun)(
concept (transformable_ranges_)(Rng1, Rng2, Fun),
regular_invocable<Fun &, range_reference_t<Rng1>, range_reference_t<Rng2>> AND
(!std::is_void<
indirect_result_t<Fun &, iterator_t<Rng1>, iterator_t<Rng2>>>::value)
);
/// \concept transformable_ranges
/// \brief The \c transformable_ranges concept
template<typename Rng1, typename Rng2, typename Fun>
CPP_concept transformable_ranges =
viewable_range<Rng1> && input_range<Rng1> &&
viewable_range<Rng2> && input_range<Rng2> &&
copy_constructible<Fun> &&
CPP_concept_ref(views::transformable_ranges_, Rng1, Rng2, Fun);
// clang-format on
struct transform_base_fn
{
template(typename Rng, typename Fun)(
requires transformable_range<Rng, Fun>)
constexpr transform_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun)
const
{
return {all(static_cast<Rng &&>(rng)), std::move(fun)};
}
template(typename Rng1, typename Rng2, typename Fun)(
requires transformable_ranges<Rng1, Rng2, Fun>)
constexpr transform2_view<all_t<Rng1>, all_t<Rng2>, Fun> //
operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const
{
return {all(static_cast<Rng1 &&>(rng1)),
all(static_cast<Rng2 &&>(rng2)),
std::move(fun)};
}
};
/// # ranges::views::transform
/// The transform view takes in a function `T -> U` and converts an input
/// range of `T` into an output range of `U` by calling the function on every
/// element of the input range.
///
/// ## Example
/// \snippet example/view/transform.cpp transform example
///
/// ### Output
/// \include example/view/transform_golden.txt
///
/// ## Syntax
/// ```cpp
/// auto output_range = input_range | ranges::views::transform(transform_func);
/// ```
///
/// ## Parameters
/// <pre><b>transform_func</b></pre>
/// - Maps an input value to an output value (`transform_func(T) -> U`)
///
/// <pre><b>input_range</b></pre>
/// - The range of elements to transform
/// - Reference type: `T`
///
/// <pre><b>output_range</b></pre>
/// - The range of output values
/// - Reference type: `U`
/// - Value type: `decay_t<U>`
/// - This range will have the same category as the input range (excluding
/// contiguous ranges). Contiguous ranges are reduced to random access ranges.
///
struct transform_fn : transform_base_fn
{
using transform_base_fn::operator();
template<typename Fun>
constexpr auto operator()(Fun fun) const
{
return make_view_closure(bind_back(transform_base_fn{}, std::move(fun)));
}
};
/// \relates transform_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(transform_fn, transform)
} // namespace views
namespace cpp20
{
namespace views
{
using ranges::views::transform;
}
template(typename Rng, typename F)(
requires input_range<Rng> AND copy_constructible<F> AND view_<Rng> AND
std::is_object<F>::value AND
regular_invocable<F &, iter_reference_t<iterator_t<Rng>>>)
using transform_view = ranges::transform_view<Rng, F>;
} // namespace cpp20
/// @}
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#include <range/v3/detail/satisfy_boost_range.hpp>
RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view)
RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view)
#endif