diff --git a/include/frozen/bits/basic_types.h b/include/frozen/bits/basic_types.h index 14490f8..674f6e6 100644 --- a/include/frozen/bits/basic_types.h +++ b/include/frozen/bits/basic_types.h @@ -68,6 +68,19 @@ struct size_integer { template using size_integer_t = typename size_integer::type; +// Helper type to work around apparent compiler bugs in MSVC related to having "too complex" +// template parameters involving either NTTP or references-to-array. +template +struct array_ref { + using array_type = const T(&) [N]; + using pointer = T*; + + pointer array; + + operator pointer () const noexcept { return array; } + operator array_type() const noexcept { return array; } +}; + template class cvector { public: diff --git a/include/frozen/bits/pic_array.h b/include/frozen/bits/pic_array.h index 8451754..97fb5e4 100644 --- a/include/frozen/bits/pic_array.h +++ b/include/frozen/bits/pic_array.h @@ -525,23 +525,23 @@ struct pic_array { // Helpers to preserve arrays in type information, instead of letting them decay to pointers template -constexpr std::pair kv_pair(T (& key)[TN], U (& val)[UN]) { - return {key, val}; +constexpr auto kv_pair(T (& key)[TN], U (& val)[UN]) { + return std::pair, bits::array_ref>{{key}, {val}}; } template -constexpr std::pair kv_pair(T (& key)[N], U val) { - return {key, val}; +constexpr auto kv_pair(T (& key)[N], U val) { + return std::pair, U>{{key}, {val}}; } template -constexpr std::pair kv_pair(T key, U (& val)[N]) { - return {key, val}; +constexpr auto kv_pair(T key, U (& val)[N]) { + return std::pair>{{key}, {val}}; } template -constexpr std::pair kv_pair(T key, U val) { - return {key, val}; +constexpr auto kv_pair(T key, U val) { + return std::pair{{key}, {val}}; } } // namespace frozen diff --git a/include/frozen/map.h b/include/frozen/map.h index abb6349..ad0a425 100644 --- a/include/frozen/map.h +++ b/include/frozen/map.h @@ -361,55 +361,108 @@ constexpr auto make_map(std::array, N> const &items, Compare con return map{items, compare}; } -template ::value>* = nullptr> +template < + typename T + , typename U + , typename Compare + , std::enable_if_t< + !bits::is_pair::value + , std::size_t>... KNs + > constexpr auto make_map( Compare const& compare, std::pair< - bits::element_t const (&)[KNs] + bits::array_ref, KNs> , U> const&... items) { constexpr const auto key_storage_size = bits::accumulate({KNs...}); using container_type = bits::pic_array, sizeof...(KNs), key_storage_size>; - return map{container_type{items...}, compare}; + using value_type = typename container_type::value_type; + return map{ + container_type{value_type(T(items.first.array), U(items.second))...}, + compare, + }; } -template -constexpr auto make_map(std::pair const (&)[KNs], U> const&... items) { +template < + typename T + , typename U + , std::size_t... KNs + > +constexpr auto make_map( + std::pair< + bits::array_ref, KNs> + , U> const&... items) { return make_map(std::less{}, items...); } -template ::value>* = nullptr> +template < + typename T + , typename U + , typename Compare + , std::enable_if_t< + !bits::is_pair::value + , std::size_t>... VNs + > constexpr auto make_map( Compare const& compare, std::pair< T - , bits::element_t const (&)[VNs]> const&... items) { + , bits::array_ref, VNs>> const&... items) { constexpr const auto key_storage_size = bits::accumulate({VNs...}); using container_type = bits::pic_array, sizeof...(VNs), key_storage_size>; - return map{container_type{items...}, compare}; + using value_type = typename container_type::value_type; + return map{ + container_type{value_type(T(items.first), U(items.second.array))...}, + compare, + }; } -template -constexpr auto make_map(std::pair const (&)[KNs]> const&... items) { +template < + typename T + , typename U + , std::size_t... KNs + > +constexpr auto make_map( + std::pair< + T + , bits::array_ref, KNs>> const&... items) { return make_map(std::less{}, items...); } -template ::value>* = nullptr> +template < + typename T + , typename U + , typename Compare + , std::size_t... KNs + , std::enable_if_t< + !bits::is_pair::value + , std::size_t>... VNs + > constexpr auto make_map( Compare const& compare, std::pair< - bits::element_t const (&)[KNs] - , bits::element_t const (&)[VNs]> const&... items) { + bits::array_ref, KNs> + , bits::array_ref, VNs>> const&... items) { constexpr const auto key_storage_size = bits::accumulate({KNs...}); constexpr const auto val_storage_size = bits::accumulate({VNs...}); using container_type = bits::pic_array, sizeof...(KNs), key_storage_size + val_storage_size>; - return map{container_type{items...}, compare}; + using value_type = typename container_type::value_type; + return map{ + container_type{value_type(T(items.first.array), U(items.second.array))...}, + compare, + }; } -template -constexpr auto make_map(std::pair const (&)[KNs], bits::element_t const (&)[VNs]> const&... items) { +template < + typename T + , typename U + , std::size_t... KNs + , std::size_t... VNs + > +constexpr auto make_map( + std::pair< + bits::array_ref, KNs> + , bits::array_ref, VNs>> const&... items) { return make_map(std::less{}, items...); } diff --git a/include/frozen/unordered_map.h b/include/frozen/unordered_map.h index 4bf7e19..5591307 100644 --- a/include/frozen/unordered_map.h +++ b/include/frozen/unordered_map.h @@ -251,77 +251,145 @@ constexpr auto make_unordered_map( return unordered_map{items, hash, equal}; } -template >::value - && !bits::is_pair::value - && !bits::is_pair::value>* = nullptr> +template < + typename T + , typename U + , typename Hasher + , typename Equal + , typename ElemT + , std::enable_if_t< + !bits::has_type>::value + && !bits::is_pair::value + && !bits::is_pair::value + && std::is_same>::value + , std::size_t>... KNs + > constexpr auto make_unordered_map( Hasher const &hash, Equal const &equal, std::pair< - bits::element_t const (&)[KNs] + bits::array_ref , U> const&... items) { constexpr const auto key_storage_size = bits::accumulate({KNs...}); using container_type = bits::pic_array, sizeof...(KNs), key_storage_size>; - return unordered_map{container_type{items...}, hash, equal}; + using value_type = typename container_type::value_type; + return unordered_map{ + container_type{value_type(T(items.first.array), U(items.second))...}, + hash, + equal, + }; } -template >::value>* = nullptr> +template < + typename T + , typename U + , typename ElemT + , std::enable_if_t< + !bits::has_type>::value + && std::is_same>::value + , std::size_t>... KNs + > constexpr auto make_unordered_map( std::pair< - bits::element_t const (&)[KNs] + bits::array_ref , U> const&... items) { return make_unordered_map(anna{}, std::equal_to{}, items...); } -template >::value - && !bits::is_pair::value - && !bits::is_pair::value>* = nullptr> +template < + typename T + , typename U + , typename Hasher + , typename Equal + , typename ElemT + , std::enable_if_t< + !bits::has_type>::value + && !bits::is_pair::value + && !bits::is_pair::value + && std::is_same>::value + , std::size_t>... VNs + > constexpr auto make_unordered_map( Hasher const &hash, Equal const &equal, std::pair< T - , bits::element_t const (&)[VNs] + , bits::array_ref > const&... items) { constexpr const auto val_storage_size = bits::accumulate({VNs...}); using container_type = bits::pic_array, sizeof...(VNs), val_storage_size>; - return unordered_map{container_type{items...}, hash, equal}; + using value_type = typename container_type::value_type; + return unordered_map{ + container_type{value_type(T(items.first), U(items.second.array))...}, + hash, + equal, + }; } -template >::value>* = nullptr> +template < + typename T + , typename U + , typename ElemT + , std::enable_if_t< + !bits::has_type>::value + && std::is_same>::value + , std::size_t>... VNs + > constexpr auto make_unordered_map( std::pair< T - , bits::element_t const (&)[VNs] + , bits::array_ref > const&... items) { return make_unordered_map(anna{}, std::equal_to{}, items...); } -template ::value && !bits::is_pair::value>* = nullptr> +template < + typename T + , typename U + , typename Hasher + , typename Equal + , typename ElemT + , typename ElemU + , std::size_t... KNs + , std::enable_if_t< + !bits::is_pair::value + && !bits::is_pair::value + && std::is_same>::value + && std::is_same>::value + , std::size_t>... VNs + > constexpr auto make_unordered_map( Hasher const &hash, Equal const &equal, std::pair< - bits::element_t const (&)[KNs] - , bits::element_t const (&)[VNs] + bits::array_ref + , bits::array_ref > const&... items) { constexpr const auto key_storage_size = bits::accumulate({KNs...}); constexpr const auto val_storage_size = bits::accumulate({VNs...}); using container_type = bits::pic_array, sizeof...(KNs), key_storage_size + val_storage_size>; - return unordered_map{container_type{items...}, hash, equal}; + using value_type = typename container_type::value_type; + return unordered_map{ + container_type{value_type(T(items.first.array), U(items.second.array))...}, + hash, + equal, + }; } -template +template < + typename T + , typename U + , typename ElemT + , typename ElemU + , std::size_t... KNs + , std::enable_if_t< + std::is_same>::value + && std::is_same>::value + , std::size_t>... VNs + > constexpr auto make_unordered_map(std::pair< - bits::element_t const (&)[KNs] - , bits::element_t const (&)[VNs] + bits::array_ref + , bits::array_ref > const&... items) { return make_unordered_map(anna{}, std::equal_to{}, items...); } diff --git a/tests/test_map.cpp b/tests/test_map.cpp index 566a8eb..4d353e7 100644 --- a/tests/test_map.cpp +++ b/tests/test_map.cpp @@ -499,3 +499,23 @@ TEST_CASE("frozen::map <> frozen::make_map transparent", "[map]") { REQUIRE(frozen_empty_map3.begin() == frozen_empty_map3.end()); } } + +TEST_CASE("frozen::make_map variations with frozen::string", "[map]") { + using frozen::kv_pair; + + constexpr auto si = frozen::make_map( + kv_pair("a", 1) + , kv_pair("b", 2) + ); + constexpr auto is = frozen::make_map( + kv_pair(1, "a") + , kv_pair(2, "b") + ); + constexpr auto ss = frozen::make_map( + kv_pair("1", "a") + , kv_pair("2", "b") + ); + + static_assert(is.at(si.at("a")) == "a", ""); + static_assert(ss.at("1") == "a", ""); +} diff --git a/tests/test_unordered_map_str.cpp b/tests/test_unordered_map_str.cpp index 35bb9db..29dd3fc 100644 --- a/tests/test_unordered_map_str.cpp +++ b/tests/test_unordered_map_str.cpp @@ -86,3 +86,23 @@ TEST_CASE("various frozen::unordered_map config", "[unordered_map]") { (void)olaf0; (void)olaf1; } + +TEST_CASE("frozen::make_unordered_map variations with frozen::string", "[unordered_map]") { + using frozen::kv_pair; + + constexpr auto si = frozen::make_unordered_map( + kv_pair("a", 1) + , kv_pair("b", 2) + ); + constexpr auto is = frozen::make_unordered_map( + kv_pair(1, "a") + , kv_pair(2, "b") + ); + constexpr auto ss = frozen::make_unordered_map( + kv_pair("1", "a") + , kv_pair("2", "b") + ); + + static_assert(is.at(si.at("a")) == "a", ""); + static_assert(ss.at("1") == "a", ""); +}