1
0
Fork 0
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:
neargye 2023-05-21 03:39:52 +04:00
parent 737ed4fc7f
commit 427a47394f
27 changed files with 515 additions and 875 deletions

View file

@ -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})

View file

@ -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

View file

@ -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

View file

@ -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"],
)

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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 <>

View file

@ -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

View file

@ -12,8 +12,6 @@ cc_library(
_TESTS = [
"test",
"test_aliases",
"test_containers",
"test_flags",
]

View file

@ -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()

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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

View file

@ -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"));

View file

@ -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);
}
}