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