From 2c1bb3a607dc03489d5f68df65f36cd65510d8dc Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 20 Jun 2014 20:53:06 -0400 Subject: [PATCH] sandbox: add a naive and incomplete map implementation --- include/boost/hana/detail/sandbox/map.hpp | 142 ++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/sandbox/map/foldable.cpp | 47 +++++++ 3 files changed, 190 insertions(+) create mode 100644 include/boost/hana/detail/sandbox/map.hpp create mode 100644 test/sandbox/map/foldable.cpp diff --git a/include/boost/hana/detail/sandbox/map.hpp b/include/boost/hana/detail/sandbox/map.hpp new file mode 100644 index 000000000..e1656ebeb --- /dev/null +++ b/include/boost/hana/detail/sandbox/map.hpp @@ -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 +#include +#include +#include +#include + + +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 + struct bucket; + + BOOST_HANA_CONSTEXPR_LAMBDA auto make_bucket = [](auto h, auto pairs) { + return bucket{h, pairs}; + }; + + template + struct bucket { + Hash hash; + Pairs pairs; // a list of (key, value) pairs + + template + friend constexpr auto operator==(bucket b1, bucket b2) + { return b1.hash == b2.hash && b1.pairs == b2.pairs; } + + template + 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 + constexpr auto lookup(Key key) const { + return fmap( + second, + find([=](auto p) { return first(p) == key; }, pairs) + ); + } + }; + + template + 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 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 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 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 : defaults::with { + template + 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 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c30464d8b..b8d57d8a7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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) diff --git a/test/sandbox/map/foldable.cpp b/test/sandbox/map/foldable.cpp new file mode 100644 index 000000000..c7c96d4ee --- /dev/null +++ b/test/sandbox/map/foldable.cpp @@ -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 + +#include +#include +#include +#include + +#include +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)); +}