1 /*!
2 @file
3 Defines `boost::hana::range`.
4 
5 @copyright Louis Dionne 2013-2017
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_HANA_RANGE_HPP
11 #define BOOST_HANA_RANGE_HPP
12 
13 #include <boost/hana/fwd/range.hpp>
14 
15 #include <boost/hana/bool.hpp>
16 #include <boost/hana/concept/integral_constant.hpp>
17 #include <boost/hana/config.hpp>
18 #include <boost/hana/core/common.hpp>
19 #include <boost/hana/core/to.hpp>
20 #include <boost/hana/core/tag_of.hpp>
21 #include <boost/hana/detail/operators/adl.hpp>
22 #include <boost/hana/detail/operators/comparable.hpp>
23 #include <boost/hana/detail/operators/iterable.hpp>
24 #include <boost/hana/fwd/at.hpp>
25 #include <boost/hana/fwd/back.hpp>
26 #include <boost/hana/fwd/contains.hpp>
27 #include <boost/hana/fwd/drop_front.hpp>
28 #include <boost/hana/fwd/drop_front_exactly.hpp>
29 #include <boost/hana/fwd/equal.hpp>
30 #include <boost/hana/fwd/find.hpp>
31 #include <boost/hana/fwd/front.hpp>
32 #include <boost/hana/fwd/is_empty.hpp>
33 #include <boost/hana/fwd/length.hpp>
34 #include <boost/hana/fwd/maximum.hpp>
35 #include <boost/hana/fwd/minimum.hpp>
36 #include <boost/hana/fwd/product.hpp>
37 #include <boost/hana/fwd/sum.hpp>
38 #include <boost/hana/fwd/unpack.hpp>
39 #include <boost/hana/integral_constant.hpp> // required by fwd decl and below
40 #include <boost/hana/optional.hpp>
41 #include <boost/hana/value.hpp>
42 
43 #include <cstddef>
44 #include <utility>
45 
46 
47 BOOST_HANA_NAMESPACE_BEGIN
48     //////////////////////////////////////////////////////////////////////////
49     // range<>
50     //////////////////////////////////////////////////////////////////////////
51     //! @cond
52     template <typename T, T From, T To>
53     struct range
54         : detail::operators::adl<range<T, From, To>>
55         , detail::iterable_operators<range<T, From, To>>
56     {
57         static_assert(From <= To,
58         "hana::make_range(from, to) requires 'from <= to'");
59 
60         using value_type = T;
61         static constexpr value_type from = From;
62         static constexpr value_type to = To;
63     };
64     //! @endcond
65 
66     template <typename T, T From, T To>
67     struct tag_of<range<T, From, To>> {
68         using type = range_tag;
69     };
70 
71     //////////////////////////////////////////////////////////////////////////
72     // make<range_tag>
73     //////////////////////////////////////////////////////////////////////////
74     template <>
75     struct make_impl<range_tag> {
76         template <typename From, typename To>
applymake_impl77         static constexpr auto apply(From const&, To const&) {
78 
79         #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
80             static_assert(hana::IntegralConstant<From>::value,
81             "hana::make_range(from, to) requires 'from' to be an IntegralConstant");
82 
83             static_assert(hana::IntegralConstant<To>::value,
84             "hana::make_range(from, to) requires 'to' to be an IntegralConstant");
85         #endif
86 
87             using T = typename common<
88                 typename hana::tag_of<From>::type::value_type,
89                 typename hana::tag_of<To>::type::value_type
90             >::type;
91             constexpr T from = hana::to<T>(From::value);
92             constexpr T to = hana::to<T>(To::value);
93             return range<T, from, to>{};
94         }
95     };
96 
97     //////////////////////////////////////////////////////////////////////////
98     // Operators
99     //////////////////////////////////////////////////////////////////////////
100     namespace detail {
101         template <>
102         struct comparable_operators<range_tag> {
103             static constexpr bool value = true;
104         };
105     }
106 
107     //////////////////////////////////////////////////////////////////////////
108     // Comparable
109     //////////////////////////////////////////////////////////////////////////
110     template <>
111     struct equal_impl<range_tag, range_tag> {
112         template <typename R1, typename R2>
applyequal_impl113         static constexpr auto apply(R1 const&, R2 const&) {
114             return hana::bool_c<
115                 (R1::from == R1::to && R2::from == R2::to) ||
116                 (R1::from == R2::from && R1::to == R2::to)
117             >;
118         }
119     };
120 
121     //////////////////////////////////////////////////////////////////////////
122     // Foldable
123     //////////////////////////////////////////////////////////////////////////
124     template <>
125     struct unpack_impl<range_tag> {
126         template <typename T, T from, typename F, T ...v>
127         static constexpr decltype(auto)
unpack_helperunpack_impl128         unpack_helper(F&& f, std::integer_sequence<T, v...>) {
129             return static_cast<F&&>(f)(integral_constant<T, from + v>{}...);
130         }
131 
132         template <typename T, T from, T to, typename F>
applyunpack_impl133         static constexpr decltype(auto) apply(range<T, from, to> const&, F&& f) {
134             return unpack_helper<T, from>(static_cast<F&&>(f),
135                 std::make_integer_sequence<T, to - from>{});
136         }
137     };
138 
139     template <>
140     struct length_impl<range_tag> {
141         template <typename T, T from, T to>
applylength_impl142         static constexpr auto apply(range<T, from, to> const&)
143         { return hana::size_c<static_cast<std::size_t>(to - from)>; }
144     };
145 
146     template <>
147     struct minimum_impl<range_tag> {
148         template <typename T, T from, T to>
applyminimum_impl149         static constexpr auto apply(range<T, from, to> const&)
150         { return integral_c<T, from>; }
151     };
152 
153     template <>
154     struct maximum_impl<range_tag> {
155         template <typename T, T from, T to>
applymaximum_impl156         static constexpr auto apply(range<T, from, to> const&)
157         { return integral_c<T, to-1>; }
158     };
159 
160     template <>
161     struct sum_impl<range_tag> {
162         // Returns the sum of `[m, n]`, where `m <= n` always hold.
163         template <typename I>
sum_helpersum_impl164         static constexpr I sum_helper(I m, I n) {
165             if (m == n)
166                 return m;
167 
168             // 0 == m < n
169             else if (0 == m)
170                 return n * (n+1) / 2;
171 
172             // 0 < m < n
173             else if (0 < m)
174                 return sum_helper(0, n) - sum_helper(0, m-1);
175 
176             // m < 0 <= n
177             else if (0 <= n)
178                 return sum_helper(0, n) - sum_helper(0, -m);
179 
180             // m < n < 0
181             else
182                 return -sum_helper(-n, -m);
183         }
184 
185         template <typename, typename T, T from, T to>
applysum_impl186         static constexpr auto apply(range<T, from, to> const&) {
187             return integral_c<T, from == to ? 0 : sum_helper(from, to-1)>;
188         }
189     };
190 
191     template <>
192     struct product_impl<range_tag> {
193         // Returns the product of `[m, n)`, where `m <= n` always hold.
194         template <typename I>
product_helperproduct_impl195         static constexpr I product_helper(I m, I n) {
196             if (m <= 0 && 0 < n)
197                 return 0;
198             else {
199                 I p = 1;
200                 for (; m != n; ++m)
201                     p *= m;
202                 return p;
203             }
204         }
205 
206         template <typename, typename T, T from, T to>
applyproduct_impl207         static constexpr auto apply(range<T, from, to> const&)
208         { return integral_c<T, product_helper(from, to)>; }
209     };
210 
211     //////////////////////////////////////////////////////////////////////////
212     // Searchable
213     //////////////////////////////////////////////////////////////////////////
214     template <>
215     struct find_impl<range_tag> {
216         template <typename T, T from, typename N>
find_helperfind_impl217         static constexpr auto find_helper(hana::true_) {
218             constexpr T n = N::value;
219             return hana::just(hana::integral_c<T, n>);
220         }
221 
222         template <typename T, T from, typename N>
find_helperfind_impl223         static constexpr auto find_helper(hana::false_)
224         { return hana::nothing; }
225 
226         template <typename T, T from, T to, typename N>
applyfind_impl227         static constexpr auto apply(range<T, from, to> const&, N const&) {
228             constexpr auto n = N::value;
229             return find_helper<T, from, N>(hana::bool_c<(n >= from && n < to)>);
230         }
231     };
232 
233     template <>
234     struct contains_impl<range_tag> {
235         template <typename T, T from, T to, typename N>
applycontains_impl236         static constexpr auto apply(range<T, from, to> const&, N const&) {
237             constexpr auto n = N::value;
238             return bool_c<(n >= from && n < to)>;
239         }
240     };
241 
242     //////////////////////////////////////////////////////////////////////////
243     // Iterable
244     //////////////////////////////////////////////////////////////////////////
245     template <>
246     struct front_impl<range_tag> {
247         template <typename T, T from, T to>
applyfront_impl248         static constexpr auto apply(range<T, from, to> const&)
249         { return integral_c<T, from>; }
250     };
251 
252     template <>
253     struct is_empty_impl<range_tag> {
254         template <typename T, T from, T to>
applyis_empty_impl255         static constexpr auto apply(range<T, from, to> const&)
256         { return bool_c<from == to>; }
257     };
258 
259     template <>
260     struct at_impl<range_tag> {
261         template <typename T, T from, T to, typename N>
applyat_impl262         static constexpr auto apply(range<T, from, to> const&, N const&) {
263             constexpr auto n = N::value;
264             return integral_c<T, from + n>;
265         }
266     };
267 
268     template <>
269     struct back_impl<range_tag> {
270         template <typename T, T from, T to>
applyback_impl271         static constexpr auto apply(range<T, from, to> const&)
272         { return integral_c<T, to - 1>; }
273     };
274 
275     template <>
276     struct drop_front_impl<range_tag> {
277         template <typename T, T from, T to, typename N>
applydrop_front_impl278         static constexpr auto apply(range<T, from, to> const&, N const&) {
279             constexpr auto n = N::value;
280             return range<T, (to < from + n ? to : from + n), to>{};
281         }
282     };
283 
284     template <>
285     struct drop_front_exactly_impl<range_tag> {
286         template <typename T, T from, T to, typename N>
applydrop_front_exactly_impl287         static constexpr auto apply(range<T, from, to> const&, N const&) {
288             constexpr auto n = N::value;
289             return range<T, from + n, to>{};
290         }
291     };
292 BOOST_HANA_NAMESPACE_END
293 
294 #endif // !BOOST_HANA_RANGE_HPP
295