Skip to content

Commit 18edc85

Browse files
committed
fix containers
1 parent b8c75ed commit 18edc85

2 files changed

Lines changed: 67 additions & 14 deletions

File tree

include/magic_enum/magic_enum_containers.hpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ namespace impl {
120120
template <typename Cmp = std::less<>, typename ForwardIt, typename E>
121121
constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) {
122122
auto count = std::distance(first, last);
123-
for (auto it = first; count > 0;) {
123+
while (count > 0) {
124+
auto it = first;
124125
auto step = count / 2;
125126
std::advance(it, step);
126127
if (comp(*it, e)) {
@@ -235,27 +236,33 @@ struct name_sort_impl<void, Cmp> {
235236
[[nodiscard]] constexpr bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare<C>(s1, s2); }
236237
};
237238

239+
template <typename T>
240+
using cmp_arg_t = std::conditional_t<std::is_enum_v<std::decay_t<T>> || std::is_constructible_v<string_view, T>, string_view, T>;
241+
242+
template <typename T>
243+
[[nodiscard]] static constexpr decltype(auto) cmp_arg(T&& value) noexcept {
244+
using D = std::decay_t<T>;
245+
if constexpr (std::is_enum_v<D>) {
246+
return enum_name(value);
247+
} else if constexpr (std::is_constructible_v<string_view, T>) {
248+
return string_view{std::forward<T>(value)};
249+
} else {
250+
return std::forward<T>(value);
251+
}
252+
}
253+
238254
template <typename E1, typename E2>
239255
[[nodiscard]] constexpr std::enable_if_t<
240256
// at least one of need to be an enum type
241257
(std::is_enum_v<std::decay_t<E1>> || std::is_enum_v<std::decay_t<E2>>) &&
242258
// if both is enum, only accept if the same enum
243259
(!std::is_enum_v<std::decay_t<E1>> || !std::is_enum_v<std::decay_t<E2>> || std::is_same_v<E1, E2>) &&
244260
// is invocable with comparator
245-
(std::is_invocable_r_v<bool, FullCmp<>, std::conditional_t<std::is_enum_v<std::decay_t<E1>>, string_view, E1>, std::conditional_t<std::is_enum_v<std::decay_t<E2>>, string_view, E2>>),
261+
(std::is_invocable_r_v<bool, FullCmp<>, cmp_arg_t<E1>, cmp_arg_t<E2>>),
246262
bool>
247263
operator()(E1 e1, E2 e2) const noexcept {
248-
using D1 = std::decay_t<E1>;
249-
using D2 = std::decay_t<E2>;
250264
constexpr FullCmp<> cmp{};
251-
252-
if constexpr (std::is_enum_v<D1> && std::is_enum_v<D2>) {
253-
return cmp(enum_name(e1), enum_name(e2));
254-
} else if constexpr (std::is_enum_v<D1>) {
255-
return cmp(enum_name(e1), e2);
256-
} else /* if constexpr (std::is_enum_v<D2>) */ {
257-
return cmp(e1, enum_name(e2));
258-
}
265+
return cmp(cmp_arg(e1), cmp_arg(e2));
259266
}
260267
};
261268

@@ -675,7 +682,7 @@ class bitset {
675682
[[nodiscard]] static constexpr iterator_impl end(parent_t p) noexcept {
676683
return iterator_impl(p, enum_count<E>());
677684
}
678-
685+
679686
public:
680687
[[nodiscard]] constexpr reference operator*() const noexcept { return *Index::it(num_index * bits_per_base + static_cast<std::size_t>(detail::countr_zero(bit_index))); }
681688

@@ -774,7 +781,7 @@ class bitset {
774781
}
775782

776783
constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{0}, char_type zero = static_cast<char_type>('0'), char_type one = static_cast<char_type>('1'))
777-
: bitset(string_view{str, (std::min)(std::char_traits<char_type>::length(str), n)}, 0, n, zero, one) {}
784+
: bitset(detail::raw_access_t{}, string_view{str, (std::min)(std::char_traits<char_type>::length(str), n)}, 0, n, zero, one) {}
778785

779786
constexpr bitset(std::initializer_list<E> starters) : a{{}} {
780787
if constexpr (magic_enum::detail::subtype_v<E> == magic_enum::detail::enum_subtype::flags) {

test/test_containers.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ TEST_CASE("containers_bitset") {
252252
REQUIRE_FALSE(color_bitset_red_green.all());
253253
REQUIRE(color_bitset_red_green.any());
254254
REQUIRE_FALSE(color_bitset_red_green.none());
255+
256+
constexpr magic_enum::containers::bitset<Color> color_bitset_raw_string {magic_enum::containers::raw_access, "101"};
257+
REQUIRE(color_bitset_raw_string.to_string( {}, '0', '1' ) == "101");
258+
REQUIRE(color_bitset_raw_string.to_ulong( {} ) == 5);
259+
REQUIRE(color_bitset_raw_string.test(Color::RED));
260+
REQUIRE_FALSE(color_bitset_raw_string.test(Color::GREEN));
261+
REQUIRE(color_bitset_raw_string.test(Color::BLUE));
255262
}
256263

257264
TEST_CASE("containers_bitset_hash") {
@@ -347,6 +354,45 @@ TEST_CASE("containers_set") {
347354
REQUIRE(color_set_assign.contains(Color::GREEN));
348355
REQUIRE_FALSE(color_set_assign.contains(Color::RED));
349356
REQUIRE_FALSE(color_set_assign.contains(Color::BLUE));
357+
358+
magic_enum::containers::set<Color, magic_enum::containers::name_less<>> color_name_set {Color::RED, Color::GREEN, Color::BLUE};
359+
constexpr magic_enum::string_view green_name = "GREEN";
360+
constexpr magic_enum::string_view blue_name = "BLUE";
361+
constexpr magic_enum::string_view purple_name = "PURPLE";
362+
const std::string blue_name_string = "BLUE";
363+
REQUIRE(color_name_set.contains(green_name));
364+
REQUIRE(color_name_set.contains(blue_name_string));
365+
REQUIRE(color_name_set.count(purple_name) == 0);
366+
REQUIRE(color_name_set.key_comp()(Color::BLUE, "GREEN"));
367+
REQUIRE(color_name_set.key_comp()("GREEN", Color::RED));
368+
REQUIRE_FALSE(color_name_set.key_comp()("GREEN", Color::BLUE));
369+
auto blue_by_literal = color_name_set.find("BLUE");
370+
REQUIRE(blue_by_literal != color_name_set.end());
371+
REQUIRE(*blue_by_literal == Color::BLUE);
372+
auto blue_by_string_view = color_name_set.find(blue_name);
373+
REQUIRE(blue_by_string_view != color_name_set.end());
374+
REQUIRE(*blue_by_string_view == Color::BLUE);
375+
auto blue_by_string = color_name_set.find(blue_name_string);
376+
REQUIRE(blue_by_string != color_name_set.end());
377+
REQUIRE(*blue_by_string == Color::BLUE);
378+
REQUIRE(color_name_set.erase("GREEN") == 1);
379+
REQUIRE_FALSE(color_name_set.contains(Color::GREEN));
380+
381+
magic_enum::containers::set<Color, magic_enum::containers::name_less_case_insensitive> color_ci_name_set {Color::RED, Color::GREEN, Color::BLUE};
382+
constexpr magic_enum::string_view green_name_lower = "green";
383+
constexpr magic_enum::string_view blue_name_lower = "blue";
384+
const std::string blue_name_lower_string = "blue";
385+
REQUIRE(color_ci_name_set.contains(green_name_lower));
386+
REQUIRE(color_ci_name_set.contains(blue_name_lower_string));
387+
auto blue_ci_by_literal = color_ci_name_set.find("blue");
388+
REQUIRE(blue_ci_by_literal != color_ci_name_set.end());
389+
REQUIRE(*blue_ci_by_literal == Color::BLUE);
390+
auto blue_ci_by_string_view = color_ci_name_set.find(blue_name_lower);
391+
REQUIRE(blue_ci_by_string_view != color_ci_name_set.end());
392+
REQUIRE(*blue_ci_by_string_view == Color::BLUE);
393+
auto blue_ci_by_string = color_ci_name_set.find(blue_name_lower_string);
394+
REQUIRE(blue_ci_by_string != color_ci_name_set.end());
395+
REQUIRE(*blue_ci_by_string == Color::BLUE);
350396
}
351397

352398
TEST_CASE("map_like_container") {

0 commit comments

Comments
 (0)