From daaba5dfd86e6f2d7dbce8b8b892011e508530ae Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sat, 11 Apr 2015 10:38:52 -0400 Subject: [PATCH] [Map] Provide model of Foldable, improve docs and add `insert` method. Fixes #41 --- example/map.cpp | 114 ++++++++- example/map.from_record.cpp | 44 ++++ include/boost/hana/fwd/map.hpp | 65 ++++- include/boost/hana/fwd/set.hpp | 2 +- include/boost/hana/map.hpp | 63 ++++- include/boost/hana/set.hpp | 8 +- test/CMakeLists.txt | 1 + test/map.cpp | 443 +++++++++++++++++++++++++++++++++ test/map/comparable.cpp | 106 -------- test/map/map.cpp | 138 ---------- test/map/searchable.cpp | 102 -------- 11 files changed, 701 insertions(+), 385 deletions(-) create mode 100644 example/map.from_record.cpp create mode 100644 test/map.cpp delete mode 100644 test/map/comparable.cpp delete mode 100644 test/map/map.cpp delete mode 100644 test/map/searchable.cpp diff --git a/example/map.cpp b/example/map.cpp index f7ace290c..b8e737986 100644 --- a/example/map.cpp +++ b/example/map.cpp @@ -6,10 +6,12 @@ Distributed under the Boost Software License, Version 1.0. #include #include +#include #include #include #include #include +#include #include #include @@ -22,6 +24,7 @@ int main() { //! [make] using namespace std::literals; + auto m = make( make(int_<1>, "foobar"s), make(type, 1234) @@ -33,6 +36,7 @@ auto m = make( //! [make_map] using namespace std::literals; + BOOST_HANA_RUNTIME_CHECK( make_map( make(int_<1>, "foobar"s), @@ -48,8 +52,76 @@ BOOST_HANA_RUNTIME_CHECK( }{ -//! [comparable] +//! [values] using namespace std::literals; + +auto m = make( + make(int_<1>, "foobar"s), + make(type, 1234) +); + +// The order of the values is unspecified. +BOOST_HANA_RUNTIME_CHECK(values(m) ^in^ permutations(make("foobar"s, 1234))); +//! [values] + +}{ + +//! [keys] +using namespace std::literals; + +auto m = make( + make(int_<1>, "foobar"s), + make(type, 1234) +); + +// The order of the keys is unspecified. +BOOST_HANA_CONSTANT_CHECK(keys(m) ^in^ permutations(make(int_<1>, type))); +//! [keys] + +}{ + +//! [from_Foldable] +using namespace std::literals; + +BOOST_HANA_RUNTIME_CHECK( + to(make( + make(type, "abcd"s), + make(type, 1234), + make(type, nullptr) + )) == make( + make(type, "abcd"s), + make(type, 1234) + ) +); +//! [from_Foldable] + +}{ + +//! [insert] +using namespace std::literals; + +auto m = make( + make(type, "abcd"s), + make(type, 1234) +); + +BOOST_HANA_RUNTIME_CHECK( + insert(m, make(type, 'x')) == + make( + make(type, "abcd"s), + make(type, 1234), + make(type, 'x') + ) +); + +BOOST_HANA_RUNTIME_CHECK(insert(m, make(type, 'x')) == m); +//! [insert] + +}{ + +//! [Comparable] +using namespace std::literals; + BOOST_HANA_RUNTIME_CHECK( make_map( make_pair(char_<'a'>, "foobar"s), @@ -61,20 +133,48 @@ BOOST_HANA_RUNTIME_CHECK( make_pair(char_<'a'>, "foobar"s) ) ); -//! [comparable] +//! [Comparable] }{ -//! [searchable] -BOOST_HANA_CONSTEXPR_LAMBDA auto m = make_map( +//! [Searchable] +constexpr auto m = make_map( make_pair(type, 'i'), make_pair(type, 'f') ); -BOOST_HANA_CONSTEXPR_CHECK(find(m, type) == just('i')); -BOOST_HANA_CONSTEXPR_CHECK(find(m, type) == just('f')); +static_assert(find(m, type) == just('i'), ""); +static_assert(find(m, type) == just('f'), ""); BOOST_HANA_CONSTANT_CHECK(find(m, type) == nothing); BOOST_HANA_CONSTANT_CHECK(find(m, int_<3>) == nothing); -//! [searchable] +//! [Searchable] + +}{ + +//! [Foldable] +using namespace std::literals; + +// Given a map of (key, value) pairs, returns a map of (value, key) pairs. +// This requires both the keys and the values to be compile-time Comparable. +auto invert = [](auto map) { + return fold.left(map, make_map(), [](auto map, auto pair) { + return insert(map, make_pair(second(pair), first(pair))); + }); +}; + +auto m = make_map( + make_pair(type, int_<1>), + make_pair(type, int_<2>), + make_pair(int_<3>, type) +); + +BOOST_HANA_CONSTANT_CHECK(invert(m) == + make_map( + make_pair(int_<1>, type), + make_pair(int_<2>, type), + make_pair(type, int_<3>) + ) +); +//! [Foldable] } diff --git a/example/map.from_record.cpp b/example/map.from_record.cpp new file mode 100644 index 000000000..4fd2b0e46 --- /dev/null +++ b/example/map.from_record.cpp @@ -0,0 +1,44 @@ +/* +@copyright Louis Dionne 2015 +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 + +#include +using namespace boost::hana; + + +//! [main] +struct Person { + std::string name; + int age; + + struct hana { struct members_impl { + static BOOST_HANA_CONSTEXPR_LAMBDA auto apply() { + return make( + make(BOOST_HANA_STRING("name"), [](auto&& p) { + return p.name; + }), + make(BOOST_HANA_STRING("age"), [](auto&& p) { + return p.age; + }) + ); + } + };}; +}; + +int main() { + Person john{"John", 35}; + BOOST_HANA_RUNTIME_ASSERT(to(john) == make( + make(BOOST_HANA_STRING("name"), "John"), + make(BOOST_HANA_STRING("age"), 35) + )); +} +//! [main] diff --git a/include/boost/hana/fwd/map.hpp b/include/boost/hana/fwd/map.hpp index 7cb81840a..1e0a16a87 100644 --- a/include/boost/hana/fwd/map.hpp +++ b/include/boost/hana/fwd/map.hpp @@ -27,30 +27,34 @@ namespace boost { namespace hana { //! 1. `Comparable` (operators provided)\n //! Two maps are equal iff all their keys are equal and are associated //! to equal values. - //! @snippet example/map.cpp comparable + //! @snippet example/map.cpp Comparable //! //! 2. `Searchable`\n //! A map can be searched by its keys with a predicate yielding a //! compile-time `Logical`. - //! @snippet example/map.cpp searchable + //! @snippet example/map.cpp Searchable + //! + //! 3. `Foldable`\n + //! Folding a map is equivalent to folding a list of the key/value pairs + //! it contains. In particular, since that list is not guaranteed to be + //! in any specific order, folding a map with an operation that is not + //! both commutative and associative will yield non-deterministic behavior. + //! @snippet example/map.cpp Foldable //! //! //! Provided conversions //! -------------------- //! 1. From any `Record`\n - //! Converting a `Record` `R` to a `Map` is equivalent to converting its - //! `members()` to a `Map`, except the values are replaced by the actual - //! members of the object instead of accessors. + //! Converting a `Record` to a `Map` creates a map where the keys are + //! the keys associated to each member of the `Record`, and the values + //! are the members associated to those keys. + //! @snippet example/map.from_record.cpp main //! //! 2. From any `Foldable`\n - //! Converts a `Foldable` of `Product`s to a `Map`. - //! Note that the foldable structure must not contain duplicate keys. - //! @todo - //! We should allow duplicate keys, with a documented policy (e.g. we - //! keep the last one). - //! - //! 3. To any `Sequence`\n - //! A `Map` can be converted to a Sequence of Products. + //! Converts a `Foldable` of `Product`s to a `Map`. If the structure + //! contains duplicate keys, only the value associated to the first + //! occurence of each key is kept. + //! @snippet example/map.cpp from_Foldable struct Map { }; template @@ -85,6 +89,11 @@ namespace boost { namespace hana { //! Returns a Sequence of the keys of the map, in unspecified order. //! @relates Map + //! + //! + //! Example + //! ------- + //! @snippet example/map.cpp keys #ifdef BOOST_HANA_DOXYGEN_INVOKED constexpr auto keys = [](auto&& map) -> decltype(auto) { return unspecified-type; @@ -100,6 +109,11 @@ namespace boost { namespace hana { //! Returns a Sequence of the values of the map, in unspecified order. //! @relates Map + //! + //! + //! Example + //! ------- + //! @snippet example/map.cpp values #ifdef BOOST_HANA_DOXYGEN_INVOKED constexpr auto values = [](auto&& map) -> decltype(auto) { return unspecified-type; @@ -112,6 +126,31 @@ namespace boost { namespace hana { constexpr _values values{}; #endif + + //! Inserts a new key/value pair in a `Map`. + //! @relates Map + //! + //! Given a `(key, value)` pair, `insert` inserts this new pair into a + //! map. If the map already contains this key, nothing is done and the + //! map is returned as-is. + //! + //! + //! @param map + //! The map in which to insert a `(key,value)` pair. + //! + //! @param pair + //! An arbitrary `Product` representing a `(key, value)` pair to insert + //! in the map. + //! + //! + //! Example + //! ------- + //! @snippet example/map.cpp insert +#ifdef BOOST_HANA_DOXYGEN_INVOKED + constexpr auto insert = [](auto&& map, auto&& pair) -> decltype(auto) { + return tag-dispatched; + }; +#endif }} // end namespace boost::hana #endif // !BOOST_HANA_FWD_MAP_HPP diff --git a/include/boost/hana/fwd/set.hpp b/include/boost/hana/fwd/set.hpp index 89d68389e..39a9b9dd5 100644 --- a/include/boost/hana/fwd/set.hpp +++ b/include/boost/hana/fwd/set.hpp @@ -28,7 +28,7 @@ namespace boost { namespace hana { //! Folding a `Set` is equivalent to folding the sequence of its values. //! However, note that the values are not required to be in any specific //! order, so using the folds provided here with an operation that is not - //! both commutative and associative will yield unspecified behavior. + //! both commutative and associative will yield non-deterministic behavior. //! @snippet example/set.cpp foldable //! //! 3. Searchable\n diff --git a/include/boost/hana/map.hpp b/include/boost/hana/map.hpp index 704d4f23c..0307e704f 100644 --- a/include/boost/hana/map.hpp +++ b/include/boost/hana/map.hpp @@ -19,6 +19,7 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include @@ -27,11 +28,11 @@ Distributed under the Boost Software License, Version 1.0. #include #include #include +#include #include #include #include #include -#include #include @@ -76,17 +77,43 @@ namespace boost { namespace hana { constexpr decltype(auto) _keys::operator()(Map&& map) const { return hana::transform(static_cast(map).storage, first); } + //! @endcond ////////////////////////////////////////////////////////////////////////// // values ////////////////////////////////////////////////////////////////////////// + //! @cond template constexpr decltype(auto) _values::operator()(Map&& map) const { return hana::transform(static_cast(map).storage, second); } - //! @endcond + ////////////////////////////////////////////////////////////////////////// + // insert + ////////////////////////////////////////////////////////////////////////// + template <> + struct insert_impl { + struct insert_helper { + template + constexpr decltype(auto) operator()(M&& map, P&& pair) const { + return hana::unpack( + hana::append(static_cast(map).storage, + static_cast(pair)), + hana::make + ); + } + }; + + template + static constexpr decltype(auto) apply(M&& map, P&& pair) { + return hana::eval_if(hana::elem(map, hana::first(pair)), + hana::lazy(map), + hana::lazy(insert_helper{})(map, pair) + ); + } + }; + ////////////////////////////////////////////////////////////////////////// // Operators ////////////////////////////////////////////////////////////////////////// @@ -134,6 +161,18 @@ namespace boost { namespace hana { { return hana::any_of(hana::keys(map), pred); } }; + ////////////////////////////////////////////////////////////////////////// + // Foldable + ////////////////////////////////////////////////////////////////////////// + template <> + struct unpack_impl { + template + static constexpr decltype(auto) apply(M&& map, F&& f) { + return hana::unpack(static_cast(map).storage, + static_cast(f)); + } + }; + ////////////////////////////////////////////////////////////////////////// // Conversions ////////////////////////////////////////////////////////////////////////// @@ -153,7 +192,7 @@ namespace boost { namespace hana { } template - struct to_impl{}>> { + struct to_impl{}()>> { template static constexpr decltype(auto) apply(X&& x) { return hana::to( @@ -164,17 +203,15 @@ namespace boost { namespace hana { }; template - struct to_impl{} && !_models{}>> { + struct to_impl{}() && + !_models{}()>> + { template - static constexpr decltype(auto) apply(Xs&& xs) - { return hana::unpack(static_cast(xs), make); } - }; - - template - struct to_impl{}>> { - template - static constexpr decltype(auto) apply(M&& m) - { return hana::to(static_cast(m).storage); } + static constexpr decltype(auto) apply(Xs&& xs) { + return hana::fold.left( + static_cast(xs), hana::make(), hana::insert + ); + } }; }} // end namespace boost::hana diff --git a/include/boost/hana/set.hpp b/include/boost/hana/set.hpp index 86e4e18ee..d1e3d3855 100644 --- a/include/boost/hana/set.hpp +++ b/include/boost/hana/set.hpp @@ -139,11 +139,9 @@ namespace boost { namespace hana { template constexpr decltype(auto) operator()(S&& s, X&& x) const { return hana::unpack( - hana::prepend( - static_cast(x), - static_cast(s).storage - ), - hana::set + hana::append(static_cast(s).storage, + static_cast(x)), + hana::make ); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 47406badc..7b843ab02 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,6 +59,7 @@ file(GLOB BOOST_HANA_SPLIT_TEST_SOURCES "ext/std/ratio.cpp" "ext/std/tuple.cpp" "integral_constant.cpp" + "map.cpp" "maybe.cpp" "minimal_record.cpp" "set.cpp" diff --git a/test/map.cpp b/test/map.cpp new file mode 100644 index 000000000..2bdca7d13 --- /dev/null +++ b/test/map.cpp @@ -0,0 +1,443 @@ +/* +@copyright Louis Dionne 2015 +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 +#include +#include +#include +#include +#include +#include +using namespace boost::hana; + + +template +auto key = test::ct_eq{}; + +template +auto val = test::ct_eq<-i>{}; + +template +auto p = test::minimal_product(key, val); + +struct undefined { }; + +int main() { + auto list = test::seq; (void)list; + auto foldable = test::seq; (void)foldable; + auto record = test::minimal_record; (void)record; + using L = test::Seq; + + auto eq_maps = make( + make(), + make(p<1, 1>), + make(p<1, 2>), + make(p<1, 1>, p<2, 2>), + make(p<1, 1>, p<2, 2>, p<3, 3>) + ); + (void)eq_maps; + + auto eq_keys = make(key<1>, key<4>); + (void)eq_keys; + +#if BOOST_HANA_TEST_PART == 1 + ////////////////////////////////////////////////////////////////////////// + // Make sure we do not instantiate rogue constructors when doing copies + ////////////////////////////////////////////////////////////////////////// + { + auto expr = make( + test::minimal_product(1, test::trap_construct{}) + ); + auto implicit_copy = expr; (void)implicit_copy; + decltype(expr) explicit_copy(expr); (void)explicit_copy; + } + + ////////////////////////////////////////////////////////////////////////// + // keys + ////////////////////////////////////////////////////////////////////////// + { + BOOST_HANA_CONSTANT_CHECK(equal( + keys(make()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + keys(make(p<1, 1>)), + list(key<1>) + )); + BOOST_HANA_CONSTANT_CHECK( + keys(make(p<1, 1>, p<2, 2>)) + ^in^ permutations(list(key<1>, key<2>)) + ); + BOOST_HANA_CONSTANT_CHECK( + keys(make(p<1, 1>, p<2, 2>, p<3, 3>)) + ^in^ permutations(list(key<1>, key<2>, key<3>)) + ); + } + + ////////////////////////////////////////////////////////////////////////// + // values + ////////////////////////////////////////////////////////////////////////// + { + BOOST_HANA_CONSTANT_CHECK(equal( + values(make()), + list() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + values(make(p<1, 1>)), + list(val<1>) + )); + BOOST_HANA_CONSTANT_CHECK( + values(make(p<1, 1>, p<2, 2>)) + ^in^ permutations(list(val<1>, val<2>)) + ); + BOOST_HANA_CONSTANT_CHECK( + values(make(p<1, 1>, p<2, 2>, p<3, 3>)) + ^in^ permutations(list(val<1>, val<2>, val<3>)) + ); + } + + ////////////////////////////////////////////////////////////////////////// + // insert + ////////////////////////////////////////////////////////////////////////// + { + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(), p<1, 1>), + make(p<1, 1>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>), p<1, 99>), + make(p<1, 1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>), p<2, 2>), + make(p<1, 1>, p<2, 2>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>), p<1, 99>), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>), p<2, 99>), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>), p<3, 3>), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>, p<3, 3>), p<1, 99>), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>, p<3, 3>), p<2, 99>), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>, p<3, 3>), p<3, 99>), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + insert(make(p<1, 1>, p<2, 2>, p<3, 3>), p<4, 4>), + make(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>) + )); + } + +#elif BOOST_HANA_TEST_PART == 2 + ////////////////////////////////////////////////////////////////////////// + // Conversions + ////////////////////////////////////////////////////////////////////////// + { + // Record -> Map + { + BOOST_HANA_CONSTANT_CHECK(equal( + to(record(test::ct_eq<1>{}, test::ct_eq<2>{})), + make( + make(test::member1, test::ct_eq<1>{}), + make(test::member2, test::ct_eq<2>{}) + ) + )); + } + + // Foldable -> Map + { + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable()), + make() + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>)), + make(p<1, 1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<2, 2>)), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<2, 2>, p<3, 3>)), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + + // with duplicates + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<1, 99>)), + make(p<1, 1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<2, 2>, p<1, 99>)), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<2, 2>, p<1, 99>, p<2, 99>)), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + to(foldable(p<1, 1>, p<2, 2>, p<1, 99>, p<2, 99>, p<3, 3>)), + make(p<1, 1>, p<2, 2>, p<3, 3>) + )); + } + + // Map -> Sequence + { + auto check = [=](auto ...xs) { + BOOST_HANA_CONSTANT_CHECK( + to(make(xs...)) ^in^ permutations(list(xs...)) + ); + }; + check(); + check(p<1, 1>); + check(p<1, 1>, p<2, 2>); + check(p<1, 1>, p<2, 2>, p<3, 3>); + check(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>); + } + } + +#elif BOOST_HANA_TEST_PART == 3 + ////////////////////////////////////////////////////////////////////////// + // Comparable + ////////////////////////////////////////////////////////////////////////// + { + // equal + { + BOOST_HANA_CONSTANT_CHECK(equal( + make(), + make() + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>), + make()) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(), + make(p<1, 1>) + ))); + + BOOST_HANA_CONSTANT_CHECK(equal( + make(p<1, 1>), + make(p<1, 1>) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>), + make(p<1, 2>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>), + make(p<2, 1>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>), + make(p<1, 1>, p<2, 2>)) + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + make(p<1, 1>, p<2, 2>), + make(p<1, 1>, p<2, 2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + make(p<1, 1>, p<2, 2>), + make(p<2, 2>, p<1, 1>) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>, p<2, 2>), + make(p<9, 1>, p<2, 2>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>, p<2, 2>), + make(p<1, 9>, p<2, 2>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>, p<2, 2>), + make(p<1, 1>, p<9, 2>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>, p<2, 2>), + make(p<1, 1>, p<2, 9>)) + )); + BOOST_HANA_CONSTANT_CHECK(not_(equal( + make(p<1, 1>, p<2, 2>), + make(p<1, 1>, p<2, 2>, p<3, 3>)) + )); + } + + // laws + test::TestComparable{eq_maps}; + } + +#elif BOOST_HANA_TEST_PART == 4 + ////////////////////////////////////////////////////////////////////////// + // Searchable + ////////////////////////////////////////////////////////////////////////// + { + // any_of + { + BOOST_HANA_CONSTANT_CHECK( + not_(any_of(make(), equal.to(key<1>))) + ); + + BOOST_HANA_CONSTANT_CHECK( + any_of(make(p<1, 1>), equal.to(key<1>)) + ); + BOOST_HANA_CONSTANT_CHECK( + not_(any_of(make(p<1, 1>), equal.to(key<2>))) + ); + + BOOST_HANA_CONSTANT_CHECK( + any_of(make(p<1, 1>, p<2, 2>), equal.to(key<1>)) + ); + BOOST_HANA_CONSTANT_CHECK( + any_of(make(p<1, 1>, p<2, 2>), equal.to(key<2>)) + ); + BOOST_HANA_CONSTANT_CHECK( + not_(any_of(make(p<1, 1>, p<2, 2>), equal.to(key<3>))) + ); + } + + // find_if + { + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(), equal.to(key<1>)), + nothing + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(p<1, 1>), equal.to(key<1>)), + just(val<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(p<1, 1>), equal.to(key<2>)), + nothing + )); + + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(p<1, 1>, p<2, 2>), equal.to(key<1>)), + just(val<1>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(p<1, 1>, p<2, 2>), equal.to(key<2>)), + just(val<2>) + )); + BOOST_HANA_CONSTANT_CHECK(equal( + find_if(make(p<1, 1>, p<2, 2>), equal.to(key<3>)), + nothing + )); + } + + // laws + test::TestSearchable{eq_maps, eq_keys}; + } + +#elif BOOST_HANA_TEST_PART == 5 + ////////////////////////////////////////////////////////////////////////// + // Foldable + ////////////////////////////////////////////////////////////////////////// + { + // fold.left + { + test::_injection<0> f{}; + test::ct_eq<999> state{}; + + auto check = [=](auto ...pairs) { + BOOST_HANA_CONSTANT_CHECK( + fold.left(make(pairs...), state, f) + ^in^ + transform(permutations(list(pairs...)), [=](auto xs) { + return fold.left(xs, state, f); + }) + ); + }; + + BOOST_HANA_CONSTANT_CHECK(equal( + fold.left(make(), state, undefined{}), + state + )); + + check(p<1, 1>); + check(p<1, 1>, p<2, 2>); + check(p<1, 1>, p<2, 2>, p<3, 3>); + check(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>); + } + + // fold.right + { + test::_injection<0> f{}; + test::ct_eq<999> state{}; + + auto check = [=](auto ...pairs) { + BOOST_HANA_CONSTANT_CHECK( + fold.right(make(pairs...), state, f) + ^in^ + transform(permutations(list(pairs...)), [=](auto xs) { + return fold.right(xs, state, f); + }) + ); + }; + + BOOST_HANA_CONSTANT_CHECK(equal( + fold.right(make(), state, undefined{}), + state + )); + + check(p<1, 1>); + check(p<1, 1>, p<2, 2>); + check(p<1, 1>, p<2, 2>, p<3, 3>); + check(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>); + } + + // unpack + { + test::_injection<0> f{}; + + auto check = [=](auto ...pairs) { + BOOST_HANA_CONSTANT_CHECK( + unpack(make(pairs...), f) + ^in^ + transform(permutations(list(pairs...)), [=](auto xs) { + return unpack(xs, f); + }) + ); + }; + + check(); + check(p<1, 1>); + check(p<1, 1>, p<2, 2>); + check(p<1, 1>, p<2, 2>, p<3, 3>); + check(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>); + } + + // laws + test::TestFoldable{eq_maps}; + } +#endif +} diff --git a/test/map/comparable.cpp b/test/map/comparable.cpp deleted file mode 100644 index 87c339c35..000000000 --- a/test/map/comparable.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -@copyright Louis Dionne 2015 -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; - - -template -auto key = test::ct_eq{}; - -template -auto val = test::ct_eq<-i>{}; - -template -auto p = test::minimal_product(key, val); - - -int main() { - auto eq_maps = make( - make(), - make(p<1, 1>), - make(p<1, 2>), - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<2, 2>, p<3, 3>) - ); - - ////////////////////////////////////////////////////////////////////////// - // Comparable - ////////////////////////////////////////////////////////////////////////// - { - // equal - { - BOOST_HANA_CONSTANT_CHECK(equal( - make(), - make() - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>), - make()) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(), - make(p<1, 1>) - ))); - - BOOST_HANA_CONSTANT_CHECK(equal( - make(p<1, 1>), - make(p<1, 1>) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>), - make(p<1, 2>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>), - make(p<2, 1>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>), - make(p<1, 1>, p<2, 2>)) - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<2, 2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - make(p<1, 1>, p<2, 2>), - make(p<2, 2>, p<1, 1>) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>, p<2, 2>), - make(p<9, 1>, p<2, 2>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>, p<2, 2>), - make(p<1, 9>, p<2, 2>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<9, 2>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<2, 9>)) - )); - BOOST_HANA_CONSTANT_CHECK(not_(equal( - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<2, 2>, p<3, 3>)) - )); - } - - // laws - test::TestComparable{eq_maps}; - } -} diff --git a/test/map/map.cpp b/test/map/map.cpp deleted file mode 100644 index 3aa414c47..000000000 --- a/test/map/map.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* -@copyright Louis Dionne 2015 -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 -#include -#include -#include -using namespace boost::hana; - - -template -auto key = test::ct_eq{}; - -template -auto val = test::ct_eq<-i>{}; - -template -auto p = test::minimal_product(key, val); - - -int main() { - ////////////////////////////////////////////////////////////////////////// - // Map interface - ////////////////////////////////////////////////////////////////////////// - { - auto list = test::seq; - auto foldable = test::seq; - auto record = test::minimal_record; - using L = test::Seq; - - // Make sure we do not instantiate rogue constructors when doing copies - { - auto expr = make( - test::minimal_product(1, test::trap_construct{}) - ); - auto implicit_copy = expr; (void)implicit_copy; - decltype(expr) explicit_copy(expr); (void)explicit_copy; - } - - // keys - { - BOOST_HANA_CONSTANT_CHECK(equal( - keys(make()), - list() - )); - BOOST_HANA_CONSTANT_CHECK(equal( - keys(make(p<1, 1>)), - list(key<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - keys(make(p<1, 1>, p<2, 2>)), - list(key<1>, key<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - keys(make(p<1, 1>, p<2, 2>, p<3, 3>)), - list(key<1>, key<2>, key<3>) - )); - } - - // values - { - BOOST_HANA_CONSTANT_CHECK(equal( - values(make()), - list() - )); - BOOST_HANA_CONSTANT_CHECK(equal( - values(make(p<1, 1>)), - list(val<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - values(make(p<1, 1>, p<2, 2>)), - list(val<1>, val<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - values(make(p<1, 1>, p<2, 2>, p<3, 3>)), - list(val<1>, val<2>, val<3>) - )); - } - - // Conversions - { - // Record -> Map - { - BOOST_HANA_CONSTANT_CHECK(equal( - to(record(test::ct_eq<1>{}, test::ct_eq<2>{})), - make( - make(test::member1, test::ct_eq<1>{}), - make(test::member2, test::ct_eq<2>{}) - ) - )); - } - - // Foldable -> Map - { - BOOST_HANA_CONSTANT_CHECK(equal( - to(foldable()), - make() - )); - BOOST_HANA_CONSTANT_CHECK(equal( - to(foldable(p<1, 1>)), - make(p<1, 1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - to(foldable(p<1, 1>, p<2, 2>)), - make(p<1, 1>, p<2, 2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - to(foldable(p<1, 1>, p<2, 2>, p<3, 3>)), - make(p<1, 1>, p<2, 2>, p<3, 3>) - )); - } - - // Map -> Sequence - { - BOOST_HANA_CONSTEXPR_LAMBDA auto check = [=](auto ...xs) { - BOOST_HANA_CONSTANT_CHECK( - elem(permutations(list(xs...)), to(make(xs...))) - ); - }; - check(); - check(p<1, 1>); - check(p<1, 1>, p<2, 2>); - check(p<1, 1>, p<2, 2>, p<3, 3>); - check(p<1, 1>, p<2, 2>, p<3, 3>, p<4, 4>); - } - } - } -} diff --git a/test/map/searchable.cpp b/test/map/searchable.cpp deleted file mode 100644 index ae675006a..000000000 --- a/test/map/searchable.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -@copyright Louis Dionne 2015 -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 -#include -#include -using namespace boost::hana; - - -template -auto key = test::ct_eq{}; - -template -auto val = test::ct_eq<-i>{}; - -template -auto p = test::minimal_product(key, val); - - -int main() { - auto eq_maps = make( - make(), - make(p<1, 1>), - make(p<1, 2>), - make(p<1, 1>, p<2, 2>), - make(p<1, 1>, p<2, 2>, p<3, 3>) - ); - - auto eq_keys = make(key<1>, key<4>); - - ////////////////////////////////////////////////////////////////////////// - // Searchable - ////////////////////////////////////////////////////////////////////////// - { - // any_of - { - BOOST_HANA_CONSTANT_CHECK( - not_(any_of(make(), equal.to(key<1>))) - ); - - BOOST_HANA_CONSTANT_CHECK( - any_of(make(p<1, 1>), equal.to(key<1>)) - ); - BOOST_HANA_CONSTANT_CHECK( - not_(any_of(make(p<1, 1>), equal.to(key<2>))) - ); - - BOOST_HANA_CONSTANT_CHECK( - any_of(make(p<1, 1>, p<2, 2>), equal.to(key<1>)) - ); - BOOST_HANA_CONSTANT_CHECK( - any_of(make(p<1, 1>, p<2, 2>), equal.to(key<2>)) - ); - BOOST_HANA_CONSTANT_CHECK( - not_(any_of(make(p<1, 1>, p<2, 2>), equal.to(key<3>))) - ); - } - - // find_if - { - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(), equal.to(key<1>)), - nothing - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(p<1, 1>), equal.to(key<1>)), - just(val<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(p<1, 1>), equal.to(key<2>)), - nothing - )); - - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(p<1, 1>, p<2, 2>), equal.to(key<1>)), - just(val<1>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(p<1, 1>, p<2, 2>), equal.to(key<2>)), - just(val<2>) - )); - BOOST_HANA_CONSTANT_CHECK(equal( - find_if(make(p<1, 1>, p<2, 2>), equal.to(key<3>)), - nothing - )); - } - - // laws - test::TestSearchable{eq_maps, eq_keys}; - } -}