295 lines
10 KiB
C++
295 lines
10 KiB
C++
|
/*!
|
||
|
@file
|
||
|
Defines `boost::hana::range`.
|
||
|
|
||
|
@copyright Louis Dionne 2013-2016
|
||
|
Distributed under the Boost Software License, Version 1.0.
|
||
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||
|
*/
|
||
|
|
||
|
#ifndef BOOST_HANA_RANGE_HPP
|
||
|
#define BOOST_HANA_RANGE_HPP
|
||
|
|
||
|
#include <boost/hana/fwd/range.hpp>
|
||
|
|
||
|
#include <boost/hana/bool.hpp>
|
||
|
#include <boost/hana/concept/integral_constant.hpp>
|
||
|
#include <boost/hana/config.hpp>
|
||
|
#include <boost/hana/core/common.hpp>
|
||
|
#include <boost/hana/core/to.hpp>
|
||
|
#include <boost/hana/core/tag_of.hpp>
|
||
|
#include <boost/hana/detail/operators/adl.hpp>
|
||
|
#include <boost/hana/detail/operators/comparable.hpp>
|
||
|
#include <boost/hana/detail/operators/iterable.hpp>
|
||
|
#include <boost/hana/fwd/at.hpp>
|
||
|
#include <boost/hana/fwd/back.hpp>
|
||
|
#include <boost/hana/fwd/contains.hpp>
|
||
|
#include <boost/hana/fwd/drop_front.hpp>
|
||
|
#include <boost/hana/fwd/drop_front_exactly.hpp>
|
||
|
#include <boost/hana/fwd/equal.hpp>
|
||
|
#include <boost/hana/fwd/find.hpp>
|
||
|
#include <boost/hana/fwd/front.hpp>
|
||
|
#include <boost/hana/fwd/is_empty.hpp>
|
||
|
#include <boost/hana/fwd/length.hpp>
|
||
|
#include <boost/hana/fwd/maximum.hpp>
|
||
|
#include <boost/hana/fwd/minimum.hpp>
|
||
|
#include <boost/hana/fwd/product.hpp>
|
||
|
#include <boost/hana/fwd/sum.hpp>
|
||
|
#include <boost/hana/fwd/unpack.hpp>
|
||
|
#include <boost/hana/integral_constant.hpp> // required by fwd decl and below
|
||
|
#include <boost/hana/optional.hpp>
|
||
|
#include <boost/hana/value.hpp>
|
||
|
|
||
|
#include <cstddef>
|
||
|
#include <utility>
|
||
|
|
||
|
|
||
|
BOOST_HANA_NAMESPACE_BEGIN
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// range<>
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//! @cond
|
||
|
template <typename T, T From, T To>
|
||
|
struct range
|
||
|
: detail::operators::adl<range<T, From, To>>
|
||
|
, detail::iterable_operators<range<T, From, To>>
|
||
|
{
|
||
|
static_assert(From <= To,
|
||
|
"hana::make_range(from, to) requires 'from <= to'");
|
||
|
|
||
|
using value_type = T;
|
||
|
static constexpr value_type from = From;
|
||
|
static constexpr value_type to = To;
|
||
|
};
|
||
|
//! @endcond
|
||
|
|
||
|
template <typename T, T From, T To>
|
||
|
struct tag_of<range<T, From, To>> {
|
||
|
using type = range_tag;
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// make<range_tag>
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct make_impl<range_tag> {
|
||
|
template <typename From, typename To>
|
||
|
static constexpr auto apply(From const&, To const&) {
|
||
|
|
||
|
#ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
|
||
|
static_assert(hana::IntegralConstant<From>::value,
|
||
|
"hana::make_range(from, to) requires 'from' to be an IntegralConstant");
|
||
|
|
||
|
static_assert(hana::IntegralConstant<To>::value,
|
||
|
"hana::make_range(from, to) requires 'to' to be an IntegralConstant");
|
||
|
#endif
|
||
|
|
||
|
using T = typename common<
|
||
|
typename hana::tag_of<From>::type::value_type,
|
||
|
typename hana::tag_of<To>::type::value_type
|
||
|
>::type;
|
||
|
constexpr T from = hana::to<T>(From::value);
|
||
|
constexpr T to = hana::to<T>(To::value);
|
||
|
return range<T, from, to>{};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Operators
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
namespace detail {
|
||
|
template <>
|
||
|
struct comparable_operators<range_tag> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Comparable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct equal_impl<range_tag, range_tag> {
|
||
|
template <typename R1, typename R2>
|
||
|
static constexpr auto apply(R1 const&, R2 const&) {
|
||
|
return hana::bool_c<
|
||
|
(R1::from == R1::to && R2::from == R2::to) ||
|
||
|
(R1::from == R2::from && R1::to == R2::to)
|
||
|
>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Foldable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct unpack_impl<range_tag> {
|
||
|
template <typename T, T from, typename F, T ...v>
|
||
|
static constexpr decltype(auto)
|
||
|
unpack_helper(F&& f, std::integer_sequence<T, v...>) {
|
||
|
return static_cast<F&&>(f)(integral_constant<T, from + v>{}...);
|
||
|
}
|
||
|
|
||
|
template <typename T, T from, T to, typename F>
|
||
|
static constexpr decltype(auto) apply(range<T, from, to> const&, F&& f) {
|
||
|
return unpack_helper<T, from>(static_cast<F&&>(f),
|
||
|
std::make_integer_sequence<T, to - from>{});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct length_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return hana::size_c<static_cast<std::size_t>(to - from)>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct minimum_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return integral_c<T, from>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct maximum_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return integral_c<T, to-1>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct sum_impl<range_tag> {
|
||
|
// Returns the sum of `[m, n]`, where `m <= n` always hold.
|
||
|
template <typename I>
|
||
|
static constexpr I sum_helper(I m, I n) {
|
||
|
if (m == n)
|
||
|
return m;
|
||
|
|
||
|
// 0 == m < n
|
||
|
else if (0 == m)
|
||
|
return n * (n+1) / 2;
|
||
|
|
||
|
// 0 < m < n
|
||
|
else if (0 < m)
|
||
|
return sum_helper(0, n) - sum_helper(0, m-1);
|
||
|
|
||
|
// m < 0 <= n
|
||
|
else if (0 <= n)
|
||
|
return sum_helper(0, n) - sum_helper(0, -m);
|
||
|
|
||
|
// m < n < 0
|
||
|
else
|
||
|
return -sum_helper(-n, -m);
|
||
|
}
|
||
|
|
||
|
template <typename, typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&) {
|
||
|
return integral_c<T, from == to ? 0 : sum_helper(from, to-1)>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct product_impl<range_tag> {
|
||
|
// Returns the product of `[m, n)`, where `m <= n` always hold.
|
||
|
template <typename I>
|
||
|
static constexpr I product_helper(I m, I n) {
|
||
|
if (m <= 0 && 0 < n)
|
||
|
return 0;
|
||
|
else {
|
||
|
I p = 1;
|
||
|
for (; m != n; ++m)
|
||
|
p *= m;
|
||
|
return p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template <typename, typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return integral_c<T, product_helper(from, to)>; }
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Searchable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct find_impl<range_tag> {
|
||
|
template <typename T, T from, typename N>
|
||
|
static constexpr auto find_helper(hana::true_) {
|
||
|
constexpr T n = N::value;
|
||
|
return hana::just(hana::integral_c<T, n>);
|
||
|
}
|
||
|
|
||
|
template <typename T, T from, typename N>
|
||
|
static constexpr auto find_helper(hana::false_)
|
||
|
{ return hana::nothing; }
|
||
|
|
||
|
template <typename T, T from, T to, typename N>
|
||
|
static constexpr auto apply(range<T, from, to> const&, N const&) {
|
||
|
constexpr auto n = N::value;
|
||
|
return find_helper<T, from, N>(hana::bool_c<(n >= from && n < to)>);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct contains_impl<range_tag> {
|
||
|
template <typename T, T from, T to, typename N>
|
||
|
static constexpr auto apply(range<T, from, to> const&, N const&) {
|
||
|
constexpr auto n = N::value;
|
||
|
return bool_c<(n >= from && n < to)>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Iterable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct front_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return integral_c<T, from>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct is_empty_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return bool_c<from == to>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct at_impl<range_tag> {
|
||
|
template <typename T, T from, T to, typename N>
|
||
|
static constexpr auto apply(range<T, from, to> const&, N const&) {
|
||
|
constexpr auto n = N::value;
|
||
|
return integral_c<T, from + n>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct back_impl<range_tag> {
|
||
|
template <typename T, T from, T to>
|
||
|
static constexpr auto apply(range<T, from, to> const&)
|
||
|
{ return integral_c<T, to - 1>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct drop_front_impl<range_tag> {
|
||
|
template <typename T, T from, T to, typename N>
|
||
|
static constexpr auto apply(range<T, from, to> const&, N const&) {
|
||
|
constexpr auto n = N::value;
|
||
|
return range<T, (to < from + n ? to : from + n), to>{};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct drop_front_exactly_impl<range_tag> {
|
||
|
template <typename T, T from, T to, typename N>
|
||
|
static constexpr auto apply(range<T, from, to> const&, N const&) {
|
||
|
constexpr auto n = N::value;
|
||
|
return range<T, from + n, to>{};
|
||
|
}
|
||
|
};
|
||
|
BOOST_HANA_NAMESPACE_END
|
||
|
|
||
|
#endif // !BOOST_HANA_RANGE_HPP
|