| 1 | // Copyright Louis Dionne 2013-2022 |
| 2 | // Distributed under the Boost Software License, Version 1.0. |
| 3 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) |
| 4 | |
| 5 | #include <boost/hana.hpp> |
| 6 | #include <boost/hana/ext/boost/mpl.hpp> |
| 7 | #include <boost/hana/ext/std.hpp> |
| 8 | |
| 9 | #include <boost/mpl/lambda.hpp> |
| 10 | #include <boost/mpl/placeholders.hpp> |
| 11 | #include <boost/mpl/quote.hpp> |
| 12 | |
| 13 | #include <iostream> |
| 14 | #include <type_traits> |
| 15 | namespace hana = boost::hana; |
| 16 | namespace mpl = boost::mpl; |
| 17 | |
| 18 | |
| 19 | namespace hpl { |
| 20 | ////////////////////////////////////////////////////////////////////////////// |
| 21 | // Utilities |
| 22 | ////////////////////////////////////////////////////////////////////////////// |
| 23 | namespace detail { |
| 24 | template <typename Pred> |
| 25 | constexpr auto mpl_predicate = hana::integral(hana::metafunction_class< |
| 26 | typename mpl::lambda<Pred>::type |
| 27 | >); |
| 28 | |
| 29 | template <typename F> |
| 30 | constexpr auto mpl_metafunction = hana::metafunction_class< |
| 31 | typename mpl::lambda<F>::type |
| 32 | >; |
| 33 | } |
| 34 | |
| 35 | ////////////////////////////////////////////////////////////////////////////// |
| 36 | // integral_c |
| 37 | ////////////////////////////////////////////////////////////////////////////// |
| 38 | template <typename T, T v> |
| 39 | using integral_c = std::integral_constant<T, v>; |
| 40 | |
| 41 | template <int i> |
| 42 | using int_ = integral_c<int, i>; |
| 43 | |
| 44 | template <long i> |
| 45 | using long_ = integral_c<long, i>; |
| 46 | |
| 47 | template <bool b> |
| 48 | using bool_ = integral_c<bool, b>; |
| 49 | |
| 50 | using true_ = bool_<true>; |
| 51 | using false_ = bool_<false>; |
| 52 | |
| 53 | |
| 54 | ////////////////////////////////////////////////////////////////////////////// |
| 55 | // Sequences, compile-time integers & al |
| 56 | // |
| 57 | // Differences with the MPL: |
| 58 | // 1. `pair<...>::first` and `pair<...>::second` won't work; |
| 59 | // use `first<pair<...>>` instead |
| 60 | ////////////////////////////////////////////////////////////////////////////// |
| 61 | template <typename ...T> |
| 62 | using vector = hana::tuple<hana::type<T>...>; |
| 63 | |
| 64 | template <typename T, T ...v> |
| 65 | using vector_c = hana::tuple<hana::integral_constant<T, v>...>; |
| 66 | |
| 67 | template <typename T, T from, T to> |
| 68 | using range_c = decltype(hana::range_c<T, from, to>); |
| 69 | |
| 70 | |
| 71 | template <typename T, typename U> |
| 72 | using pair = hana::pair<hana::type<T>, hana::type<U>>; |
| 73 | |
| 74 | template <typename P> |
| 75 | struct first : decltype(+hana::first(P{})) { }; |
| 76 | |
| 77 | template <typename P> |
| 78 | struct second : decltype(+hana::second(P{})) { }; |
| 79 | |
| 80 | |
| 81 | ////////////////////////////////////////////////////////////////////////////// |
| 82 | // Miscellaneous metafunctions |
| 83 | ////////////////////////////////////////////////////////////////////////////// |
| 84 | template <typename C1, typename C2> |
| 85 | struct equal_to |
| 86 | : bool_<C1::value == C2::value> |
| 87 | { }; |
| 88 | |
| 89 | template <typename C1, typename C2> |
| 90 | struct less |
| 91 | : bool_<(C1::value < C2::value)> |
| 92 | { }; |
| 93 | |
| 94 | template <typename C1, typename C2> |
| 95 | struct greater |
| 96 | : bool_<(C1::value > C2::value)> |
| 97 | { }; |
| 98 | |
| 99 | template <typename N> |
| 100 | struct next |
| 101 | : integral_c<typename N::value_type, N::value + 1> |
| 102 | { }; |
| 103 | |
| 104 | ////////////////////////////////////////////////////////////////////////////// |
| 105 | // Intrinsics |
| 106 | // |
| 107 | // Differences with the MPL: |
| 108 | // 1. `at` does not work for associative sequences; use `find` instead. |
| 109 | // 2. `begin`, `end`, `clear`, `erase`, `erase_key`, `insert`, `insert_range`, |
| 110 | // `is_sequence`, `key_type`, `order`, `sequence_tag`, `value_type`: not implemented |
| 111 | ////////////////////////////////////////////////////////////////////////////// |
| 112 | template <typename Sequence, typename N> |
| 113 | struct at |
| 114 | : decltype(hana::at(Sequence{}, N{})) |
| 115 | { }; |
| 116 | |
| 117 | template <typename Sequence, long n> |
| 118 | using at_c = at<Sequence, long_<n>>; |
| 119 | |
| 120 | template <typename Sequence> |
| 121 | struct back |
| 122 | : decltype(+hana::back(Sequence{})) |
| 123 | { }; |
| 124 | |
| 125 | template <typename Sequence> |
| 126 | struct empty |
| 127 | : decltype(hana::is_empty(Sequence{})) |
| 128 | { }; |
| 129 | |
| 130 | template <typename Sequence> |
| 131 | struct front |
| 132 | : decltype(+hana::front(Sequence{})) |
| 133 | { }; |
| 134 | |
| 135 | template <typename Sequence> |
| 136 | struct pop_back { |
| 137 | using type = decltype(hana::drop_back( |
| 138 | hana::to_tuple(Sequence{}), hana::size_c<1> |
| 139 | )); |
| 140 | }; |
| 141 | |
| 142 | template <typename Sequence> |
| 143 | struct pop_front { |
| 144 | using type = decltype(hana::drop_front(Sequence{})); |
| 145 | }; |
| 146 | |
| 147 | template <typename Sequence, typename T> |
| 148 | struct push_back { |
| 149 | using type = decltype(hana::append(Sequence{}, hana::type_c<T>)); |
| 150 | }; |
| 151 | |
| 152 | template <typename Sequence, typename T> |
| 153 | struct push_front { |
| 154 | using type = decltype(hana::prepend(Sequence{}, hana::type_c<T>)); |
| 155 | }; |
| 156 | |
| 157 | template <typename Sequence> |
| 158 | struct size |
| 159 | : decltype(hana::length(Sequence{})) |
| 160 | { }; |
| 161 | |
| 162 | ////////////////////////////////////////////////////////////////////////////// |
| 163 | // Iteration algorithms |
| 164 | // |
| 165 | // Differences with the MPL: |
| 166 | // 1. reverse_fold: |
| 167 | // Does not take an optional additional ForwardOp argument. |
| 168 | // |
| 169 | // 2. iter_fold, reverse_iter_fold: |
| 170 | // Not implemented because we don't use iterators |
| 171 | ////////////////////////////////////////////////////////////////////////////// |
| 172 | template <typename Sequence, typename State, typename F> |
| 173 | struct fold |
| 174 | : decltype(hana::fold( |
| 175 | Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F> |
| 176 | )) |
| 177 | { }; |
| 178 | |
| 179 | template <typename Sequence, typename State, typename F> |
| 180 | struct reverse_fold |
| 181 | : decltype(hana::reverse_fold( |
| 182 | Sequence{}, hana::type_c<State>, detail::mpl_metafunction<F> |
| 183 | )) |
| 184 | { }; |
| 185 | |
| 186 | template <typename Sequence, typename State, typename F> |
| 187 | using accumulate = fold<Sequence, State, F>; |
| 188 | |
| 189 | ////////////////////////////////////////////////////////////////////////////// |
| 190 | // Query algorithms |
| 191 | // |
| 192 | // Differences with the MPL: |
| 193 | // 1. find_if and find: |
| 194 | // Instead of returning an iterator, they either have a nested `::type` |
| 195 | // alias to the answer, or they have no nested `::type` at all, which |
| 196 | // makes them SFINAE-friendly. |
| 197 | // |
| 198 | // 2. lower_bound, upper_bound: |
| 199 | // Not implemented. |
| 200 | // |
| 201 | // 3. {min,max}_element: |
| 202 | // Not returning an iterator, and also won't work on empty sequences. |
| 203 | ////////////////////////////////////////////////////////////////////////////// |
| 204 | template <typename Sequence, typename Pred> |
| 205 | struct find_if |
| 206 | : decltype(hana::find_if(Sequence{}, detail::mpl_predicate<Pred>)) |
| 207 | { }; |
| 208 | |
| 209 | template <typename Sequence, typename T> |
| 210 | struct find |
| 211 | : decltype(hana::find(Sequence{}, hana::type_c<T>)) |
| 212 | { }; |
| 213 | |
| 214 | template <typename Sequence, typename T> |
| 215 | struct contains |
| 216 | : decltype(hana::contains(Sequence{}, hana::type_c<T>)) |
| 217 | { }; |
| 218 | |
| 219 | template <typename Sequence, typename T> |
| 220 | struct count |
| 221 | : decltype(hana::count(Sequence{}, hana::type_c<T>)) |
| 222 | { }; |
| 223 | |
| 224 | template <typename Sequence, typename Pred> |
| 225 | struct count_if |
| 226 | : decltype(hana::count_if(Sequence{}, detail::mpl_predicate<Pred>)) |
| 227 | { }; |
| 228 | |
| 229 | template <typename Sequence, typename Pred = mpl::quote2<less>> |
| 230 | struct min_element |
| 231 | : decltype(hana::minimum(Sequence{}, detail::mpl_predicate<Pred>)) |
| 232 | { }; |
| 233 | |
| 234 | template <typename Sequence, typename Pred = mpl::quote2<less>> |
| 235 | struct max_element |
| 236 | : decltype(hana::maximum(Sequence{}, detail::mpl_predicate<Pred>)) |
| 237 | { }; |
| 238 | |
| 239 | template <typename S1, typename S2, typename Pred = mpl::quote2<std::is_same>> |
| 240 | struct equal |
| 241 | : decltype( // inefficient but whatever |
| 242 | hana::length(S1{}) == hana::length(S2{}) && |
| 243 | hana::all(hana::zip_shortest_with(detail::mpl_predicate<Pred>, |
| 244 | hana::to_tuple(S1{}), |
| 245 | hana::to_tuple(S2{}))) |
| 246 | ) |
| 247 | { }; |
| 248 | |
| 249 | ////////////////////////////////////////////////////////////////////////////// |
| 250 | // Transformation algorithms |
| 251 | // |
| 252 | // Differences from the MPL: |
| 253 | // 1. The algorithms do not accept an optional inserter, and they always |
| 254 | // return a `vector`. |
| 255 | // 2. stable_partition: not implemented |
| 256 | // 3. All the reverse_* algorithms are not implemented. |
| 257 | ////////////////////////////////////////////////////////////////////////////// |
| 258 | template <typename Sequence> |
| 259 | struct copy { |
| 260 | using type = decltype(hana::to_tuple(Sequence{})); |
| 261 | }; |
| 262 | |
| 263 | template <typename Sequence, typename Pred> |
| 264 | struct copy_if { |
| 265 | using type = decltype(hana::filter( |
| 266 | hana::to_tuple(Sequence{}), |
| 267 | detail::mpl_predicate<Pred> |
| 268 | )); |
| 269 | }; |
| 270 | |
| 271 | template <typename Sequence, typename Sequence_or_Op, typename = void> |
| 272 | struct transform; |
| 273 | |
| 274 | template <typename Sequence, typename Op> |
| 275 | struct transform<Sequence, Op> { |
| 276 | using type = decltype(hana::transform( |
| 277 | hana::to_tuple(Sequence{}), detail::mpl_metafunction<Op> |
| 278 | )); |
| 279 | }; |
| 280 | |
| 281 | template <typename S1, typename S2, typename Op> |
| 282 | struct transform { |
| 283 | using type = decltype(hana::zip_with( |
| 284 | detail::mpl_metafunction<Op>, |
| 285 | hana::to_tuple(S1{}), |
| 286 | hana::to_tuple(S2{}) |
| 287 | )); |
| 288 | }; |
| 289 | |
| 290 | template <typename Sequence, typename OldType, typename NewType> |
| 291 | struct replace { |
| 292 | using type = decltype(hana::replace( |
| 293 | hana::to_tuple(Sequence{}), |
| 294 | hana::type_c<OldType>, |
| 295 | hana::type_c<NewType> |
| 296 | )); |
| 297 | }; |
| 298 | |
| 299 | template <typename Sequence, typename Pred, typename NewType> |
| 300 | struct replace_if { |
| 301 | using type = decltype(hana::replace_if( |
| 302 | hana::to_tuple(Sequence{}), |
| 303 | detail::mpl_predicate<Pred>, |
| 304 | hana::type_c<NewType> |
| 305 | )); |
| 306 | }; |
| 307 | |
| 308 | template <typename Sequence, typename T> |
| 309 | struct remove { |
| 310 | using type = decltype(hana::filter( |
| 311 | hana::to_tuple(Sequence{}), |
| 312 | hana::not_equal.to(hana::type_c<T>) |
| 313 | )); |
| 314 | }; |
| 315 | |
| 316 | template <typename Sequence, typename Pred> |
| 317 | struct remove_if { |
| 318 | using type = decltype(hana::filter( |
| 319 | hana::to_tuple(Sequence{}), |
| 320 | hana::compose(hana::not_, detail::mpl_predicate<Pred>) |
| 321 | )); |
| 322 | }; |
| 323 | |
| 324 | template <typename Sequence, typename Pred> |
| 325 | struct unique { |
| 326 | using type = decltype(hana::unique( |
| 327 | hana::to_tuple(Sequence{}), |
| 328 | detail::mpl_predicate<Pred> |
| 329 | )); |
| 330 | }; |
| 331 | |
| 332 | template <typename Sequence, typename Pred> |
| 333 | struct partition { |
| 334 | using hana_pair = decltype(hana::partition( |
| 335 | hana::to_tuple(Sequence{}), |
| 336 | detail::mpl_predicate<Pred> |
| 337 | )); |
| 338 | using type = pair< |
| 339 | decltype(hana::first(hana_pair{})), |
| 340 | decltype(hana::second(hana_pair{})) |
| 341 | >; |
| 342 | }; |
| 343 | |
| 344 | template <typename Sequence, typename Pred = mpl::quote2<less>> |
| 345 | struct sort { |
| 346 | using type = decltype(hana::sort( |
| 347 | hana::to_tuple(Sequence{}), detail::mpl_predicate<Pred> |
| 348 | )); |
| 349 | }; |
| 350 | |
| 351 | template <typename Sequence> |
| 352 | struct reverse { |
| 353 | using type = decltype(hana::reverse(hana::to_tuple(Sequence{}))); |
| 354 | }; |
| 355 | |
| 356 | |
| 357 | ////////////////////////////////////////////////////////////////////////////// |
| 358 | // Runtime algorithms |
| 359 | ////////////////////////////////////////////////////////////////////////////// |
| 360 | template <typename Sequence, typename F> |
| 361 | void for_each(F f) { |
| 362 | hana::for_each(Sequence{}, [&f](auto t) { |
| 363 | f(typename decltype(t)::type{}); |
| 364 | }); |
| 365 | } |
| 366 | |
| 367 | template <typename Sequence, typename TransformOp, typename F> |
| 368 | void for_each(F f) { |
| 369 | for_each<typename transform<Sequence, TransformOp>::type>(f); |
| 370 | } |
| 371 | |
| 372 | } // end namespace hpl |
| 373 | |
| 374 | |
| 375 | template <typename N> |
| 376 | struct is_odd |
| 377 | : hpl::bool_<(N::value % 2)> |
| 378 | { }; |
| 379 | |
| 380 | |
| 381 | int main() { |
| 382 | using namespace hpl; |
| 383 | |
| 384 | ////////////////////////////////////////////////////////////////////////////// |
| 385 | // Misc |
| 386 | ////////////////////////////////////////////////////////////////////////////// |
| 387 | |
| 388 | // pair |
| 389 | { |
| 390 | static_assert(std::is_same<first<pair<int, float>>::type, int>{}, "" ); |
| 391 | static_assert(std::is_same<second<pair<int, float>>::type, float>{}, "" ); |
| 392 | } |
| 393 | |
| 394 | ////////////////////////////////////////////////////////////////////////////// |
| 395 | // Intrinsics |
| 396 | ////////////////////////////////////////////////////////////////////////////// |
| 397 | |
| 398 | // at |
| 399 | { |
| 400 | using range = range_c<long,10,50>; |
| 401 | static_assert(at<range, int_<0>>::value == 10, "" ); |
| 402 | static_assert(at<range, int_<10>>::value == 20, "" ); |
| 403 | static_assert(at<range, int_<40>>::value == 50, "" ); |
| 404 | } |
| 405 | |
| 406 | // at_c |
| 407 | { |
| 408 | using range = range_c<long, 10, 50>; |
| 409 | static_assert(at_c<range, 0>::value == 10, "" ); |
| 410 | static_assert(at_c<range, 10>::value == 20, "" ); |
| 411 | static_assert(at_c<range, 40>::value == 50, "" ); |
| 412 | } |
| 413 | |
| 414 | // back |
| 415 | { |
| 416 | using range1 = range_c<int,0,1>; |
| 417 | using range2 = range_c<int,0,10>; |
| 418 | using range3 = range_c<int,-10,0>; |
| 419 | using types = vector<int, char, float>; |
| 420 | static_assert(back<range1>::value == 0, "" ); |
| 421 | static_assert(back<range2>::value == 9, "" ); |
| 422 | static_assert(back<range3>::value == -1, "" ); |
| 423 | static_assert(std::is_same<back<types>::type, float>{}, "" ); |
| 424 | } |
| 425 | |
| 426 | // empty |
| 427 | { |
| 428 | using empty_range = range_c<int,0,0>; |
| 429 | using types = vector<long,float,double>; |
| 430 | static_assert(empty<empty_range>{}, "" ); |
| 431 | static_assert(!empty<types>{}, "" ); |
| 432 | } |
| 433 | |
| 434 | // front |
| 435 | { |
| 436 | using types1 = vector<long>; |
| 437 | using types2 = vector<int,long>; |
| 438 | using types3 = vector<char,int,long>; |
| 439 | static_assert(std::is_same<front<types1>::type, long>{}, "" ); |
| 440 | static_assert(std::is_same<front<types2>::type, int>{}, "" ); |
| 441 | static_assert(std::is_same<front<types3>::type, char>{}, "" ); |
| 442 | } |
| 443 | |
| 444 | // pop_back |
| 445 | { |
| 446 | using types1 = vector<long>; |
| 447 | using types2 = vector<long,int>; |
| 448 | using types3 = vector<long,int,char>; |
| 449 | |
| 450 | |
| 451 | using result1 = pop_back<types1>::type; |
| 452 | using result2 = pop_back<types2>::type; |
| 453 | using result3 = pop_back<types3>::type; |
| 454 | |
| 455 | static_assert(size<result1>::value == 0, "" ); |
| 456 | static_assert(size<result2>::value == 1, "" ); |
| 457 | static_assert(size<result3>::value == 2, "" ); |
| 458 | |
| 459 | static_assert(std::is_same< back<result2>::type, long>{}, "" ); |
| 460 | static_assert(std::is_same< back<result3>::type, int>{}, "" ); |
| 461 | } |
| 462 | |
| 463 | // pop_front |
| 464 | { |
| 465 | using types1 = vector<long>; |
| 466 | using types2 = vector<int,long>; |
| 467 | using types3 = vector<char,int,long>; |
| 468 | |
| 469 | using result1 = pop_front<types1>::type; |
| 470 | using result2 = pop_front<types2>::type; |
| 471 | using result3 = pop_front<types3>::type; |
| 472 | |
| 473 | static_assert(size<result1>::value == 0, "" ); |
| 474 | static_assert(size<result2>::value == 1, "" ); |
| 475 | static_assert(size<result3>::value == 2, "" ); |
| 476 | |
| 477 | static_assert(std::is_same<front<result2>::type, long>{}, "" ); |
| 478 | static_assert(std::is_same<front<result3>::type, int>{}, "" ); |
| 479 | } |
| 480 | |
| 481 | // push_back |
| 482 | { |
| 483 | using bools = vector_c<bool,false,false,false,true,true,true,false,false>; |
| 484 | using message = push_back<bools, false_>::type; |
| 485 | static_assert(back<message>::type::value == false, "" ); |
| 486 | static_assert(count_if<message, equal_to<mpl::_1, false_>>{} == 6u, "" ); |
| 487 | } |
| 488 | |
| 489 | // push_front |
| 490 | { |
| 491 | using v = vector_c<int,1,2,3,5,8,13,21>; |
| 492 | static_assert(size<v>{} == 7u, "" ); |
| 493 | |
| 494 | using fibonacci = push_front<v, int_<1>>::type; |
| 495 | static_assert(size<fibonacci>{} == 8u, "" ); |
| 496 | |
| 497 | static_assert(equal< |
| 498 | fibonacci, |
| 499 | vector_c<int,1,1,2,3,5,8,13,21>, |
| 500 | equal_to<mpl::_, mpl::_> |
| 501 | >{}, "" ); |
| 502 | } |
| 503 | |
| 504 | // size |
| 505 | { |
| 506 | using empty_list = vector<>; |
| 507 | using numbers = vector_c<int,0,1,2,3,4,5>; |
| 508 | using more_numbers = range_c<int,0,100>; |
| 509 | |
| 510 | static_assert(size<empty_list>{} == 0u, "" ); |
| 511 | static_assert(size<numbers>{} == 6u, "" ); |
| 512 | static_assert(size<more_numbers>{} == 100u, "" ); |
| 513 | } |
| 514 | |
| 515 | |
| 516 | ////////////////////////////////////////////////////////////////////////////// |
| 517 | // Iteration algorithms |
| 518 | ////////////////////////////////////////////////////////////////////////////// |
| 519 | |
| 520 | // fold |
| 521 | { |
| 522 | using types = vector<long,float,short,double,float,long,long double>; |
| 523 | using number_of_floats = fold<types, int_<0>, |
| 524 | mpl::if_<std::is_floating_point<mpl::_2>, |
| 525 | next<mpl::_1>, |
| 526 | mpl::_1 |
| 527 | > |
| 528 | >::type; |
| 529 | static_assert(number_of_floats{} == 4, "" ); |
| 530 | } |
| 531 | |
| 532 | // reverse_fold |
| 533 | { |
| 534 | using numbers = vector_c<int,5,-1,0,-7,-2,0,-5,4>; |
| 535 | using negatives = vector_c<int,-1,-7,-2,-5>; |
| 536 | using result = reverse_fold<numbers, vector_c<int>, |
| 537 | mpl::if_<less<mpl::_2, int_<0>>, |
| 538 | push_front<mpl::_1, mpl::_2>, |
| 539 | mpl::_1 |
| 540 | > |
| 541 | >::type; |
| 542 | static_assert(equal<negatives, result>{}, "" ); |
| 543 | } |
| 544 | |
| 545 | ////////////////////////////////////////////////////////////////////////////// |
| 546 | // Query algorithms |
| 547 | ////////////////////////////////////////////////////////////////////////////// |
| 548 | |
| 549 | // find_if |
| 550 | { |
| 551 | using types = vector<char,int,unsigned,long,unsigned long>; |
| 552 | using found = find_if<types, std::is_same<mpl::_1, unsigned>>::type; |
| 553 | static_assert(std::is_same<found, unsigned>{}, "" ); |
| 554 | } |
| 555 | |
| 556 | // find |
| 557 | { |
| 558 | using types = vector<char,int,unsigned,long,unsigned long>; |
| 559 | static_assert(std::is_same<find<types, unsigned>::type, unsigned>{}, "" ); |
| 560 | } |
| 561 | |
| 562 | // contains |
| 563 | { |
| 564 | using types = vector<char,int,unsigned,long,unsigned long>; |
| 565 | static_assert(!contains<types, bool>{}, "" ); |
| 566 | } |
| 567 | |
| 568 | // count |
| 569 | { |
| 570 | using types = vector<int,char,long,short,char,short,double,long>; |
| 571 | static_assert(count<types, short>{} == 2u, "" ); |
| 572 | } |
| 573 | |
| 574 | // count_if |
| 575 | { |
| 576 | using types = vector<int,char,long,short,char,long,double,long>; |
| 577 | static_assert(count_if<types, std::is_floating_point<mpl::_>>{} == 1u, "" ); |
| 578 | static_assert(count_if<types, std::is_same<mpl::_, char>>{} == 2u, "" ); |
| 579 | static_assert(count_if<types, std::is_same<mpl::_, void>>{} == 0u, "" ); |
| 580 | } |
| 581 | |
| 582 | // min_element (MPL's example is completely broken) |
| 583 | { |
| 584 | } |
| 585 | |
| 586 | // max_element (MPL's example is completely broken) |
| 587 | { |
| 588 | } |
| 589 | |
| 590 | // equal |
| 591 | { |
| 592 | using s1 = vector<char,int,unsigned,long,unsigned long>; |
| 593 | using s2 = vector<char,int,unsigned,long>; |
| 594 | static_assert(!equal<s1,s2>{}, "" ); |
| 595 | } |
| 596 | |
| 597 | |
| 598 | ////////////////////////////////////////////////////////////////////////////// |
| 599 | // Transformaton algorithms |
| 600 | ////////////////////////////////////////////////////////////////////////////// |
| 601 | // copy |
| 602 | { |
| 603 | using numbers = vector_c<int,10, 11, 12, 13, 14, 15, 16, 17, 18, 19>; |
| 604 | using result = copy<range_c<int, 10, 20>>::type; |
| 605 | static_assert(size<result>{} == 10u, "" ); |
| 606 | static_assert(equal<result, numbers, mpl::quote2<equal_to>>{}, "" ); |
| 607 | } |
| 608 | |
| 609 | // copy_if |
| 610 | { |
| 611 | using result = copy_if<range_c<int, 0, 10>, less<mpl::_1, int_<5>>>::type; |
| 612 | static_assert(size<result>{} == 5u, "" ); |
| 613 | static_assert(equal<result, range_c<int, 0, 5>>{}, "" ); |
| 614 | } |
| 615 | |
| 616 | // transform |
| 617 | { |
| 618 | using types = vector<char,short,int,long,float,double>; |
| 619 | using pointers = vector<char*,short*,int*,long*,float*,double*>; |
| 620 | using result = transform<types,std::add_pointer<mpl::_1>>::type; |
| 621 | static_assert(equal<result, pointers>{}, "" ); |
| 622 | } |
| 623 | |
| 624 | // replace |
| 625 | { |
| 626 | using types = vector<int,float,char,float,float,double>; |
| 627 | using expected = vector<int,double,char,double,double,double>; |
| 628 | using result = replace< types,float,double >::type; |
| 629 | static_assert(equal<result, expected>{}, "" ); |
| 630 | } |
| 631 | |
| 632 | // replace_if |
| 633 | { |
| 634 | using numbers = vector_c<int,1,4,5,2,7,5,3,5>; |
| 635 | using expected = vector_c<int,1,4,0,2,0,0,3,0>; |
| 636 | using result = replace_if<numbers, greater<mpl::_, int_<4>>, int_<0>>::type; |
| 637 | static_assert(equal<result, expected, mpl::quote2<equal_to>>{}, "" ); |
| 638 | } |
| 639 | |
| 640 | // remove |
| 641 | { |
| 642 | using types = vector<int,float,char,float,float,double>; |
| 643 | using result = hpl::remove<types, float>::type; |
| 644 | static_assert(equal<result, vector<int, char, double>>{}, "" ); |
| 645 | } |
| 646 | |
| 647 | // remove_if |
| 648 | { |
| 649 | using numbers = vector_c<int,1,4,5,2,7,5,3,5>; |
| 650 | using result = remove_if<numbers, greater<mpl::_, int_<4> > >::type; |
| 651 | static_assert(equal<result, vector_c<int,1,4,2,3>, mpl::quote2<equal_to>>{}, "" ); |
| 652 | } |
| 653 | |
| 654 | // unique |
| 655 | { |
| 656 | using types = vector<int,float,float,char,int,int,int,double>; |
| 657 | using expected = vector<int,float,char,int,double>; |
| 658 | using result = unique<types, std::is_same<mpl::_1, mpl::_2>>::type; |
| 659 | static_assert(equal<result, expected>{}, "" ); |
| 660 | } |
| 661 | |
| 662 | // partition |
| 663 | { |
| 664 | using r = partition<range_c<int,0,10>, is_odd<mpl::_1>>::type; |
| 665 | static_assert(equal<first<r>::type, vector_c<int,1,3,5,7,9>>{}, "" ); |
| 666 | static_assert(equal<second<r>::type, vector_c<int,0,2,4,6,8>>{}, "" ); |
| 667 | } |
| 668 | |
| 669 | // sort |
| 670 | { |
| 671 | using numbers = vector_c<int,3,4,0,-5,8,-1,7>; |
| 672 | using expected = vector_c<int,-5,-1,0,3,4,7,8>; |
| 673 | using result = sort<numbers>::type; |
| 674 | static_assert(equal<result, expected, equal_to<mpl::_, mpl::_>>{}, "" ); |
| 675 | } |
| 676 | |
| 677 | // reverse |
| 678 | { |
| 679 | using numbers = vector_c<int,9,8,7,6,5,4,3,2,1,0>; |
| 680 | using result = reverse<numbers>::type; |
| 681 | static_assert(equal<result, range_c<int,0,10>>{}, "" ); |
| 682 | } |
| 683 | |
| 684 | ////////////////////////////////////////////////////////////////////////////// |
| 685 | // Runtime algorithms |
| 686 | ////////////////////////////////////////////////////////////////////////////// |
| 687 | |
| 688 | // for_each |
| 689 | { |
| 690 | auto value_printer = [](auto x) { |
| 691 | std::cout << x << '\n'; |
| 692 | }; |
| 693 | |
| 694 | for_each<range_c<int, 0, 10> >(f: value_printer); |
| 695 | } |
| 696 | |
| 697 | } |
| 698 | |