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

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