mirror of
https://github.com/Neargye/magic_enum.git
synced 2026-01-10 23:44:29 +00:00
* Remove MAGIC_ENUM_ENABLE_NONASCII
* Optimize template instantiations * Remove auto is_flags * Change flags API
This commit is contained in:
parent
737ed4fc7f
commit
427a47394f
27 changed files with 515 additions and 875 deletions
|
|
@ -19,7 +19,6 @@ else()
|
|||
set(IS_TOPLEVEL_PROJECT FALSE)
|
||||
endif()
|
||||
|
||||
option(MAGIC_ENUM_OPT_ENABLE_NONASCII "Enable support for non-ASCII enumeration identifier" OFF)
|
||||
option(MAGIC_ENUM_OPT_BUILD_EXAMPLES "Build magic_enum examples" ${IS_TOPLEVEL_PROJECT})
|
||||
option(MAGIC_ENUM_OPT_BUILD_TESTS "Build and perform magic_enum tests" ${IS_TOPLEVEL_PROJECT})
|
||||
option(MAGIC_ENUM_OPT_INSTALL "Generate and install magic_enum target" ${IS_TOPLEVEL_PROJECT})
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2022 Daniil Goncharov
|
||||
Copyright (c) 2019 - 2023 Daniil Goncharov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -61,12 +61,6 @@
|
|||
#define MAGIC_ENUM_RANGE_MAX 255
|
||||
```
|
||||
|
||||
* To add support for non-ASCII enumeration identifier, use special macros:
|
||||
```cpp
|
||||
#define MAGIC_ENUM_ENABLE_NONASCII
|
||||
#include <magic_enum.hpp>
|
||||
```
|
||||
|
||||
## `enum_cast`
|
||||
|
||||
```cpp
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ load("@magic_enum//bazel:copts.bzl", "COPTS")
|
|||
_EXAMPLES = [
|
||||
"enum_flag_example",
|
||||
"example",
|
||||
"example_containers_array",
|
||||
"example_containers_bitset",
|
||||
"example_containers_set",
|
||||
#"example_containers_array", TODO
|
||||
#"example_containers_bitset", TODO
|
||||
#"example_containers_set", TODO
|
||||
"example_custom_name",
|
||||
"example_switch",
|
||||
]
|
||||
|
|
@ -23,6 +23,5 @@ cc_binary(
|
|||
srcs = ["example_nonascii_name.cpp"],
|
||||
deps = ["@magic_enum"],
|
||||
copts = COPTS,
|
||||
defines = ["MAGIC_ENUM_ENABLE_NONASCII"],
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,12 +19,11 @@ endfunction()
|
|||
|
||||
make_example(example)
|
||||
make_example(enum_flag_example)
|
||||
make_example(example_containers_array)
|
||||
make_example(example_containers_bitset)
|
||||
make_example(example_containers_set)
|
||||
#make_example(example_containers_array) TODO
|
||||
#make_example(example_containers_bitset) TODO
|
||||
#make_example(example_containers_set) TODO
|
||||
make_example(example_custom_name)
|
||||
make_example(example_switch)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
set(OPTIONS ${OPTIONS} -DMAGIC_ENUM_ENABLE_NONASCII)
|
||||
make_example(example_nonascii_name)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2022 Uruha Komachin <uruhakomachin@gmail.com>.
|
||||
// Copyright (c) 2020 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2023 Uruha Komachin <uruhakomachin@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2022 Bela Schaum <schaumb@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,8 @@
|
|||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2023 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -39,13 +40,14 @@
|
|||
namespace magic_enum::containers {
|
||||
|
||||
namespace detail {
|
||||
template<typename T, typename = void>
|
||||
|
||||
template <typename T, typename = void>
|
||||
[[maybe_unused]] constexpr static bool is_transparent_v {};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
constexpr static bool is_transparent_v<T, std::void_t<typename T::is_transparent>> {true};
|
||||
|
||||
template<typename Eq = std::equal_to<>, typename T1, typename T2>
|
||||
template <typename Eq = std::equal_to<>, typename T1, typename T2>
|
||||
constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) {
|
||||
auto first1 = t1.begin();
|
||||
auto last1 = t1.end();
|
||||
|
|
@ -60,7 +62,7 @@ namespace detail {
|
|||
return first2 == last2;
|
||||
}
|
||||
|
||||
template<typename Cmp = std::less<>, typename T1, typename T2>
|
||||
template <typename Cmp = std::less<>, typename T1, typename T2>
|
||||
constexpr bool lexicographical_compare(T1&& t1, T2&& t2, Cmp&& cmp = {}) noexcept {
|
||||
auto first1 = t1.begin();
|
||||
auto last1 = t1.end();
|
||||
|
|
@ -75,7 +77,7 @@ namespace detail {
|
|||
return (first1 == last1) && (first2 != last2);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
template <typename T>
|
||||
constexpr std::size_t popcount( T x ) noexcept {
|
||||
std::size_t c = 0;
|
||||
while (x > 0) {
|
||||
|
|
@ -85,7 +87,7 @@ namespace detail {
|
|||
return c;
|
||||
}
|
||||
|
||||
template<typename Cmp = std::less<>, typename ForwardIt, typename E>
|
||||
template <typename Cmp = std::less<>, typename ForwardIt, typename E>
|
||||
constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) {
|
||||
auto count = std::distance(first, last);
|
||||
|
||||
|
|
@ -103,7 +105,7 @@ namespace detail {
|
|||
return first;
|
||||
}
|
||||
|
||||
template<typename Cmp = std::less<>, typename BidirIt, typename E>
|
||||
template <typename Cmp = std::less<>, typename BidirIt, typename E>
|
||||
constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) {
|
||||
const auto first = lower_bound(begin, end, e, comp);
|
||||
return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp] (auto&& lhs, auto&& rhs) {
|
||||
|
|
@ -111,7 +113,7 @@ namespace detail {
|
|||
}).base()};
|
||||
}
|
||||
|
||||
template<typename E = void, typename Cmp = std::less<E>, typename = void>
|
||||
template <typename E = void, typename Cmp = std::less<E>, typename = void>
|
||||
struct indexing {
|
||||
[[nodiscard]] constexpr static auto get_indices() noexcept {
|
||||
// reverse result index mapping
|
||||
|
|
@ -159,7 +161,7 @@ namespace detail {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename E, typename Less>
|
||||
template <typename E, typename Less>
|
||||
struct indexing<E, Less, std::enable_if_t<std::is_enum_v<std::decay_t<E>> &&
|
||||
(std::is_same_v<Less, std::less<E>> || std::is_same_v<Less, std::less<>>)>> {
|
||||
constexpr static inline const std::array<E, enum_count<E>()>* values_v = &enum_values<E>();
|
||||
|
|
@ -168,17 +170,17 @@ namespace detail {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename Less>
|
||||
template <typename Less>
|
||||
struct indexing<void, Less, void> {
|
||||
using is_transparent = std::true_type;
|
||||
template<typename E>
|
||||
template <typename E>
|
||||
[[nodiscard]] constexpr inline optional<std::size_t> operator()(E val) const noexcept {
|
||||
constexpr indexing<E, Less> ix{};
|
||||
return ix(val);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename E = void,
|
||||
template <typename E = void,
|
||||
typename OP = std::less<>,
|
||||
typename = void>
|
||||
struct name_sort_impl {
|
||||
|
|
@ -187,13 +189,13 @@ namespace detail {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename OP>
|
||||
template <typename OP>
|
||||
struct name_sort_impl<void, OP> {
|
||||
using is_transparent = std::true_type;
|
||||
template<typename S = OP, typename = void>
|
||||
template <typename S = OP, typename = void>
|
||||
struct FullCmp : S {};
|
||||
|
||||
template<typename S>
|
||||
template <typename S>
|
||||
struct FullCmp<S, std::enable_if_t<!std::is_invocable_v<S, string_view, string_view> &&
|
||||
std::is_invocable_v<S, char, char>>> {
|
||||
[[nodiscard]] constexpr inline bool operator()(string_view s1, string_view s2) const noexcept {
|
||||
|
|
@ -201,7 +203,7 @@ namespace detail {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename E1, typename E2>
|
||||
template <typename E1, typename E2>
|
||||
[[nodiscard]] constexpr inline std::enable_if_t<
|
||||
// at least one of need to be an enum type
|
||||
(std::is_enum_v<std::decay_t<E1>> || std::is_enum_v<std::decay_t<E2>>) &&
|
||||
|
|
@ -227,7 +229,7 @@ namespace detail {
|
|||
|
||||
struct raw_access_t {};
|
||||
|
||||
template<typename Parent, typename Iterator, typename Getter, typename Predicate>
|
||||
template <typename Parent, typename Iterator, typename Getter, typename Predicate>
|
||||
struct FilteredIterator {
|
||||
Parent parent;
|
||||
Iterator first;
|
||||
|
|
@ -248,7 +250,7 @@ namespace detail {
|
|||
constexpr FilteredIterator(FilteredIterator&&) noexcept = default;
|
||||
constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default;
|
||||
|
||||
template<typename OtherParent, typename OtherIterator, typename = std::enable_if_t<std::is_convertible_v<OtherParent, Parent> && std::is_convertible_v<OtherIterator, Iterator>>*>
|
||||
template <typename OtherParent, typename OtherIterator, typename = std::enable_if_t<std::is_convertible_v<OtherParent, Parent> && std::is_convertible_v<OtherIterator, Iterator>>*>
|
||||
constexpr explicit FilteredIterator(const FilteredIterator<OtherParent, OtherIterator, Getter, Predicate>& other)
|
||||
: parent(other.parent)
|
||||
, first(other.first)
|
||||
|
|
@ -317,25 +319,25 @@ namespace detail {
|
|||
};
|
||||
} // detail
|
||||
|
||||
template<typename E = void>
|
||||
template <typename E = void>
|
||||
using name_less [[maybe_unused]] = detail::name_sort_impl<E>;
|
||||
template<typename E = void>
|
||||
template <typename E = void>
|
||||
using name_greater [[maybe_unused]] = detail::name_sort_impl<E, std::greater<>>;
|
||||
|
||||
using name_less_ci [[maybe_unused]] = detail::name_sort_impl<void, magic_enum::detail::case_insensitive<std::less<>>>;
|
||||
using name_greater_ci [[maybe_unused]] = detail::name_sort_impl<void, magic_enum::detail::case_insensitive<std::greater<>>>;
|
||||
|
||||
template<typename E = void>
|
||||
template <typename E = void>
|
||||
using default_indexing = detail::indexing<E>;
|
||||
|
||||
template<typename Cmp = std::less<>>
|
||||
template <typename Cmp = std::less<>>
|
||||
using comparator_indexing [[maybe_unused]] = detail::indexing<void, Cmp>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ARRAY //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename E, typename V, typename Index = default_indexing<E>>
|
||||
template <typename E, typename V, typename Index = default_indexing<E>>
|
||||
struct array {
|
||||
static_assert(std::is_enum_v<E>);
|
||||
static_assert(std::is_trivially_constructible_v<Index>);
|
||||
|
|
@ -505,28 +507,28 @@ struct array {
|
|||
|
||||
namespace detail {
|
||||
|
||||
template <class E, class T, std::size_t N, std::size_t... I>
|
||||
template <typename E, typename T, std::size_t N, std::size_t... I>
|
||||
constexpr array<E, std::remove_cv_t<T>> to_array_impl(T (&a)[N], std::index_sequence<I...>) {
|
||||
return {{a[I]...}};
|
||||
}
|
||||
|
||||
template <class E, class T, std::size_t N, std::size_t... I>
|
||||
template <typename E, typename T, std::size_t N, std::size_t... I>
|
||||
constexpr array<E, std::remove_cv_t<T>> to_array_impl(T (&&a)[N], std::index_sequence<I...>) {
|
||||
return {{std::move(a[I])...}};
|
||||
}
|
||||
}
|
||||
|
||||
template<class E, class T, std::size_t N>
|
||||
template <typename E, typename T, std::size_t N>
|
||||
constexpr std::enable_if_t<(enum_count<E>() == N), array<E, std::remove_cv_t<T>>> to_array(T (&a)[N]) {
|
||||
return detail::to_array_impl<E>(a, std::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
template<class E, class T, std::size_t N>
|
||||
template <typename E, typename T, std::size_t N>
|
||||
constexpr std::enable_if_t<(enum_count<E>() == N), array<E, std::remove_cv_t<T>>> to_array(T (&&a)[N]) {
|
||||
return detail::to_array_impl<E>(std::move(a), std::make_index_sequence<N>{});
|
||||
}
|
||||
|
||||
template<class E, class ...Ts>
|
||||
template <typename E, typename ...Ts>
|
||||
constexpr std::enable_if_t<(enum_count<E>() == sizeof...(Ts)), array<E, std::remove_cv_t<std::common_type_t<Ts...>>>> make_array(Ts&& ... ts) {
|
||||
return {{std::forward<Ts>(ts)...}};
|
||||
}
|
||||
|
|
@ -537,7 +539,7 @@ inline constexpr detail::raw_access_t raw_access {};
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BITSET //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename E, typename Index = default_indexing<E>>
|
||||
template <typename E, typename Index = default_indexing<E>>
|
||||
class bitset {
|
||||
static_assert(std::is_enum_v<E>);
|
||||
static_assert(std::is_trivially_constructible_v<Index>);
|
||||
|
|
@ -552,7 +554,7 @@ class bitset {
|
|||
constexpr static std::size_t not_interested = base_type_count * bits_per_base - enum_count<E>();
|
||||
constexpr static base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1;
|
||||
|
||||
template<class parent_t = bitset*>
|
||||
template <typename parent_t = bitset*>
|
||||
class reference_impl {
|
||||
friend class bitset;
|
||||
|
||||
|
|
@ -602,7 +604,7 @@ class bitset {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T to_(detail::raw_access_t) const {
|
||||
T res{};
|
||||
T flag{1};
|
||||
|
|
@ -678,7 +680,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template<typename V = E>
|
||||
template <typename V = E>
|
||||
constexpr explicit bitset(std::enable_if_t<magic_enum::detail::is_flags_v<V>, E> starter) : a{{}} {
|
||||
auto u = enum_underlying(starter);
|
||||
for (E v : enum_values<E>()) {
|
||||
|
|
@ -692,7 +694,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Cmp = std::equal_to<>>
|
||||
template <typename Cmp = std::equal_to<>>
|
||||
constexpr explicit bitset(string_view sv,
|
||||
Cmp&& cmp = {},
|
||||
char sep = '|') {
|
||||
|
|
@ -867,7 +869,7 @@ public:
|
|||
return cp;
|
||||
}
|
||||
|
||||
template<typename V = E>
|
||||
template <typename V = E>
|
||||
[[nodiscard]] constexpr explicit operator std::enable_if_t<magic_enum::detail::is_flags_v<V>, E>() const {
|
||||
E res{};
|
||||
for (auto& e : enum_values<E>()) {
|
||||
|
|
@ -936,7 +938,7 @@ private:
|
|||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SET //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename E, typename CExprLess = std::less<E>>
|
||||
template <typename E, typename CExprLess = std::less<E>>
|
||||
class set {
|
||||
using index_type = detail::indexing<E, CExprLess>;
|
||||
struct Getter {
|
||||
|
|
@ -969,7 +971,7 @@ public:
|
|||
|
||||
constexpr set() noexcept = default;
|
||||
|
||||
template<typename InputIt>
|
||||
template <typename InputIt>
|
||||
constexpr set(InputIt first, InputIt last) {
|
||||
while (first != last) {
|
||||
insert(*first++);
|
||||
|
|
@ -982,7 +984,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template<typename V = E>
|
||||
template <typename V = E>
|
||||
constexpr explicit set(std::enable_if_t<magic_enum::detail::is_flags_v<V>, E> starter) {
|
||||
auto u = enum_underlying(starter);
|
||||
for (E v : enum_values<E>()) {
|
||||
|
|
@ -1084,7 +1086,7 @@ public:
|
|||
return insert(hint, value);
|
||||
}
|
||||
|
||||
template< class InputIt >
|
||||
template <typename InputIt>
|
||||
constexpr void insert(InputIt first, InputIt last) noexcept {
|
||||
while (first != last) {
|
||||
insert(*first++);
|
||||
|
|
@ -1097,12 +1099,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
template <typename... Args>
|
||||
constexpr std::pair<iterator,bool> emplace(Args&&... args) noexcept {
|
||||
return insert({std::forward<Args>(args)...});
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
template <typename... Args>
|
||||
constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept {
|
||||
return emplace(std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
|
@ -1127,7 +1129,7 @@ public:
|
|||
return res;
|
||||
}
|
||||
|
||||
template<class K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> erase(K&& x) noexcept {
|
||||
size_type c{};
|
||||
for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{});
|
||||
|
|
@ -1147,7 +1149,7 @@ public:
|
|||
return index_type{}(key) && a[key];
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> count(const K& x) const {
|
||||
size_type c{};
|
||||
for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); first != last; ++first) {
|
||||
|
|
@ -1164,7 +1166,7 @@ public:
|
|||
return end();
|
||||
}
|
||||
|
||||
template<class K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> find(const K& x) const {
|
||||
for (auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{}); first != last; ++first) {
|
||||
if (a.test(*first)) {
|
||||
|
|
@ -1178,7 +1180,7 @@ public:
|
|||
return count(key);
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, bool> contains(const K& x) const noexcept {
|
||||
return count(x) > 0;
|
||||
}
|
||||
|
|
@ -1187,7 +1189,7 @@ public:
|
|||
return {lower_bound(key), upper_bound(key)};
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, std::pair<const_iterator,const_iterator>> equal_range(const K& x) const noexcept {
|
||||
return {lower_bound(x), upper_bound(x)};
|
||||
}
|
||||
|
|
@ -1202,7 +1204,7 @@ public:
|
|||
return end();
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> lower_bound(const K& x) const noexcept {
|
||||
auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{});
|
||||
return first != last ? lower_bound(*first) : end();
|
||||
|
|
@ -1217,7 +1219,7 @@ public:
|
|||
return end();
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
template <typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> upper_bound(const K& x) const noexcept {
|
||||
auto [first, last] = detail::equal_range(index_type::values_v->begin(), index_type::values_v->end(), x, key_compare{});
|
||||
return first != last ? upper_bound(*std::prev(last)) : end();
|
||||
|
|
@ -1263,7 +1265,7 @@ public:
|
|||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename Pred>
|
||||
template <typename Pred>
|
||||
size_type erase_if(Pred pred) {
|
||||
auto old_size = size();
|
||||
for (auto i = begin(), last = end(); i != last; ) {
|
||||
|
|
@ -1282,429 +1284,54 @@ private:
|
|||
std::size_t s{};
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FLATSET //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename E, typename CExprLess = std::less<E>>
|
||||
class flat_set {
|
||||
using index_type = detail::indexing<E, CExprLess>;
|
||||
public:
|
||||
using container_type = std::array<E, enum_count<E>()>;
|
||||
using key_type = E;
|
||||
using value_type = E;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using key_compare = CExprLess;
|
||||
using value_compare = CExprLess;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using iterator = const E*;
|
||||
using const_iterator = const E*;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
constexpr flat_set() noexcept : a{}, s{} {}
|
||||
template<typename InputIterator>
|
||||
constexpr flat_set(InputIterator begin, InputIterator end) {
|
||||
insert(begin, end);
|
||||
}
|
||||
constexpr flat_set(std::initializer_list<value_type> il) {
|
||||
insert(il);
|
||||
}
|
||||
|
||||
constexpr flat_set(const flat_set &) = default;
|
||||
constexpr flat_set(flat_set&&) noexcept = default;
|
||||
constexpr flat_set & operator=(const flat_set &) = default;
|
||||
constexpr flat_set & operator=(flat_set &&) noexcept = default;
|
||||
constexpr flat_set & operator=(std::initializer_list< value_type > il) {
|
||||
return *this = flat_set{il};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator begin() const noexcept {
|
||||
return a.begin();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator end() const noexcept {
|
||||
return a.begin() + s;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept {
|
||||
return {end()};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reverse_iterator rend() const noexcept {
|
||||
return {begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator cbegin() const noexcept {
|
||||
return begin();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator cend() const noexcept {
|
||||
return end();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept {
|
||||
return rend();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool empty() const noexcept {
|
||||
return s == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_type size() const noexcept {
|
||||
return s;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_type max_size() const noexcept {
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_type capacity() const noexcept {
|
||||
return a.size();
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
constexpr std::pair< iterator, bool > emplace(Args &&... args) {
|
||||
return insert(value_type{std::forward<Args>(args)...});
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
constexpr iterator emplace_hint(const_iterator, Args &&... args) {
|
||||
return insert(value_type{std::forward<Args>(args)...}).first;
|
||||
}
|
||||
|
||||
constexpr std::pair< iterator, bool > insert(const value_type & v) {
|
||||
auto it = lower_bound(v);
|
||||
bool inserts = it == end() || *it != v;
|
||||
if (inserts) {
|
||||
auto nTh = it - begin();
|
||||
for (size_type cp = s; cp > static_cast<size_type>(nTh); --cp) {
|
||||
a[cp] = a[cp-1];
|
||||
}
|
||||
a[nTh] = v;
|
||||
++s;
|
||||
}
|
||||
return {it, inserts};
|
||||
}
|
||||
|
||||
constexpr std::pair< iterator, bool > insert(value_type&& v) {
|
||||
return insert(v);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
constexpr void insert(InputIterator begin, InputIterator end) {
|
||||
while(begin != end) {
|
||||
insert(*begin++);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void insert(std::initializer_list< value_type > il) {
|
||||
for (auto e : il) {
|
||||
insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename C2>
|
||||
constexpr void merge(flat_set<value_type, C2> & other) {
|
||||
for (auto e : other) {
|
||||
insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename C2>
|
||||
constexpr void merge(flat_set<value_type, C2> && other) {
|
||||
merge(other);
|
||||
}
|
||||
|
||||
constexpr size_type erase(const key_type & key) {
|
||||
auto it = lower_bound(key);
|
||||
bool erases = it != end() && *it == key;
|
||||
if (erases) {
|
||||
erase(it);
|
||||
}
|
||||
return erases;
|
||||
}
|
||||
constexpr iterator erase(const_iterator it) {
|
||||
if (it != end()) {
|
||||
for (size_type from = it - begin(); from < s-1; ++from) {
|
||||
a[from] = a[from+1];
|
||||
}
|
||||
|
||||
--s;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr iterator erase(const_iterator first, const_iterator last) {
|
||||
while ((first = erase(first)) != last) { ; }
|
||||
return first;
|
||||
}
|
||||
|
||||
constexpr void swap(flat_set & fs) noexcept {
|
||||
size_type until = (std::min)(s, fs.s);
|
||||
for (size_type i{}; i < until; ++i) {
|
||||
auto v = a[i];
|
||||
a[i] = fs.a[i];
|
||||
fs.a[i] = v;
|
||||
}
|
||||
for (size_type i = until; i < s; ++i) {
|
||||
fs.a[i] = a[i];
|
||||
}
|
||||
for (size_type i = until; i < fs.s; ++i) {
|
||||
a[i] = fs.a[i];
|
||||
}
|
||||
|
||||
until = s;
|
||||
s = fs.s;
|
||||
fs.s = until;
|
||||
}
|
||||
|
||||
constexpr void clear() noexcept {
|
||||
s = 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr key_compare key_comp() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_compare value_comp() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator find(const key_type & k) const {
|
||||
auto it = lower_bound(k);
|
||||
if (it != end() && *it != k) {
|
||||
it = end();
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template<class K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> find(const K& x) const {
|
||||
auto [first, last] = equal_range(x);
|
||||
return first != last ? first : end();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator nth(size_type n) const noexcept {
|
||||
return a.begin() + n;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_type index_of(const_iterator i) const noexcept {
|
||||
return i - begin();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_type count(const key_type & k) const {
|
||||
return find(k) != end();
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> count(const K& x) const {
|
||||
auto [first, last] = equal_range(x);
|
||||
return last - first;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool contains(const key_type & key) const {
|
||||
return count(key);
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, bool> contains(const K& x) const {
|
||||
auto [first, last] = equal_range(x);
|
||||
return last - first > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator lower_bound(const key_type & k) const {
|
||||
return detail::lower_bound(begin(), end(), k, key_compare{});
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> lower_bound(const K& x) const {
|
||||
return detail::lower_bound(begin(), end(), x, key_compare{});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_iterator upper_bound(const key_type & k) const {
|
||||
return equal_range(k).second;
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> upper_bound(const K& x) const {
|
||||
return equal_range(x).second;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::pair< const_iterator, const_iterator > equal_range(const key_type & k) const {
|
||||
return detail::equal_range(begin(), end(), k, key_compare{});
|
||||
}
|
||||
|
||||
template<typename K, typename KC = key_compare>
|
||||
[[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, std::pair< const_iterator, const_iterator >> equal_range(const K& x) const {
|
||||
return detail::equal_range(begin(), end(), x, key_compare{});
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator==(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
if (lhs.s != rhs.s) { return false; }
|
||||
for (size_type i{}; i < lhs.s; ++i) {
|
||||
if (lhs.a[i] != rhs.a[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator!=(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
return lhs.a != rhs.a;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator<(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
if (lhs.s < rhs.s) { return true; }
|
||||
if (rhs.s < lhs.s) { return false; }
|
||||
|
||||
for (auto& e : *index_type::values_v) {
|
||||
if (auto c = rhs.contains(e); c != lhs.contains(e)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator<=(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator>(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr friend bool operator>=(const flat_set& lhs, const flat_set& rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
constexpr friend void swap(flat_set & lhs, flat_set & rhs) noexcept {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template<typename Pred>
|
||||
size_type erase_if(Pred pred) {
|
||||
auto old_size = size();
|
||||
for (auto i = begin(), last = end(); i != last; ) {
|
||||
if (pred(*i)) {
|
||||
i = erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return old_size - size();
|
||||
}
|
||||
private:
|
||||
container_type a;
|
||||
std::size_t s;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
// multiset like API. (Probably delete can invalidate allocators?)
|
||||
template<typename E, typename CExprLess = std::less<E>>
|
||||
class multiset {
|
||||
using index_type = detail::indexing<E, CExprLess>;
|
||||
public:
|
||||
|
||||
//...
|
||||
|
||||
private:
|
||||
array<E, std::size_t, index_type> a;
|
||||
};
|
||||
|
||||
|
||||
// map like API.
|
||||
template<typename E, typename V, typename CExprLess = std::less<E>>
|
||||
class map {
|
||||
using index_type = detail::indexing<E, CExprLess>;
|
||||
public:
|
||||
|
||||
//...
|
||||
|
||||
private:
|
||||
array<E, optional<std::pair<const E, V>>, index_type> a;
|
||||
};
|
||||
|
||||
|
||||
// flat_map (map) like API with contiguous iterator --> can be memcpy'd if V is trivially_copyable.
|
||||
template<typename E, typename V, typename CExprLess = std::less<E>>
|
||||
class flat_map {
|
||||
public:
|
||||
|
||||
//...
|
||||
|
||||
private:
|
||||
union ValueType {
|
||||
std::uint8_t uninitialized = {};
|
||||
std::pair<const E, V> value;
|
||||
};
|
||||
array<E, ValueType> a;
|
||||
std::size_t s;
|
||||
};
|
||||
*/
|
||||
|
||||
}// namespace magic_enum::containers
|
||||
|
||||
namespace std {
|
||||
template< auto I, typename E, typename V, typename Index>
|
||||
template <auto I, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
|
||||
I < magic_enum::enum_count<E>()), V&> get( magic_enum::containers::array<E, V, Index>& a ) noexcept {
|
||||
return a.a[I];
|
||||
}
|
||||
|
||||
template< auto I, typename E, typename V, typename Index>
|
||||
template <auto I, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
|
||||
I < magic_enum::enum_count<E>()), V&&> get( magic_enum::containers::array<E, V, Index>&& a ) noexcept {
|
||||
return std::move(a.a[I]);
|
||||
}
|
||||
|
||||
template< auto I, typename E, typename V, typename Index>
|
||||
template <auto I, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
|
||||
I < magic_enum::enum_count<E>()), const V&> get( const magic_enum::containers::array<E, V, Index>& a ) noexcept {
|
||||
return a.a[I];
|
||||
}
|
||||
|
||||
template< auto I, typename E, typename V, typename Index>
|
||||
template <auto I, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<(std::is_integral_v<decltype(I)> &&
|
||||
I < magic_enum::enum_count<E>()), const V&&> get( const magic_enum::containers::array<E, V, Index>&& a ) noexcept {
|
||||
return std::move(a.a[I]);
|
||||
}
|
||||
|
||||
template< auto Enum, typename E, typename V, typename Index>
|
||||
template <auto Enum, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
|
||||
magic_enum::enum_contains(Enum), V&> get( magic_enum::containers::array<E, V, Index>& a ) noexcept {
|
||||
return a[Enum];
|
||||
}
|
||||
|
||||
template< auto Enum, typename E, typename V, typename Index>
|
||||
template <auto Enum, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
|
||||
magic_enum::enum_contains(Enum), V&&> get( magic_enum::containers::array<E, V, Index>&& a ) noexcept {
|
||||
return std::move(a[Enum]);
|
||||
}
|
||||
|
||||
template< auto Enum, typename E, typename V, typename Index>
|
||||
template <auto Enum, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
|
||||
magic_enum::enum_contains(Enum), const V&> get( const magic_enum::containers::array<E, V, Index>& a ) noexcept {
|
||||
return a[Enum];
|
||||
}
|
||||
|
||||
template< auto Enum, typename E, typename V, typename Index>
|
||||
template <auto Enum, typename E, typename V, typename Index>
|
||||
constexpr std::enable_if_t<std::is_same_v<decltype(Enum), E> &&
|
||||
magic_enum::enum_contains(Enum), const V&&> get( const magic_enum::containers::array<E, V, Index>&& a ) noexcept {
|
||||
return std::move(a[Enum]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif// NEARGYE_MAGIC_ENUM_CONTAINERS_HPP
|
||||
#endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -58,8 +58,14 @@ struct std::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && mag
|
|||
using D = std::decay_t<E>;
|
||||
|
||||
if constexpr (magic_enum::detail::supported<D>::value) {
|
||||
if (const auto name = magic_enum::enum_name<D, magic_enum::as_flags<magic_enum::detail::is_flags_v<D>>>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
|
||||
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
} else {
|
||||
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
|
||||
|
|
@ -79,8 +85,14 @@ struct fmt::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && mag
|
|||
using D = std::decay_t<E>;
|
||||
|
||||
if constexpr (magic_enum::detail::supported<D>::value) {
|
||||
if (const auto name = magic_enum::enum_name<D, magic_enum::as_flags<magic_enum::detail::is_flags_v<D>>>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
|
||||
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
} else {
|
||||
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -56,23 +56,23 @@ struct invoke_result<F, V, true> : std::invoke_result<F, V> {};
|
|||
template <typename F, typename V>
|
||||
using invoke_result_t = typename invoke_result<F, V>::type;
|
||||
|
||||
template <typename E, typename F, std::size_t... I>
|
||||
template <typename E, detail::enum_subtype S, typename F, std::size_t... I>
|
||||
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
|
||||
|
||||
if constexpr (count_v<E> == 0) {
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return identity<nonesuch>{};
|
||||
} else {
|
||||
return std::common_type<invoke_result_t<F, enum_constant<values_v<E>[I]>>...>{};
|
||||
return std::common_type<invoke_result_t<F, enum_constant<values_v<E, S>[I]>>...>{};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, typename Result, typename F>
|
||||
template <typename E, detail::enum_subtype S, typename Result, typename F>
|
||||
constexpr auto result_type() noexcept {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
|
||||
|
||||
constexpr auto seq = std::make_index_sequence<detail::count_v<E>>{};
|
||||
using R = typename decltype(common_invocable<E, F>(seq))::type;
|
||||
constexpr auto seq = std::make_index_sequence<detail::count_v<E, S>>{};
|
||||
using R = typename decltype(common_invocable<E, S, F>(seq))::type;
|
||||
if constexpr (std::is_same_v<Result, default_result_type>) {
|
||||
if constexpr (std::is_same_v<R, nonesuch>) {
|
||||
return identity<void>{};
|
||||
|
|
@ -90,7 +90,7 @@ constexpr auto result_type() noexcept {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Result, typename F, typename D = std::decay_t<T>, typename R = typename decltype(result_type<D, Result, F>())::type>
|
||||
template <typename E, detail::enum_subtype S, typename Result, typename F, typename D = std::decay_t<E>, typename R = typename decltype(result_type<D, S, Result, F>())::type>
|
||||
using result_t = std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
|
||||
|
||||
#if !defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
|
|
@ -110,10 +110,10 @@ constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r
|
|||
}
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t End, typename R, typename E, typename F, typename Def>
|
||||
template <std::size_t I, std::size_t End, typename R, typename E, detail::enum_subtype S, typename F, typename Def>
|
||||
constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
|
||||
if constexpr(I < End) {
|
||||
constexpr auto v = enum_constant<enum_value<E, I>()>{};
|
||||
constexpr auto v = enum_constant<enum_value<E, I, S>()>{};
|
||||
if (value == v) {
|
||||
if constexpr (std::is_invocable_r_v<R, F, decltype(v)>) {
|
||||
return invoke_r<R>(std::forward<F>(f), v);
|
||||
|
|
@ -121,63 +121,73 @@ constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
|
|||
return def();
|
||||
}
|
||||
} else {
|
||||
return constexpr_switch_impl<I + 1, End, R>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
return constexpr_switch_impl<I + 1, End, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
}
|
||||
} else {
|
||||
return def();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename E, typename F, typename Def>
|
||||
template <typename R, typename E, detail::enum_subtype S, typename F, typename Def>
|
||||
constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::constexpr_switch requires enum type.");
|
||||
|
||||
if constexpr (count_v<E> == 0) {
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return def();
|
||||
} else {
|
||||
return constexpr_switch_impl<0, count_v<E>, R>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
return constexpr_switch_impl<0, count_v<E, S>, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace magic_enum::detail
|
||||
|
||||
template <typename Result = detail::default_result_type, typename E, typename F, typename R = detail::result_t<E, Result, F>>
|
||||
template <typename Result = detail::default_result_type, typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
|
||||
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
detail::default_result_type_lambda<R>);
|
||||
#else
|
||||
return detail::constexpr_switch<R, D>(
|
||||
return detail::constexpr_switch<R, D, S>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
detail::default_result_type_lambda<R>);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Result, typename E, typename F, typename R = detail::result_t<E, Result, F>>
|
||||
template <typename Result = detail::default_result_type, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||
return enum_switch<Result, E, S>(std::forward<F>(f), value);
|
||||
}
|
||||
|
||||
template <typename Result, typename E, auto S = detail::subtype_v<std::decay_t<E>>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
|
||||
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
return detail::constexpr_switch<&detail::values_v<D>, detail::case_call_t::value>(
|
||||
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
[&result]() -> R { return std::forward<Result>(result); });
|
||||
#else
|
||||
return detail::constexpr_switch<R, D>(
|
||||
return detail::constexpr_switch<R, D, S>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
[&result]() -> R { return std::forward<Result>(result); });
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Result, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||
return enum_switch<Result, E, S>(std::forward<F>(f), value, std::forward<Result>(result));
|
||||
}
|
||||
|
||||
} // namespace magic_enum
|
||||
|
||||
template <>
|
||||
|
|
|
|||
|
|
@ -8,10 +8,6 @@ magic_enum_include = include_directories('include')
|
|||
|
||||
magic_enum_args = []
|
||||
|
||||
if get_option('noascii')
|
||||
magic_enum_args += '-DMAGIC_ENUM_ENABLE_NONASCII'
|
||||
endif
|
||||
|
||||
if get_option('hash')
|
||||
magic_enum_args += '-DMAGIC_ENUM_ENABLE_HASH'
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ cc_library(
|
|||
|
||||
_TESTS = [
|
||||
"test",
|
||||
"test_aliases",
|
||||
"test_containers",
|
||||
"test_flags",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
|||
check_cxx_compiler_flag(-std=c++23 HAS_CPP23_FLAG)
|
||||
endif()
|
||||
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
set(OPTIONS ${OPTIONS} -DMAGIC_ENUM_ENABLE_NONASCII)
|
||||
endif()
|
||||
|
||||
function(make_test src target std)
|
||||
add_executable(${target} ${src})
|
||||
target_compile_options(${target} PRIVATE ${OPTIONS})
|
||||
|
|
@ -41,7 +37,7 @@ endfunction()
|
|||
make_test(test.cpp test-cpp17 c++17)
|
||||
make_test(test_flags.cpp test_flags-cpp17 c++17)
|
||||
make_test(test_aliases.cpp test_aliases-cpp17 c++17)
|
||||
make_test(test_containers.cpp test_containers-cpp17 c++17)
|
||||
#make_test(test_containers.cpp test_containers-cpp17 c++17) TODO
|
||||
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp17 c++17)
|
||||
|
|
@ -51,7 +47,7 @@ if(HAS_CPP20_FLAG)
|
|||
make_test(test.cpp test-cpp20 c++20)
|
||||
make_test(test_flags.cpp test_flags-cpp20 c++20)
|
||||
make_test(test_aliases.cpp test_aliases-cpp20 c++20)
|
||||
make_test(test_containers.cpp test_containers-cpp20 c++20)
|
||||
#make_test(test_containers.cpp test_containers-cpp20 c++20) TODO
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp20 c++20)
|
||||
endif()
|
||||
|
|
@ -61,7 +57,7 @@ if(HAS_CPP23_FLAG)
|
|||
make_test(test.cpp test-cpp23 c++23)
|
||||
make_test(test_flags.cpp test_flags-cpp23 c++23)
|
||||
make_test(test_aliases.cpp test_aliases-cpp23 c++23)
|
||||
make_test(test_containers.cpp test_containers-cpp23 c++23)
|
||||
#make_test(test_containers.cpp test_containers-cpp23 c++23) TODO
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp23 c++23)
|
||||
endif()
|
||||
|
|
@ -71,7 +67,7 @@ if(HAS_CPPLATEST_FLAG)
|
|||
make_test(test.cpp test-cpplatest c++latest)
|
||||
make_test(test_flags.cpp test_flags-cpplatest c++latest)
|
||||
make_test(test_aliases.cpp test_aliases-cpplatest c++latest)
|
||||
make_test(test_containers.cpp test_containers-cpplatest c++latest)
|
||||
#make_test(test_containers.cpp test_containers-cpplatest c++latest) TODO
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpplatest c++latest)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ catch2_dep = declare_dependency(
|
|||
test_files = {
|
||||
'basic test' : files('test.cpp'),
|
||||
'flags test' : files('test_flags.cpp'),
|
||||
'aliases test' : files('test_aliases.cpp'),
|
||||
'containers test' : files('test_containers.cpp'),
|
||||
}
|
||||
|
||||
foreach test_name, test_src : test_files
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -55,7 +55,6 @@ enum number : unsigned long {
|
|||
two = 200,
|
||||
three = 300,
|
||||
four = 400,
|
||||
|
||||
#if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
|
||||
_1 = one,
|
||||
_2 = two,
|
||||
|
|
@ -63,6 +62,11 @@ enum number : unsigned long {
|
|||
_4 = four
|
||||
#endif
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
|
||||
enum class crc_hack {
|
||||
b5a7b602ab754d7ab30fb42c4fb28d82
|
||||
|
|
@ -73,12 +77,6 @@ enum class crc_hack_2 {
|
|||
d19f2e9e82d14b96be4fa12b8a27ee9f
|
||||
};
|
||||
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
};
|
||||
|
||||
enum class MaxUsedAsInvalid : std::uint8_t {
|
||||
ONE,
|
||||
TWO = 63,
|
||||
|
|
@ -460,7 +458,8 @@ TEST_CASE("enum_name") {
|
|||
REQUIRE(cr_name == "red");
|
||||
REQUIRE(enum_name<Color&>(cb) == "BLUE");
|
||||
REQUIRE(enum_name<as_flags<false>>(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_name<detail::value_type::default_value>(static_cast<Color>(0)).empty());
|
||||
REQUIRE(enum_name<as_common<true>>(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_name<as_flags<false>>(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = enum_name(no);
|
||||
|
|
@ -762,58 +761,58 @@ TEST_CASE("extrema") {
|
|||
|
||||
SECTION("min") {
|
||||
REQUIRE(magic_enum::customize::enum_range<BadColor>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<BadColor, false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<BadColor> == 0);
|
||||
REQUIRE(magic_enum::detail::reflected_min<BadColor, as_common<>>() == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<BadColor, as_common<>> == 0);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Color>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Color, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Color> == -12);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Color, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Color, as_common<>> == -12);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Numbers>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Numbers, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Numbers> == 1);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Numbers, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Numbers, as_common<>> == 1);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Directions>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Directions, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Directions> == -120);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Directions, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Directions, as_common<>> == -120);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<number>::min == 100);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<number, false> == 100);
|
||||
REQUIRE(magic_enum::detail::min_v<number> == 100);
|
||||
REQUIRE(magic_enum::detail::reflected_min<number, as_common<>>() == 100);
|
||||
REQUIRE(magic_enum::detail::min_v<number, as_common<>> == 100);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Binary, false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<Binary> == false);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Binary, as_common<>>() == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<Binary, as_common<>> == false);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<MaxUsedAsInvalid,false> == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<MaxUsedAsInvalid> == 0);
|
||||
REQUIRE(magic_enum::detail::reflected_min<MaxUsedAsInvalid, as_common<>>() == 0);
|
||||
REQUIRE(magic_enum::detail::min_v<MaxUsedAsInvalid, as_common<>> == 0);
|
||||
}
|
||||
|
||||
SECTION("max") {
|
||||
REQUIRE(magic_enum::customize::enum_range<BadColor>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<BadColor, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<BadColor> == 2);
|
||||
REQUIRE(magic_enum::detail::reflected_max<BadColor, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<BadColor, as_common<>> == 2);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Color>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Color, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Color> == 15);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Color, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Color, as_common<>> == 15);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Numbers>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Numbers, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Numbers> == 3);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Numbers, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Numbers, as_common<>> == 3);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<Directions>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Directions, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Directions> == 120);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Directions, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Directions, as_common<>> == 120);
|
||||
|
||||
REQUIRE(magic_enum::customize::enum_range<number>::max == 300);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<number, false> == 300);
|
||||
REQUIRE(magic_enum::detail::max_v<number> == 300);
|
||||
REQUIRE(magic_enum::detail::reflected_max<number, as_common<>>() == 300);
|
||||
REQUIRE(magic_enum::detail::max_v<number, as_common<>> == 300);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Binary, false> == 1);
|
||||
REQUIRE(magic_enum::detail::max_v<Binary> == true);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Binary, as_common<>>() == 1);
|
||||
REQUIRE(magic_enum::detail::max_v<Binary, as_common<>> == true);
|
||||
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<MaxUsedAsInvalid, false> == 64);
|
||||
REQUIRE(magic_enum::detail::max_v<MaxUsedAsInvalid> == 63);
|
||||
REQUIRE(magic_enum::detail::reflected_max<MaxUsedAsInvalid, as_common<>>() == 64);
|
||||
REQUIRE(magic_enum::detail::max_v<MaxUsedAsInvalid, as_common<>> == 63);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -41,6 +41,10 @@
|
|||
#include <sstream>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum class Numbers : int {
|
||||
one = 1 << 1,
|
||||
|
|
@ -48,6 +52,10 @@ enum class Numbers : int {
|
|||
three = 1 << 3,
|
||||
many = 1 << 30,
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Numbers> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum Directions : std::uint64_t {
|
||||
Left = std::uint64_t{1} << 10,
|
||||
|
|
@ -55,13 +63,16 @@ enum Directions : std::uint64_t {
|
|||
Up = std::uint64_t{1} << 31,
|
||||
Right = std::uint64_t{1} << 63,
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Directions> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum number : unsigned long {
|
||||
one = 1 << 1,
|
||||
two = 1 << 2,
|
||||
three = 1 << 3,
|
||||
four = 1 << 4,
|
||||
|
||||
#if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
|
||||
_1 = one,
|
||||
_2 = two,
|
||||
|
|
@ -71,10 +82,12 @@ enum number : unsigned long {
|
|||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr int min = 100;
|
||||
static constexpr int max = 300;
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum_fuse.hpp>
|
||||
|
||||
using namespace magic_enum;
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
|
|
@ -208,11 +221,6 @@ TEST_CASE("enum_contains") {
|
|||
REQUIRE(cr);
|
||||
REQUIRE(enum_contains<Color&>(cg));
|
||||
REQUIRE(enum_contains(cm[2]));
|
||||
REQUIRE(enum_contains<Color, as_flags<>>(Color::RED | Color::GREEN));
|
||||
REQUIRE(enum_contains<Color, as_flags<true>>(Color::RED | Color::GREEN | Color::GREEN));
|
||||
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color::GREEN));
|
||||
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
|
||||
REQUIRE_FALSE(enum_contains<Color>(Color::RED | Color{8}));
|
||||
REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
|
||||
|
||||
REQUIRE(enum_flags_contains<Color&>(cg));
|
||||
|
|
@ -252,11 +260,6 @@ TEST_CASE("enum_contains") {
|
|||
REQUIRE(enum_contains<Color>(1));
|
||||
REQUIRE(enum_contains<Color&>(2));
|
||||
REQUIRE(enum_contains<const Color>(4));
|
||||
REQUIRE(enum_contains<Color, as_flags<>>(1 | 2));
|
||||
REQUIRE(enum_contains<Color, as_flags<true>>(1 | 2 | 1));
|
||||
REQUIRE_FALSE(enum_contains<Color>(1 | 2));
|
||||
REQUIRE_FALSE(enum_contains<Color>(1 | 2 | 1));
|
||||
REQUIRE_FALSE(enum_contains<Color>(1 | 2 | 8));
|
||||
REQUIRE_FALSE(enum_contains<Color>(0));
|
||||
|
||||
REQUIRE(enum_flags_contains<Color>(1));
|
||||
|
|
@ -297,9 +300,6 @@ TEST_CASE("enum_contains") {
|
|||
REQUIRE(enum_contains<Color>(cr));
|
||||
REQUIRE(enum_contains<Color&>("GREEN"));
|
||||
REQUIRE(enum_contains<const Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE(enum_contains<Color&, as_flags<>>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE(enum_contains<Color&, as_flags<true>>("GREEN|RED"));
|
||||
REQUIRE(enum_contains<Color, as_flags<true>>("GREEN|RED|RED"));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED"));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED|RED"));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2022 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -35,11 +35,7 @@
|
|||
#include <string_view>
|
||||
#include <sstream>
|
||||
|
||||
#if !defined(MAGIC_ENUM_ENABLE_NONASCII)
|
||||
#error ENABLE_NONASCII must be defined to run nonascii tests
|
||||
#endif
|
||||
|
||||
enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40 };
|
||||
enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40, TVÅ = 50 };
|
||||
|
||||
enum class LanguageFlag : int {
|
||||
日本語 = 1 << 1,
|
||||
|
|
@ -59,6 +55,7 @@ TEST_CASE("enum_cast") {
|
|||
REQUIRE(enum_cast<const Language>("English").value() == Language::English);
|
||||
REQUIRE(lang.value() == Language::日本語);
|
||||
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
|
||||
REQUIRE(enum_cast<Language>("TVÅ").value() == Language::TVÅ);
|
||||
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
|
||||
}
|
||||
|
||||
|
|
@ -130,12 +127,12 @@ TEST_CASE("enum_value") {
|
|||
|
||||
TEST_CASE("enum_values") {
|
||||
constexpr auto& s7 = enum_values<const Language>();
|
||||
REQUIRE(s7 == std::array<Language, 4>{{Language::日本語, Language::한국어, Language::English, Language::😃}});
|
||||
REQUIRE(s7 == std::array<Language, 5>{{Language::日本語, Language::한국어, Language::English, Language::😃, Language::TVÅ}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_count") {
|
||||
constexpr auto s7 = enum_count<Language>();
|
||||
REQUIRE(s7 == 4);
|
||||
REQUIRE(s7 == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_name") {
|
||||
|
|
@ -147,6 +144,7 @@ TEST_CASE("enum_name") {
|
|||
REQUIRE(enum_name<const Language>(Language::English) == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_name(Language::😃) == "😃");
|
||||
REQUIRE(enum_name(Language::TVÅ) == "TVÅ");
|
||||
REQUIRE(enum_name(static_cast<Language>(0)).empty());
|
||||
}
|
||||
|
||||
|
|
@ -162,12 +160,12 @@ TEST_CASE("enum_name") {
|
|||
|
||||
TEST_CASE("enum_names") {
|
||||
constexpr auto& s5 = enum_names<const Language>();
|
||||
REQUIRE(s5 == std::array<std::string_view, 4>{{"日本語", "한국어", "English", "😃"}});
|
||||
REQUIRE(s5 == std::array<std::string_view, 5>{{"日本語", "한국어", "English", "😃", "TVÅ"}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_entries") {
|
||||
constexpr auto& s5 = enum_entries<const Language>();
|
||||
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 4>{{{Language::日本語, "日本語"}, {Language::한국어, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}}});
|
||||
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 5>{{{Language::日本語, "日本語"}, {Language::한국어, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}, {Language::TVÅ, "TVÅ"}}});
|
||||
}
|
||||
|
||||
TEST_CASE("ostream_operators") {
|
||||
|
|
@ -251,14 +249,14 @@ TEST_CASE("enum_type_name") {
|
|||
TEST_CASE("extrema") {
|
||||
SECTION("min") {
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min_v<Language, false> == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Language> == 10);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Language, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Language, as_common<>> == 10);
|
||||
}
|
||||
|
||||
SECTION("max") {
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max_v<Language, false> == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Language> == 40);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Language, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Language, as_common<>> == 50);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue