Skip to content

Commit 7fa1dbc

Browse files
authored
Merge pull request #205 from elbeno/smaller-env-types
🎨 Keep environment types as small as possible
2 parents 77c5ab7 + 4617804 commit 7fa1dbc

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

include/stdx/env.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ namespace stdx {
1212
inline namespace v1 {
1313
namespace _env {
1414
template <auto Query, auto Value> struct ct_prop {
15-
[[nodiscard]] CONSTEVAL static auto query(decltype(Query)) noexcept {
15+
using query_t = std::remove_cvref_t<decltype(Query)>;
16+
17+
[[nodiscard]] CONSTEVAL static auto query(query_t) noexcept {
1618
return Value;
1719
}
1820
};
@@ -61,6 +63,9 @@ template <std::size_t N> struct autowrap<str_lit_t<N>> {
6163
template <typename T> autowrap(T) -> autowrap<T>;
6264
template <std::size_t N> autowrap(str_lit_t<N>) -> autowrap<str_lit_t<N>>;
6365

66+
template <typename T, typename U>
67+
using queries_equal = std::is_same<typename T::query_t, typename U::query_t>;
68+
6469
template <typename> struct for_each_pair;
6570
template <std::size_t... Is> struct for_each_pair<std::index_sequence<Is...>> {
6671
template <auto... Args>
@@ -72,7 +77,8 @@ template <envlike Env = env<>>
7277
constexpr auto make_env = []<autowrap... Args> {
7378
using new_env_t = typename for_each_pair<
7479
std::make_index_sequence<sizeof...(Args) / 2>>::template type<Args...>;
75-
return boost::mp11::mp_append<new_env_t, Env>{};
80+
return boost::mp11::mp_unique_if<boost::mp11::mp_append<new_env_t, Env>,
81+
queries_equal>{};
7682
};
7783
} // namespace _env
7884

@@ -81,7 +87,9 @@ using extend_env_t =
8187
decltype(_env::make_env<Env>.template operator()<Args...>());
8288

8389
template <envlike... Envs>
84-
using append_env_t = boost::mp11::mp_reverse<boost::mp11::mp_append<Envs...>>;
90+
using append_env_t = boost::mp11::mp_unique_if<
91+
boost::mp11::mp_reverse<boost::mp11::mp_append<Envs...>>,
92+
_env::queries_equal>;
8593

8694
template <_env::autowrap... Args>
8795
using make_env_t = extend_env_t<env<>, Args...>;

test/env.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdx/ct_string.hpp>
22
#include <stdx/env.hpp>
33

4+
#include <boost/mp11/algorithm.hpp>
45
#include <catch2/catch_test_macros.hpp>
56

67
namespace {
@@ -50,3 +51,25 @@ TEST_CASE("envlike concept", "[env]") {
5051
static_assert(stdx::envlike<stdx::env<>>);
5152
static_assert(stdx::envlike<stdx::make_env_t<custom, 17>>);
5253
}
54+
55+
namespace {
56+
template <typename Q> struct match_query {
57+
template <typename T> using fn = std::is_same<Q, typename T::query_t>;
58+
};
59+
} // namespace
60+
61+
TEST_CASE("extending environment doesn't create duplicate keys", "[env]") {
62+
using E1 = stdx::make_env_t<custom, 17>;
63+
using E2 = stdx::extend_env_t<E1, custom, 18>;
64+
static_assert(
65+
boost::mp11::mp_count_if_q<E2, match_query<custom_t>>::value == 1);
66+
}
67+
68+
TEST_CASE("appending environment doesn't create duplicate keys", "[env]") {
69+
using E1 = stdx::make_env_t<custom, 17>;
70+
using E2 = stdx::make_env_t<custom, 18>;
71+
using E3 = stdx::make_env_t<custom, 19>;
72+
using E = stdx::append_env_t<E1, E2, E3>;
73+
static_assert(boost::mp11::mp_count_if_q<E, match_query<custom_t>>::value ==
74+
1);
75+
}

0 commit comments

Comments
 (0)