mirror of
https://github.com/boostorg/hana.git
synced 2026-02-15 01:02:10 +00:00
sandbox: add a naive and incomplete map implementation
This commit is contained in:
142
include/boost/hana/detail/sandbox/map.hpp
Normal file
142
include/boost/hana/detail/sandbox/map.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*!
|
||||
@file
|
||||
Defines `boost::hana::sandbox::map`.
|
||||
|
||||
@copyright Louis Dionne 2014
|
||||
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_DETAIL_SANDBOX_MAP_HPP
|
||||
#define BOOST_HANA_DETAIL_SANDBOX_MAP_HPP
|
||||
|
||||
#include <boost/hana/detail/constexpr.hpp>
|
||||
#include <boost/hana/foldable.hpp>
|
||||
#include <boost/hana/list.hpp>
|
||||
#include <boost/hana/logical.hpp>
|
||||
#include <boost/hana/maybe.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace hana {
|
||||
namespace sandbox {
|
||||
struct Map;
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto pair = [](auto x, auto y) {
|
||||
return [=](auto f) { return f(x, y); };
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto second = [](auto p) {
|
||||
return p([](auto x, auto y) { return y; });
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto first = [](auto p) {
|
||||
return p([](auto x, auto y) { return x; });
|
||||
};
|
||||
|
||||
namespace map_detail {
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto replace = [](auto pred, auto new_val, auto xs) {
|
||||
auto go = [=](auto x) { return if_(pred(x), new_val, x); };
|
||||
return fmap(go, xs);
|
||||
};
|
||||
|
||||
template <typename Hash, typename Pairs>
|
||||
struct bucket;
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto make_bucket = [](auto h, auto pairs) {
|
||||
return bucket<decltype(h), decltype(pairs)>{h, pairs};
|
||||
};
|
||||
|
||||
template <typename Hash, typename Pairs>
|
||||
struct bucket {
|
||||
Hash hash;
|
||||
Pairs pairs; // a list of (key, value) pairs
|
||||
|
||||
template <typename H1, typename P1, typename H2, typename P2>
|
||||
friend constexpr auto operator==(bucket<H1, P1> b1, bucket<H2, P2> b2)
|
||||
{ return b1.hash == b2.hash && b1.pairs == b2.pairs; }
|
||||
|
||||
template <typename Key, typename Value>
|
||||
constexpr auto insert(Key k, Value v) const {
|
||||
auto iskey = [=](auto pair) { return first(pair) == k; };
|
||||
return eval_if(any(iskey, pairs),
|
||||
[=](auto _) {
|
||||
auto new_pairs = _(replace)(iskey, pair(k, v), pairs);
|
||||
return make_bucket(hash, new_pairs);
|
||||
},
|
||||
[=](auto _) {
|
||||
return make_bucket(hash, _(cons)(pair(k, v), pairs));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
constexpr auto lookup(Key key) const {
|
||||
return fmap(
|
||||
second,
|
||||
find([=](auto p) { return first(p) == key; }, pairs)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Buckets>
|
||||
struct map {
|
||||
Buckets buckets; // a list of buckets
|
||||
using hana_datatype = Map;
|
||||
};
|
||||
}
|
||||
|
||||
//! @todo Create a `Hashable` type class.
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto hash = [](auto x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto insert = [](auto key, auto value, auto map) {
|
||||
auto h = hash(key);
|
||||
// This should be O(1), but for now it'll do.
|
||||
auto bucket = find([=](auto b) { return b.hash == h; }, map.buckets);
|
||||
|
||||
auto insert_in_bucket = [=](auto bucket) {
|
||||
auto new_buckets = replace(_ == bucket, bucket.insert(key, value), map.buckets);
|
||||
map_detail::map<decltype(new_buckets)> new_map{new_buckets};
|
||||
return new_map;
|
||||
};
|
||||
|
||||
auto insert_new_bucket = [=] {
|
||||
auto new_bucket = map_detail::make_bucket(h, list()).insert(key, value);
|
||||
auto buckets = cons(new_bucket, map.buckets);
|
||||
map_detail::map<decltype(buckets)> new_map{buckets};
|
||||
return new_map;
|
||||
};
|
||||
|
||||
// we should not need to evaluate insert_new_bucket.
|
||||
return maybe(insert_new_bucket(), insert_in_bucket, bucket);
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto map = [](auto ...pairs) {
|
||||
map_detail::map<decltype(list())> empty_map{list()};
|
||||
auto ins = [](auto map, auto pair) { return insert(first(pair), second(pair), map); };
|
||||
return foldl(ins, empty_map, list(pairs...));
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto lookup = [](auto key, auto map) {
|
||||
auto h = hash(key);
|
||||
auto bucket = find([=](auto b) { return b.hash == h; }, map.buckets);
|
||||
return maybe(nothing,
|
||||
[=](auto bucket) { return bucket.lookup(key); }
|
||||
, bucket);
|
||||
};
|
||||
} // end namespace sandbox
|
||||
|
||||
template <>
|
||||
struct Foldable<sandbox::Map> : defaults<Foldable>::with<sandbox::Map> {
|
||||
template <typename F, typename State, typename Map>
|
||||
static constexpr auto lazy_foldr_impl(F f, State s, Map m) {
|
||||
auto f_ = [=](auto bucket, auto s) {
|
||||
return lazy_foldr(f, s(), fmap(sandbox::second, bucket().pairs));
|
||||
};
|
||||
return lazy_foldr(f_, s, m.buckets);
|
||||
}
|
||||
};
|
||||
}} // end namespace boost::hana
|
||||
|
||||
#endif // !BOOST_HANA_DETAIL_SANDBOX_MAP_HPP
|
||||
@@ -138,6 +138,7 @@ boost_hana_add_test(sandbox.is_valid)
|
||||
boost_hana_add_test(sandbox.lazy)
|
||||
boost_hana_add_test(sandbox.llist)
|
||||
boost_hana_add_test(sandbox.logical)
|
||||
boost_hana_add_test(sandbox.map.foldable)
|
||||
boost_hana_add_test(sandbox.matrix)
|
||||
boost_hana_add_test(sandbox.operator)
|
||||
boost_hana_add_test(sandbox.ratio)
|
||||
|
||||
47
test/sandbox/map/foldable.cpp
Normal file
47
test/sandbox/map/foldable.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
@copyright Louis Dionne 2014
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
|
||||
#include <boost/hana/detail/sandbox/map.hpp>
|
||||
|
||||
#include <boost/hana/detail/constexpr.hpp>
|
||||
#include <boost/hana/functional.hpp>
|
||||
#include <boost/hana/integral.hpp>
|
||||
#include <boost/hana/list.hpp>
|
||||
|
||||
#include <cassert>
|
||||
using namespace boost::hana;
|
||||
using sandbox::map;
|
||||
using sandbox::pair;
|
||||
using sandbox::second;
|
||||
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto contains = [](auto x, auto xs) {
|
||||
return any(_ == x, xs);
|
||||
};
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto check_fold = [](auto ...pairs) {
|
||||
auto values = fmap(second, list(pairs...));
|
||||
auto result = lazy_foldr(on(cons, apply), list(), map(pairs...));
|
||||
assert(contains(result, permutations(values)));
|
||||
};
|
||||
|
||||
int main() {
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto k1 = int_<1>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto k2 = int_<2>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto k3 = int_<3>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto k4 = int_<4>;
|
||||
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto v1 = char_<'1'>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto v2 = char_<'2'>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto v3 = char_<'3'>;
|
||||
BOOST_HANA_CONSTEXPR_LAMBDA auto v4 = char_<'4'>;
|
||||
|
||||
check_fold();
|
||||
check_fold(pair(k1, v1));
|
||||
check_fold(pair(k1, v1), pair(k2, v2));
|
||||
check_fold(pair(k1, v1), pair(k2, v2), pair(k3, v3));
|
||||
check_fold(pair(k1, v1), pair(k2, v2), pair(k3, v3), pair(k4, v4));
|
||||
}
|
||||
Reference in New Issue
Block a user