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
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 <>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue