File indexing completed on 2025-01-18 09:38:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_HANA_MAP_HPP
0011 #define BOOST_HANA_MAP_HPP
0012
0013 #include <boost/hana/fwd/map.hpp>
0014
0015 #include <boost/hana/all_of.hpp>
0016 #include <boost/hana/basic_tuple.hpp>
0017 #include <boost/hana/bool.hpp>
0018 #include <boost/hana/concept/comparable.hpp>
0019 #include <boost/hana/concept/constant.hpp>
0020 #include <boost/hana/concept/product.hpp>
0021 #include <boost/hana/config.hpp>
0022 #include <boost/hana/contains.hpp>
0023 #include <boost/hana/core/is_a.hpp>
0024 #include <boost/hana/core/make.hpp>
0025 #include <boost/hana/core/to.hpp>
0026 #include <boost/hana/detail/decay.hpp>
0027 #include <boost/hana/detail/fast_and.hpp>
0028 #include <boost/hana/detail/has_duplicates.hpp>
0029 #include <boost/hana/detail/hash_table.hpp>
0030 #include <boost/hana/detail/intrinsics.hpp>
0031 #include <boost/hana/detail/operators/adl.hpp>
0032 #include <boost/hana/detail/operators/comparable.hpp>
0033 #include <boost/hana/detail/operators/searchable.hpp>
0034 #include <boost/hana/equal.hpp>
0035 #include <boost/hana/find.hpp>
0036 #include <boost/hana/first.hpp>
0037 #include <boost/hana/fold_left.hpp>
0038 #include <boost/hana/functional/demux.hpp>
0039 #include <boost/hana/functional/on.hpp>
0040 #include <boost/hana/functional/partial.hpp>
0041 #include <boost/hana/fwd/any_of.hpp>
0042 #include <boost/hana/fwd/at_key.hpp>
0043 #include <boost/hana/fwd/difference.hpp>
0044 #include <boost/hana/fwd/erase_key.hpp>
0045 #include <boost/hana/fwd/intersection.hpp>
0046 #include <boost/hana/fwd/is_subset.hpp>
0047 #include <boost/hana/fwd/keys.hpp>
0048 #include <boost/hana/fwd/union.hpp>
0049 #include <boost/hana/insert.hpp>
0050 #include <boost/hana/integral_constant.hpp>
0051 #include <boost/hana/keys.hpp>
0052 #include <boost/hana/length.hpp>
0053 #include <boost/hana/optional.hpp>
0054 #include <boost/hana/remove_if.hpp>
0055 #include <boost/hana/second.hpp>
0056 #include <boost/hana/unpack.hpp>
0057 #include <boost/hana/value.hpp>
0058
0059
0060 #include <cstddef>
0061 #include <type_traits>
0062 #include <utility>
0063
0064
0065 namespace boost { namespace hana {
0066
0067
0068
0069 namespace detail {
0070 template <>
0071 struct comparable_operators<map_tag> {
0072 static constexpr bool value = true;
0073 };
0074 }
0075
0076
0077
0078
0079
0080 namespace detail {
0081 template <typename ...>
0082 struct storage_is_default_constructible;
0083 template <typename ...T>
0084 struct storage_is_default_constructible<hana::basic_tuple<T...>> {
0085 static constexpr bool value = detail::fast_and<
0086 BOOST_HANA_TT_IS_CONSTRUCTIBLE(T)...
0087 >::value;
0088 };
0089
0090 template <typename ...>
0091 struct storage_is_copy_constructible;
0092 template <typename ...T>
0093 struct storage_is_copy_constructible<hana::basic_tuple<T...>> {
0094 static constexpr bool value = detail::fast_and<
0095 BOOST_HANA_TT_IS_CONSTRUCTIBLE(T, T const&)...
0096 >::value;
0097 };
0098
0099 template <typename ...>
0100 struct storage_is_move_constructible;
0101 template <typename ...T>
0102 struct storage_is_move_constructible<hana::basic_tuple<T...>> {
0103 static constexpr bool value = detail::fast_and<
0104 BOOST_HANA_TT_IS_CONSTRUCTIBLE(T, T&&)...
0105 >::value;
0106 };
0107
0108 template <typename ...>
0109 struct storage_is_copy_assignable;
0110 template <typename ...T>
0111 struct storage_is_copy_assignable<hana::basic_tuple<T...>> {
0112 static constexpr bool value = detail::fast_and<
0113 BOOST_HANA_TT_IS_ASSIGNABLE(T, T const&)...
0114 >::value;
0115 };
0116
0117 template <typename ...>
0118 struct storage_is_move_assignable;
0119 template <typename ...T>
0120 struct storage_is_move_assignable<hana::basic_tuple<T...>> {
0121 static constexpr bool value = detail::fast_and<
0122 BOOST_HANA_TT_IS_ASSIGNABLE(T, T&&)...
0123 >::value;
0124 };
0125
0126 template <typename HashTable, typename Storage>
0127 struct map_impl final
0128 : detail::searchable_operators<map_impl<HashTable, Storage>>
0129 , detail::operators::adl<map_impl<HashTable, Storage>>
0130 {
0131 using hash_table_type = HashTable;
0132 using storage_type = Storage;
0133
0134 Storage storage;
0135
0136 using hana_tag = map_tag;
0137
0138 template <typename ...P, typename = typename std::enable_if<
0139 std::is_same<
0140 Storage,
0141 hana::basic_tuple<typename detail::decay<P>::type...>
0142 >::value
0143 >::type>
0144 explicit constexpr map_impl(P&& ...pairs)
0145 : storage{static_cast<P&&>(pairs)...}
0146 { }
0147
0148 explicit constexpr map_impl(Storage&& xs)
0149 : storage(static_cast<Storage&&>(xs))
0150 { }
0151
0152 template <typename ...Dummy, typename = typename std::enable_if<
0153 detail::storage_is_default_constructible<Storage, Dummy...>::value
0154 >::type>
0155 constexpr map_impl()
0156 : storage()
0157 { }
0158
0159 template <typename ...Dummy, typename = typename std::enable_if<
0160 detail::storage_is_copy_constructible<Storage, Dummy...>::value
0161 >::type>
0162 constexpr map_impl(map_impl const& other)
0163 : storage(other.storage)
0164 { }
0165
0166 template <typename ...Dummy, typename = typename std::enable_if<
0167 detail::storage_is_move_constructible<Storage, Dummy...>::value
0168 >::type>
0169 constexpr map_impl(map_impl&& other)
0170 : storage(static_cast<Storage&&>(other.storage))
0171 { }
0172
0173 template <typename ...Dummy, typename = typename std::enable_if<
0174 detail::storage_is_move_assignable<Storage, Dummy...>::value
0175 >::type>
0176 constexpr map_impl& operator=(map_impl&& other) {
0177 storage = static_cast<Storage&&>(other.storage);
0178 return *this;
0179 }
0180
0181 template <typename ...Dummy, typename = typename std::enable_if<
0182 detail::storage_is_copy_assignable<Storage, Dummy...>::value
0183 >::type>
0184 constexpr map_impl& operator=(map_impl const& other) {
0185 storage = other.storage;
0186 return *this;
0187 }
0188
0189
0190
0191 ~map_impl() = default;
0192 };
0193
0194
0195 template <typename Storage>
0196 struct KeyAtIndex {
0197 template <std::size_t i>
0198 using apply = decltype(hana::first(hana::at_c<i>(std::declval<Storage>())));
0199 };
0200
0201 template <typename ...Pairs>
0202 struct make_map_type {
0203 using Storage = hana::basic_tuple<Pairs...>;
0204 using HashTable = typename detail::make_hash_table<
0205 detail::KeyAtIndex<Storage>::template apply, sizeof...(Pairs)
0206 >::type;
0207 using type = detail::map_impl<HashTable, Storage>;
0208 };
0209 }
0210
0211
0212
0213
0214 template <>
0215 struct make_impl<map_tag> {
0216 template <typename ...Pairs>
0217 static constexpr auto apply(Pairs&& ...pairs) {
0218 #if defined(BOOST_HANA_CONFIG_ENABLE_DEBUG_MODE)
0219 static_assert(detail::fast_and<hana::Product<Pairs>::value...>::value,
0220 "hana::make_map(pairs...) requires all the 'pairs' to be Products");
0221
0222 static_assert(detail::fast_and<
0223 hana::Comparable<decltype(hana::first(pairs))>::value...
0224 >::value,
0225 "hana::make_map(pairs...) requires all the keys to be Comparable");
0226
0227 static_assert(detail::fast_and<
0228 hana::Constant<
0229 decltype(hana::equal(hana::first(pairs), hana::first(pairs)))
0230 >::value...
0231 >::value,
0232 "hana::make_map(pairs...) requires all the keys to be "
0233 "Comparable at compile-time");
0234
0235
0236
0237
0238 static_assert(!detail::has_duplicates<decltype(hana::first(pairs))...>::value,
0239 "hana::make_map({keys, values}...) requires all the keys to be unique");
0240
0241 static_assert(!detail::has_duplicates<decltype(hana::hash(hana::first(pairs)))...>::value,
0242 "hana::make_map({keys, values}...) requires all the keys to have different hashes");
0243 #endif
0244
0245 using Map = typename detail::make_map_type<typename detail::decay<Pairs>::type...>::type;
0246 return Map{hana::make_basic_tuple(static_cast<Pairs&&>(pairs)...)};
0247 }
0248 };
0249
0250
0251
0252
0253 template <>
0254 struct keys_impl<map_tag> {
0255 template <typename Map>
0256 static constexpr decltype(auto) apply(Map&& map) {
0257 return hana::transform(static_cast<Map&&>(map).storage, hana::first);
0258 }
0259 };
0260
0261
0262
0263
0264
0265 template <typename Map>
0266 constexpr decltype(auto) values_t::operator()(Map&& map) const {
0267 return hana::transform(static_cast<Map&&>(map).storage, hana::second);
0268 }
0269
0270
0271
0272
0273
0274 template <>
0275 struct insert_impl<map_tag> {
0276 template <typename Map, typename Pair>
0277 static constexpr auto helper(Map&& map, Pair&& pair, ...) {
0278 using RawMap = typename std::remove_reference<Map>::type;
0279 using HashTable = typename RawMap::hash_table_type;
0280 using NewHashTable = typename detail::bucket_insert<
0281 HashTable,
0282 decltype(hana::first(pair)),
0283 decltype(hana::length(map.storage))::value
0284 >::type;
0285
0286 using NewStorage = decltype(
0287 hana::append(static_cast<Map&&>(map).storage, static_cast<Pair&&>(pair))
0288 );
0289 return detail::map_impl<NewHashTable, NewStorage>(
0290 hana::append(static_cast<Map&&>(map).storage, static_cast<Pair&&>(pair))
0291 );
0292 }
0293
0294 template <typename Map, typename Pair, std::size_t i>
0295 static constexpr auto
0296 helper(Map&& map, Pair&&,
0297 hana::optional<std::integral_constant<std::size_t, i>>)
0298 {
0299 return static_cast<Map&&>(map);
0300 }
0301
0302
0303
0304
0305
0306 template <typename Map, typename Pair>
0307 static constexpr auto apply(Map&& map, Pair&& pair) {
0308 using RawMap = typename std::remove_reference<Map>::type;
0309 using Storage = typename RawMap::storage_type;
0310 using HashTable = typename RawMap::hash_table_type;
0311 using Key = decltype(hana::first(pair));
0312 using MaybeIndex = typename detail::find_index<
0313 HashTable, Key, detail::KeyAtIndex<Storage>::template apply
0314 >::type;
0315 return helper(static_cast<Map&&>(map), static_cast<Pair&&>(pair), MaybeIndex{});
0316 }
0317 };
0318
0319
0320
0321
0322 template <>
0323 struct erase_key_impl<map_tag> {
0324
0325
0326
0327 template <typename Map, typename Key>
0328 static constexpr auto
0329 erase_key_helper(Map&& map, Key const&, hana::false_) {
0330 return static_cast<Map&&>(map);
0331 }
0332
0333 template <typename Map, typename Key>
0334 static constexpr auto
0335 erase_key_helper(Map&& map, Key const& key, hana::true_) {
0336 return hana::unpack(
0337 hana::remove_if(static_cast<Map&&>(map).storage,
0338 hana::on(hana::equal.to(key), hana::first)),
0339 hana::make_map
0340 );
0341 }
0342
0343 template <typename Map, typename Key>
0344 static constexpr auto apply_impl(Map&& map, Key const& key, hana::false_) {
0345 return erase_key_helper(static_cast<Map&&>(map), key,
0346 hana::contains(map, key));
0347 }
0348
0349 template <typename Map, typename Key>
0350 static constexpr auto apply_impl(Map&& map, Key const&, hana::true_) {
0351 return static_cast<Map&&>(map);
0352 }
0353
0354 template <typename Map, typename Key>
0355 static constexpr auto apply(Map&& map, Key const& key) {
0356 constexpr bool is_empty = decltype(hana::length(map))::value == 0;
0357 return apply_impl(static_cast<Map&&>(map), key, hana::bool_<is_empty>{});
0358 }
0359 };
0360
0361
0362
0363
0364 template <>
0365 struct equal_impl<map_tag, map_tag> {
0366 template <typename M1, typename M2>
0367 static constexpr auto equal_helper(M1 const&, M2 const&, hana::false_) {
0368 return hana::false_c;
0369 }
0370
0371 template <typename M1, typename M2>
0372 static constexpr auto equal_helper(M1 const& m1, M2 const& m2, hana::true_) {
0373 return hana::all_of(hana::keys(m1), hana::demux(equal)(
0374 hana::partial(hana::find, m1),
0375 hana::partial(hana::find, m2)
0376 ));
0377 }
0378
0379 template <typename M1, typename M2>
0380 static constexpr auto apply(M1 const& m1, M2 const& m2) {
0381 return equal_impl::equal_helper(m1, m2, hana::bool_c<
0382 decltype(hana::length(m1.storage))::value ==
0383 decltype(hana::length(m2.storage))::value
0384 >);
0385 }
0386 };
0387
0388
0389
0390
0391 template <>
0392 struct find_impl<map_tag> {
0393 template <typename Map>
0394 static constexpr auto find_helper(Map&&, ...) {
0395 return hana::nothing;
0396 }
0397
0398 template <typename Map, std::size_t i>
0399 static constexpr auto
0400 find_helper(Map&& map, hana::optional<std::integral_constant<std::size_t, i>>) {
0401 return hana::just(hana::second(hana::at_c<i>(static_cast<Map&&>(map).storage)));
0402 }
0403
0404 template <typename Map, typename Key>
0405 static constexpr auto apply(Map&& map, Key const&) {
0406 using RawMap = typename std::remove_reference<Map>::type;
0407 using Storage = typename RawMap::storage_type;
0408 using HashTable = typename RawMap::hash_table_type;
0409 using MaybeIndex = typename detail::find_index<
0410 HashTable, Key, detail::KeyAtIndex<Storage>::template apply
0411 >::type;
0412 return find_helper(static_cast<Map&&>(map), MaybeIndex{});
0413 }
0414 };
0415
0416 template <>
0417 struct find_if_impl<map_tag> {
0418 template <typename M, typename Pred>
0419 static constexpr auto apply(M&& map, Pred&& pred) {
0420 return hana::transform(
0421 hana::find_if(static_cast<M&&>(map).storage,
0422 hana::compose(static_cast<Pred&&>(pred), hana::first)),
0423 hana::second
0424 );
0425 }
0426 };
0427
0428 template <>
0429 struct contains_impl<map_tag> {
0430 template <typename Map, typename Key>
0431 static constexpr auto apply(Map const&, Key const&) {
0432 using RawMap = typename std::remove_reference<Map>::type;
0433 using HashTable = typename RawMap::hash_table_type;
0434 using Storage = typename RawMap::storage_type;
0435 using MaybeIndex = typename detail::find_index<
0436 HashTable, Key, detail::KeyAtIndex<Storage>::template apply
0437 >::type;
0438 return hana::bool_<!decltype(hana::is_nothing(MaybeIndex{}))::value>{};
0439 }
0440 };
0441
0442 template <>
0443 struct any_of_impl<map_tag> {
0444 template <typename M, typename Pred>
0445 static constexpr auto apply(M const& map, Pred const& pred)
0446 { return hana::any_of(hana::keys(map), pred); }
0447 };
0448
0449 template <>
0450 struct is_subset_impl<map_tag, map_tag> {
0451 template <typename Ys>
0452 struct all_contained {
0453 Ys const& ys;
0454 template <typename ...X>
0455 constexpr auto operator()(X const& ...x) const {
0456 return hana::bool_c<detail::fast_and<
0457 hana::value<decltype(hana::contains(ys, x))>()...
0458 >::value>;
0459 }
0460 };
0461
0462 template <typename Xs, typename Ys>
0463 static constexpr auto apply(Xs const& xs, Ys const& ys) {
0464 auto ys_keys = hana::keys(ys);
0465 return hana::unpack(hana::keys(xs), all_contained<decltype(ys_keys)>{ys_keys});
0466 }
0467 };
0468
0469 template <>
0470 struct at_key_impl<map_tag> {
0471 template <typename Map, typename Key>
0472 static constexpr decltype(auto) apply(Map&& map, Key const&) {
0473 using RawMap = typename std::remove_reference<Map>::type;
0474 using HashTable = typename RawMap::hash_table_type;
0475 using Storage = typename RawMap::storage_type;
0476 using MaybeIndex = typename detail::find_index<
0477 HashTable, Key, detail::KeyAtIndex<Storage>::template apply
0478 >::type;
0479 static_assert(!decltype(hana::is_nothing(MaybeIndex{}))::value,
0480 "hana::at_key(map, key) requires the 'key' to be present in the 'map'");
0481 constexpr std::size_t index = decltype(*MaybeIndex{}){}();
0482 return hana::second(hana::at_c<index>(static_cast<Map&&>(map).storage));
0483 }
0484 };
0485
0486
0487
0488
0489 template <>
0490 struct union_impl<map_tag> {
0491 template <typename Xs, typename Ys>
0492 static constexpr auto apply(Xs&& xs, Ys&& ys) {
0493 return hana::fold_left(static_cast<Xs&&>(xs), static_cast<Ys&&>(ys),
0494 hana::insert);
0495 }
0496 };
0497
0498
0499
0500
0501 namespace detail {
0502 template <typename Ys>
0503 struct map_insert_if_contains {
0504 Ys const& ys;
0505
0506
0507
0508 template <typename Result, typename Pair>
0509 static constexpr auto helper(Result&& result, Pair&& pair, hana::true_) {
0510 return hana::insert(static_cast<Result&&>(result), static_cast<Pair&&>(pair));
0511 }
0512
0513 template <typename Result, typename Pair>
0514 static constexpr auto helper(Result&& result, Pair&&, hana::false_) {
0515 return static_cast<Result&&>(result);
0516 }
0517
0518 template <typename Result, typename Pair>
0519 constexpr auto operator()(Result&& result, Pair&& pair) const {
0520 constexpr bool keep = hana::value<decltype(hana::contains(ys, hana::first(pair)))>();
0521 return map_insert_if_contains::helper(static_cast<Result&&>(result),
0522 static_cast<Pair&&>(pair),
0523 hana::bool_c<keep>);
0524 }
0525 };
0526 }
0527
0528 template <>
0529 struct intersection_impl<map_tag> {
0530 template <typename Xs, typename Ys>
0531 static constexpr auto apply(Xs&& xs, Ys const& ys) {
0532 return hana::fold_left(static_cast<Xs&&>(xs), hana::make_map(),
0533 detail::map_insert_if_contains<Ys>{ys});
0534 }
0535 };
0536
0537
0538
0539
0540 template <>
0541 struct difference_impl<map_tag> {
0542 template <typename Xs, typename Ys>
0543 static constexpr auto apply(Xs&& xs, Ys&& ys) {
0544 return hana::fold_left(
0545 hana::keys(static_cast<Ys&&>(ys)),
0546 static_cast<Xs&&>(xs),
0547 hana::erase_key);
0548 }
0549 };
0550
0551
0552
0553
0554 template <>
0555 struct unpack_impl<map_tag> {
0556 template <typename M, typename F>
0557 static constexpr decltype(auto) apply(M&& map, F&& f) {
0558 return hana::unpack(static_cast<M&&>(map).storage,
0559 static_cast<F&&>(f));
0560 }
0561 };
0562
0563
0564
0565
0566 template <typename F>
0567 struct to_impl<map_tag, F, when<hana::Foldable<F>::value>> {
0568 template <typename Xs>
0569 static constexpr decltype(auto) apply(Xs&& xs) {
0570 return hana::fold_left(
0571 static_cast<Xs&&>(xs), hana::make_map(), hana::insert
0572 );
0573 }
0574 };
0575 }}
0576
0577 #endif