Coverage Report

Created: 2023-09-25 06:29

/src/magic_enum/include/magic_enum_containers.hpp
Line
Count
Source (jump to first uncovered line)
1
//  __  __             _        ______                          _____
2
// |  \/  |           (_)      |  ____|                        / ____|_     _
3
// | \  / | __ _  __ _ _  ___  | |__   _ __  _   _ _ __ ___   | |   _| |_ _| |_
4
// | |\/| |/ _` |/ _` | |/ __| |  __| | '_ \| | | | '_ ` _ \  | |  |_   _|_   _|
5
// | |  | | (_| | (_| | | (__  | |____| | | | |_| | | | | | | | |____|_|   |_|
6
// |_|  |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_|  \_____|
7
//                __/ | https://github.com/Neargye/magic_enum
8
//               |___/  version 0.9.3
9
//
10
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
11
// SPDX-License-Identifier: MIT
12
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
13
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
14
//
15
// Permission is hereby  granted, free of charge, to any  person obtaining a copy
16
// of this software and associated  documentation files (the "Software"), to deal
17
// in the Software  without restriction, including without  limitation the rights
18
// to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
19
// copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
20
// furnished to do so, subject to the following conditions:
21
//
22
// The above copyright notice and this permission notice shall be included in all
23
// copies or substantial portions of the Software.
24
//
25
// THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
26
// IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
27
// FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
28
// AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
29
// LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
// OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
31
// SOFTWARE.
32
33
#ifndef NEARGYE_MAGIC_ENUM_CONTAINERS_HPP
34
#define NEARGYE_MAGIC_ENUM_CONTAINERS_HPP
35
36
#include "magic_enum.hpp"
37
38
#if !defined(MAGIC_ENUM_NO_EXCEPTION) && (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND))
39
#  include <stdexcept>
40
0
#  define MAGIC_ENUM_THROW(...) throw (__VA_ARGS__)
41
#else
42
#  include <cstdlib>
43
#  define MAGIC_ENUM_THROW(...) std::abort()
44
#endif
45
46
namespace magic_enum::containers {
47
48
namespace detail {
49
50
template <typename T, typename = void>
51
static constexpr bool is_transparent_v{};
52
53
template <typename T>
54
static constexpr bool is_transparent_v<T, std::void_t<typename T::is_transparent>>{true};
55
56
template <typename Eq = std::equal_to<>, typename T1, typename T2>
57
constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) {
58
  auto first1 = t1.begin();
59
  auto last1 = t1.end();
60
  auto first2 = t2.begin();
61
  auto last2 = t2.end();
62
63
  for (; first1 != last1; ++first1, ++first2) {
64
    if (first2 == last2 || !eq(*first1, *first2)) {
65
      return false;
66
    }
67
  }
68
  return first2 == last2;
69
}
70
71
template <typename Cmp = std::less<>, typename T1, typename T2>
72
constexpr bool lexicographical_compare(T1&& t1, T2&& t2, Cmp&& cmp = {}) noexcept {
73
  auto first1 = t1.begin();
74
  auto last1 = t1.end();
75
  auto first2 = t2.begin();
76
  auto last2 = t2.end();
77
78
  // copied from std::lexicographical_compare
79
  for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) {
80
    if (cmp(*first1, *first2)) {
81
      return true;
82
    }
83
    if (cmp(*first2, *first1)) {
84
      return false;
85
    }
86
  }
87
  return (first1 == last1) && (first2 != last2);
88
}
89
90
template <typename T>
91
512
constexpr std::size_t popcount(T x) noexcept {
92
512
  std::size_t c = 0;
93
2.04k
  while (x > 0) {
94
1.53k
    c += x & 1;
95
1.53k
    x >>= 1;
96
1.53k
  }
97
512
  return c;
98
512
}
99
100
template <typename Cmp = std::less<>, typename ForwardIt, typename E>
101
constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) {
102
  auto count = std::distance(first, last);
103
  for (auto it = first; count > 0;) {
104
    auto step = count / 2;
105
    std::advance(it, step);
106
    if (comp(*it, e)) {
107
      first = ++it;
108
      count -= step + 1;
109
    } else {
110
      count = step;
111
    }
112
  }
113
  return first;
114
}
115
116
template <typename Cmp = std::less<>, typename BidirIt, typename E>
117
constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) {
118
  const auto first = lower_bound(begin, end, e, comp);
119
  return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp](auto&& lhs, auto&& rhs) { return comp(rhs, lhs); }).base()};
120
}
121
122
template <typename E = void, typename Cmp = std::less<E>, typename = void>
123
class indexing {
124
  [[nodiscard]] static constexpr auto get_indices() noexcept {
125
    // reverse result index mapping
126
    std::array<std::size_t, enum_count<E>()> rev_res{};
127
128
    // std::iota
129
    for (std::size_t i = 0; i < enum_count<E>(); ++i) {
130
      rev_res[i] = i;
131
    }
132
133
    constexpr auto orig_values = enum_values<E>();
134
    constexpr Cmp cmp{};
135
136
    // ~std::sort
137
    for (std::size_t i = 0; i < enum_count<E>(); ++i) {
138
      for (std::size_t j = i + 1; j < enum_count<E>(); ++j) {
139
        if (cmp(orig_values[rev_res[j]], orig_values[rev_res[i]])) {
140
          auto tmp = rev_res[i];
141
          rev_res[i] = rev_res[j];
142
          rev_res[j] = tmp;
143
        }
144
      }
145
    }
146
147
    std::array<E, enum_count<E>()> sorted_values{};
148
    // reverse the sorted indices
149
    std::array<std::size_t, enum_count<E>()> res{};
150
    for (std::size_t i = 0; i < enum_count<E>(); ++i) {
151
      res[rev_res[i]] = i;
152
      sorted_values[i] = orig_values[rev_res[i]];
153
    }
154
155
    return std::pair{sorted_values, res};
156
  }
157
158
  static constexpr auto indices = get_indices();
159
160
 public:
161
  [[nodiscard]] static constexpr const E* begin() noexcept { return indices.first.data(); }
162
163
  [[nodiscard]] static constexpr const E* end() noexcept { return indices.first.data() + indices.first.size(); }
164
165
  [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return indices.first.data() + i; }
166
167
  [[nodiscard]] static constexpr optional<std::size_t> at(E val) noexcept {
168
    if (auto i = enum_index(val)) {
169
      return indices.second[*i];
170
    }
171
    return {};
172
  }
173
};
174
175
template <typename E, typename Cmp>
176
class indexing<E, Cmp, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && (std::is_same_v<Cmp, std::less<E>> || std::is_same_v<Cmp, std::less<>>)>> {
177
   static constexpr auto& values = enum_values<E>();
178
179
 public:
180
1.53k
   [[nodiscard]] static constexpr const E* begin() noexcept { return values.data(); }
181
182
1.53k
   [[nodiscard]] static constexpr const E* end() noexcept { return values.data() + values.size(); }
183
184
1.53k
  [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return values.data() + i; }
185
186
4.09k
  [[nodiscard]] static constexpr optional<std::size_t> at(E val) noexcept { return enum_index(val); }
187
};
188
189
template <typename Cmp>
190
struct indexing<void, Cmp, void> {
191
  using is_transparent = std::true_type;
192
193
  template <typename E>
194
  [[nodiscard]] static constexpr optional<std::size_t> at(E val) noexcept {
195
    return indexing<E, Cmp>::at(val);
196
  }
197
};
198
199
template <typename E = void, typename Cmp = std::less<>, typename = void>
200
struct name_sort_impl {
201
  [[nodiscard]] constexpr bool operator()(E e1, E e2) const noexcept { return Cmp{}(enum_name(e1), enum_name(e2)); }
202
};
203
204
template <typename Cmp>
205
struct name_sort_impl<void, Cmp> {
206
  using is_transparent = std::true_type;
207
208
  template <typename C = Cmp, typename = void>
209
  struct FullCmp : C {};
210
211
  template <typename C>
212
  struct FullCmp<C, std::enable_if_t<!std::is_invocable_v<C, string_view, string_view> && std::is_invocable_v<C, char_type, char_type>>> {
213
    [[nodiscard]] constexpr bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare<C>(s1, s2); }
214
  };
215
216
  template <typename E1, typename E2>
217
  [[nodiscard]] constexpr std::enable_if_t<
218
      // at least one of need to be an enum type
219
      (std::is_enum_v<std::decay_t<E1>> || std::is_enum_v<std::decay_t<E2>>) &&
220
      // if both is enum, only accept if the same enum
221
      (!std::is_enum_v<std::decay_t<E1>> || !std::is_enum_v<std::decay_t<E2>> || std::is_same_v<E1, E2>) &&
222
      // is invocable with comparator
223
      (std::is_invocable_r_v<bool, FullCmp<>, std::conditional_t<std::is_enum_v<std::decay_t<E1>>, string_view, E1>, std::conditional_t<std::is_enum_v<std::decay_t<E2>>, string_view, E2>>),
224
      bool>
225
  operator()(E1 e1, E2 e2) const noexcept {
226
    using D1 = std::decay_t<E1>;
227
    using D2 = std::decay_t<E2>;
228
    constexpr FullCmp<> cmp{};
229
230
    if constexpr (std::is_enum_v<D1> && std::is_enum_v<D2>) {
231
      return cmp(enum_name(e1), enum_name(e2));
232
    } else if constexpr (std::is_enum_v<D1>) {
233
      return cmp(enum_name(e1), e2);
234
    } else /* if constexpr (std::is_enum_v<D2>) */ {
235
      return cmp(e1, enum_name(e2));
236
    }
237
  }
238
};
239
240
struct raw_access_t {};
241
242
template <typename Parent, typename Iterator, typename Getter, typename Predicate>
243
struct FilteredIterator {
244
  Parent parent;
245
  Iterator first;
246
  Iterator last;
247
  Iterator current;
248
  Getter getter;
249
  Predicate predicate;
250
251
  using iterator_category = std::bidirectional_iterator_tag;
252
  using value_type = std::remove_reference_t<std::invoke_result_t<Getter, Parent, Iterator>>;
253
  using difference_type = std::ptrdiff_t;
254
  using pointer = value_type*;
255
  using reference = value_type&;
256
257
  constexpr FilteredIterator() noexcept = default;
258
  constexpr FilteredIterator(const FilteredIterator&) = default;
259
  constexpr FilteredIterator& operator=(const FilteredIterator&) = default;
260
  constexpr FilteredIterator(FilteredIterator&&) noexcept = default;
261
  constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default;
262
263
  template <typename OtherParent, typename OtherIterator, typename = std::enable_if_t<std::is_convertible_v<OtherParent, Parent> && std::is_convertible_v<OtherIterator, Iterator>>*>
264
  constexpr explicit FilteredIterator(const FilteredIterator<OtherParent, OtherIterator, Getter, Predicate>& other)
265
      : parent(other.parent), first(other.first), last(other.last), current(other.current), getter(other.getter), predicate(other.predicate) {}
266
267
  constexpr FilteredIterator(Parent p, Iterator begin, Iterator end, Iterator curr, Getter getter = {}, Predicate pred = {})
268
1.53k
      : parent(p), first(std::move(begin)), last(std::move(end)), current(std::move(curr)), getter{std::move(getter)}, predicate{std::move(pred)} {
269
1.53k
    if (current == first && !predicate(parent, current)) {
270
0
      ++*this;
271
0
    }
272
1.53k
  }
273
274
  [[nodiscard]] constexpr reference operator*() const { return getter(parent, current); }
275
276
  [[nodiscard]] constexpr pointer operator->() const { return std::addressof(**this); }
277
278
0
  constexpr FilteredIterator& operator++() {
279
0
    do {
280
0
      ++current;
281
0
    } while (current != last && !predicate(parent, current));
282
0
    return *this;
283
0
  }
284
285
  [[nodiscard]] constexpr FilteredIterator operator++(int) {
286
    FilteredIterator cp = *this;
287
    ++*this;
288
    return cp;
289
  }
290
291
  constexpr FilteredIterator& operator--() {
292
    do {
293
      --current;
294
    } while (current != first && !predicate(parent, current));
295
    return *this;
296
  }
297
298
  [[nodiscard]] constexpr FilteredIterator operator--(int) {
299
    FilteredIterator cp = *this;
300
    --*this;
301
    return cp;
302
  }
303
304
  [[nodiscard]] friend constexpr bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current == rhs.current; }
305
306
  [[nodiscard]] friend constexpr bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current != rhs.current; }
307
};
308
309
} // namespace detail
310
311
template <typename E = void>
312
using name_less = detail::name_sort_impl<E>;
313
314
template <typename E = void>
315
using name_greater = detail::name_sort_impl<E, std::greater<>>;
316
317
using name_less_case_insensitive = detail::name_sort_impl<void, magic_enum::detail::case_insensitive<std::less<>>>;
318
319
using name_greater_case_insensitive = detail::name_sort_impl<void, magic_enum::detail::case_insensitive<std::greater<>>>;
320
321
template <typename E = void>
322
using default_indexing = detail::indexing<E>;
323
324
template <typename Cmp = std::less<>>
325
using comparator_indexing = detail::indexing<void, Cmp>;
326
327
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
328
//                                                          ARRAY                                                            //
329
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
330
template <typename E, typename V, typename Index = default_indexing<E>>
331
struct array {
332
  static_assert(std::is_enum_v<E>);
333
  static_assert(std::is_trivially_constructible_v<Index>);
334
  static_assert(enum_count<E>() == 0 || Index::at(enum_values<E>().front())); // check Index is constexpr
335
336
  using index_type = Index;
337
  using container_type = std::array<V, enum_count<E>()>;
338
339
  using value_type = typename container_type::value_type;
340
  using size_type = typename container_type::size_type;
341
  using difference_type = typename container_type::difference_type;
342
  using reference = typename container_type::reference;
343
  using const_reference = typename container_type::const_reference;
344
  using pointer = typename container_type::pointer;
345
  using const_pointer = typename container_type::const_pointer;
346
  using iterator = typename container_type::iterator;
347
  using const_iterator = typename container_type::const_iterator;
348
  using reverse_iterator = typename container_type::reverse_iterator;
349
  using const_reverse_iterator = typename container_type::const_reverse_iterator;
350
351
  constexpr reference at(E pos) {
352
    if (auto index = index_type::at(pos)) {
353
      return a[*index];
354
    }
355
    MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at Unrecognized position"));
356
  }
357
358
  constexpr const_reference at(E pos) const {
359
    if (auto index = index_type::at(pos)) {
360
      return a[*index];
361
    }
362
    MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at: Unrecognized position"));
363
  }
364
365
  [[nodiscard]] constexpr reference operator[](E pos) {
366
    auto i = index_type::at(pos);
367
    return MAGIC_ENUM_ASSERT(i), a[*i];
368
  }
369
370
  [[nodiscard]] constexpr const_reference operator[](E pos) const {
371
    auto i = index_type::at(pos);
372
    return MAGIC_ENUM_ASSERT(i), a[*i];
373
  }
374
375
  [[nodiscard]] constexpr reference front() noexcept { return a.front(); }
376
377
  [[nodiscard]] constexpr const_reference front() const noexcept { return a.front(); }
378
379
  [[nodiscard]] constexpr reference back() noexcept { return a.back(); }
380
381
  [[nodiscard]] constexpr const_reference back() const noexcept { return a.back(); }
382
383
  [[nodiscard]] constexpr pointer data() noexcept { return a.data(); }
384
385
  [[nodiscard]] constexpr const_pointer data() const noexcept { return a.data(); }
386
387
  [[nodiscard]] constexpr iterator begin() noexcept { return a.begin(); }
388
389
  [[nodiscard]] constexpr const_iterator begin() const noexcept { return a.begin(); }
390
391
  [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return a.cbegin(); }
392
393
  [[nodiscard]] constexpr iterator end() noexcept { return a.end(); }
394
395
  [[nodiscard]] constexpr const_iterator end() const noexcept { return a.end(); }
396
397
  [[nodiscard]] constexpr const_iterator cend() const noexcept { return a.cend(); }
398
399
  [[nodiscard]] constexpr iterator rbegin() noexcept { return a.rbegin(); }
400
401
  [[nodiscard]] constexpr const_iterator rbegin() const noexcept { return a.rbegin(); }
402
403
  [[nodiscard]] constexpr const_iterator crbegin() const noexcept { return a.crbegin(); }
404
405
  [[nodiscard]] constexpr iterator rend() noexcept { return a.rend(); }
406
407
  [[nodiscard]] constexpr const_iterator rend() const noexcept { return a.rend(); }
408
409
  [[nodiscard]] constexpr const_iterator crend() const noexcept { return a.crend(); }
410
411
  [[nodiscard]] constexpr bool empty() const noexcept { return a.empty(); }
412
413
  [[nodiscard]] constexpr size_type size() const noexcept { return a.size(); }
414
415
  [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); }
416
417
  constexpr void fill(const V& value) {
418
    for (auto& v : a) {
419
      v = value;
420
    }
421
  }
422
423
  constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v<V>) {
424
    for (std::size_t i = 0; i < a.size(); ++i) {
425
      auto v = std::move(other.a[i]);
426
      other.a[i] = std::move(a[i]);
427
      a[i] = std::move(v);
428
    }
429
  }
430
431
  [[nodiscard]] friend constexpr bool operator==(const array& a1, const array& a2) { return detail::equal(a1, a2); }
432
433
  [[nodiscard]] friend constexpr bool operator!=(const array& a1, const array& a2) { return !detail::equal(a1, a2); }
434
435
  [[nodiscard]] friend constexpr bool operator<(const array& a1, const array& a2) { return detail::lexicographical_compare(a1, a2); }
436
437
  [[nodiscard]] friend constexpr bool operator<=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a2, a1); }
438
439
  [[nodiscard]] friend constexpr bool operator>(const array& a1, const array& a2) { return detail::lexicographical_compare(a2, a1); }
440
441
  [[nodiscard]] friend constexpr bool operator>=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a1, a2); }
442
443
  container_type a;
444
};
445
446
namespace detail {
447
448
template <typename E, typename T, std::size_t N, std::size_t... I>
449
constexpr array<E, std::remove_cv_t<T>> to_array_impl(T (&a)[N], std::index_sequence<I...>) {
450
  return {{a[I]...}};
451
}
452
453
template <typename E, typename T, std::size_t N, std::size_t... I>
454
constexpr array<E, std::remove_cv_t<T>> to_array_impl(T(&&a)[N], std::index_sequence<I...>) {
455
  return {{std::move(a[I])...}};
456
}
457
458
} // namespace detail
459
460
template <typename E, typename T, std::size_t N>
461
constexpr std::enable_if_t<(enum_count<E>() == N), array<E, std::remove_cv_t<T>>> to_array(T (&a)[N]) {
462
  return detail::to_array_impl<E>(a, std::make_index_sequence<N>{});
463
}
464
465
template <typename E, typename T, std::size_t N>
466
constexpr std::enable_if_t<(enum_count<E>() == N), array<E, std::remove_cv_t<T>>> to_array(T(&&a)[N]) {
467
  return detail::to_array_impl<E>(std::move(a), std::make_index_sequence<N>{});
468
}
469
470
template <typename E, typename... Ts>
471
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) {
472
  return {{std::forward<Ts>(ts)...}};
473
}
474
475
inline constexpr detail::raw_access_t raw_access{};
476
477
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
478
//                                                         BITSET                                                            //
479
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
480
template <typename E, typename Index = default_indexing<E>>
481
class bitset {
482
  static_assert(std::is_enum_v<E>);
483
  static_assert(std::is_trivially_constructible_v<Index>);
484
  static_assert(enum_count<E>() == 0 || Index::at(enum_values<E>().front())); // check Index is constexpr
485
486
  using base_type = std::conditional_t<enum_count<E>() <= 8,  std::uint_least8_t,
487
                    std::conditional_t<enum_count<E>() <= 16, std::uint_least16_t,
488
                    std::conditional_t<enum_count<E>() <= 32, std::uint_least32_t,
489
                                                              std::uint_least64_t>>>;
490
491
  static constexpr std::size_t bits_per_base = sizeof(base_type) * 8;
492
  static constexpr std::size_t base_type_count = (enum_count<E>() > 0 ? (enum_count<E>() - 1) / bits_per_base + 1 : 0);
493
  static constexpr std::size_t not_interested = base_type_count * bits_per_base - enum_count<E>();
494
  static constexpr base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1;
495
496
  template <typename parent_t = bitset*>
497
  class reference_impl {
498
    friend class bitset;
499
500
    parent_t parent;
501
    std::size_t num_index;
502
    base_type bit_index;
503
504
2.56k
    constexpr reference_impl(parent_t parent, std::size_t ix) noexcept : reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)}) {}
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >*>::reference_impl(magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >*, unsigned long)
Line
Count
Source
504
2.04k
    constexpr reference_impl(parent_t parent, std::size_t ix) noexcept : reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)}) {}
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> > const*>::reference_impl(magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> > const*, unsigned long)
Line
Count
Source
504
512
    constexpr reference_impl(parent_t parent, std::size_t ix) noexcept : reference_impl(parent, std::pair{ix / bits_per_base, base_type{1} << (ix % bits_per_base)}) {}
505
506
2.56k
    constexpr reference_impl(parent_t parent, std::pair<std::size_t, base_type> ix) noexcept : parent(parent), num_index(std::get<0>(ix)), bit_index(std::get<1>(ix)) {}
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >*>::reference_impl(magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >*, std::__1::pair<unsigned long, unsigned char>)
Line
Count
Source
506
2.04k
    constexpr reference_impl(parent_t parent, std::pair<std::size_t, base_type> ix) noexcept : parent(parent), num_index(std::get<0>(ix)), bit_index(std::get<1>(ix)) {}
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> > const*>::reference_impl(magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> > const*, std::__1::pair<unsigned long, unsigned char>)
Line
Count
Source
506
512
    constexpr reference_impl(parent_t parent, std::pair<std::size_t, base_type> ix) noexcept : parent(parent), num_index(std::get<0>(ix)), bit_index(std::get<1>(ix)) {}
507
508
   public:
509
2.04k
    constexpr reference_impl& operator=(bool v) noexcept {
510
2.04k
      if (v) {
511
2.04k
        parent->a[num_index] |= bit_index;
512
2.04k
      } else {
513
0
        parent->a[num_index] &= ~bit_index;
514
0
      }
515
2.04k
      return *this;
516
2.04k
    }
517
518
    constexpr reference_impl& operator=(const reference_impl& v) noexcept {
519
      if (this == &v) {
520
        return *this;
521
      }
522
      *this = static_cast<bool>(v);
523
      return *this;
524
    }
525
526
2.04k
    [[nodiscard]] constexpr explicit operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; }
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >*>::operator bool() const
Line
Count
Source
526
1.53k
    [[nodiscard]] constexpr explicit operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; }
magic_enum_fuzzer.cc:magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> >::reference_impl<magic_enum::containers::bitset<LLVMFuzzerTestOneInput::FuzzEnum, magic_enum::containers::detail::indexing<LLVMFuzzerTestOneInput::FuzzEnum, std::__1::less<LLVMFuzzerTestOneInput::FuzzEnum>, void> > const*>::operator bool() const
Line
Count
Source
526
512
    [[nodiscard]] constexpr explicit operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; }
527
528
    [[nodiscard]] constexpr bool operator~() const noexcept { return !static_cast<bool>(*this); }
529
530
    constexpr reference_impl& flip() noexcept {
531
      *this = ~*this;
532
      return *this;
533
    }
534
  };
535
536
  template <typename T>
537
  [[nodiscard]] constexpr T to_(detail::raw_access_t) const {
538
    T res{};
539
    T flag{1};
540
    for (std::size_t i = 0; i < size(); ++i, flag <<= 1) {
541
      if (const_reference{this, i}) {
542
        if (i >= sizeof(T) * 8) {
543
          MAGIC_ENUM_THROW(std::overflow_error("magic_enum::containers::bitset::to: Cannot represent enum in this type"));
544
        }
545
        res |= flag;
546
      }
547
    }
548
    return res;
549
  }
550
551
 public:
552
  using index_type = Index;
553
  using container_type = std::array<base_type, base_type_count>;
554
  using reference = reference_impl<>;
555
  using const_reference = reference_impl<const bitset*>;
556
557
1.53k
  constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept : a{{}} {}
558
559
  constexpr explicit bitset(detail::raw_access_t, unsigned long long val) : a{{}} {
560
    unsigned long long bit{1};
561
    for (std::size_t i = 0; i < (sizeof(val) * 8); ++i, bit <<= 1) {
562
      if ((val & bit) > 0) {
563
        if (i >= enum_count<E>()) {
564
          MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw number"));
565
        }
566
567
        reference{this, i} = true;
568
      }
569
    }
570
  }
571
572
  constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char_type zero = static_cast<char_type>('0'), char_type one = static_cast<char_type>('1'))
573
      : a{{}} {
574
    std::size_t i = 0;
575
    for (auto c : sv.substr(pos, n)) {
576
      if (c == one) {
577
        if (i >= enum_count<E>()) {
578
          MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw string"));
579
        }
580
        reference{this, i} = true;
581
      } else if (c != zero) {
582
        MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized character in raw string"));
583
      }
584
      ++i;
585
    }
586
  }
587
588
  constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{0}, char_type zero = static_cast<char_type>('0'), char_type one = static_cast<char_type>('1'))
589
      : bitset(string_view{str, (std::min)(std::char_traits<char_type>::length(str), n)}, 0, n, zero, one) {}
590
591
  constexpr bitset(std::initializer_list<E> starters) : a{{}} {
592
    if constexpr (magic_enum::detail::subtype_v<E> == magic_enum::detail::enum_subtype::flags) {
593
      for (auto& f : starters) {
594
        *this |= bitset(f);
595
      }
596
    } else {
597
      for (auto& f : starters) {
598
        set(f);
599
      }
600
    }
601
  }
602
  template <typename V, std::enable_if_t<std::is_same_v<V, E> && magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, int> = 0>
603
  constexpr explicit bitset(V starter) : a{{}} {
604
    auto u = enum_underlying(starter);
605
    for (E v : enum_values<E>()) {
606
      if (auto ul = enum_underlying(v); (ul & u) != 0) {
607
        u &= ~ul;
608
        (*this)[v] = true;
609
      }
610
    }
611
    if (u != 0) {
612
      MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in flag"));
613
    }
614
  }
615
616
  template <typename Cmp = std::equal_to<>>
617
  constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char_type sep = static_cast<char_type>('|')) {
618
    for (std::size_t to = 0; (to = magic_enum::detail::find(sv, sep)) != string_view::npos; sv.remove_prefix(to + 1)) {
619
      if (auto v = enum_cast<E>(sv.substr(0, to), cmp)) {
620
        set(v);
621
      } else {
622
        MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string"));
623
      }
624
    }
625
    if (!sv.empty()) {
626
      if (auto v = enum_cast<E>(sv, cmp)) {
627
        set(v);
628
      } else {
629
        MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string"));
630
      }
631
    }
632
  }
633
634
  [[nodiscard]] friend constexpr bool operator==(const bitset& lhs, const bitset& rhs) noexcept { return detail::equal(lhs.a, rhs.a); }
635
636
  [[nodiscard]] friend constexpr bool operator!=(const bitset& lhs, const bitset& rhs) noexcept { return !detail::equal(lhs.a, rhs.a); }
637
638
512
  [[nodiscard]] constexpr bool operator[](E pos) const {
639
512
    auto i = index_type::at(pos);
640
512
    return MAGIC_ENUM_ASSERT(i), static_cast<bool>(const_reference(this, *i));
641
512
  }
642
643
1.53k
  [[nodiscard]] constexpr reference operator[](E pos) {
644
1.53k
    auto i = index_type::at(pos);
645
1.53k
    return MAGIC_ENUM_ASSERT(i), reference{this, *i};
646
1.53k
  }
647
648
  constexpr bool test(E pos) const {
649
    if (auto i = index_type::at(pos)) {
650
      return static_cast<bool>(const_reference(this, *i));
651
    }
652
    MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::test: Unrecognized position"));
653
  }
654
655
512
  [[nodiscard]] constexpr bool all() const noexcept {
656
512
    if constexpr (base_type_count == 0) {
657
512
      return true;
658
512
    }
659
660
512
    for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) {
661
0
      auto check = ~a[i];
662
0
      if (check) {
663
0
        return false;
664
0
      }
665
0
    }
666
667
512
    if constexpr (not_interested > 0) {
668
512
      return a[base_type_count - 1] == last_value_max;
669
512
    }
670
512
  }
671
672
1.02k
  [[nodiscard]] constexpr bool any() const noexcept {
673
1.02k
    for (auto& v : a) {
674
1.02k
      if (v > 0) {
675
1.02k
        return true;
676
1.02k
      }
677
1.02k
    }
678
0
    return false;
679
1.02k
  }
680
681
512
  [[nodiscard]] constexpr bool none() const noexcept { return !any(); }
682
683
512
  [[nodiscard]] constexpr std::size_t count() const noexcept {
684
512
    std::size_t c = 0;
685
512
    for (auto& v : a) {
686
512
      c += detail::popcount(v);
687
512
    }
688
512
    return c;
689
512
  }
690
691
512
  [[nodiscard]] constexpr std::size_t size() const noexcept { return enum_count<E>(); }
692
693
  [[nodiscard]] constexpr std::size_t max_size() const noexcept { return enum_count<E>(); }
694
695
  constexpr bitset& operator&=(const bitset& other) noexcept {
696
    for (std::size_t i = 0; i < base_type_count; ++i) {
697
      a[i] &= other.a[i];
698
    }
699
    return *this;
700
  }
701
702
  constexpr bitset& operator|=(const bitset& other) noexcept {
703
    for (std::size_t i = 0; i < base_type_count; ++i) {
704
      a[i] |= other.a[i];
705
    }
706
    return *this;
707
  }
708
709
  constexpr bitset& operator^=(const bitset& other) noexcept {
710
    for (std::size_t i = 0; i < base_type_count; ++i) {
711
      a[i] ^= other.a[i];
712
    }
713
    return *this;
714
  }
715
716
  [[nodiscard]] constexpr bitset operator~() const noexcept {
717
    bitset res;
718
    for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) {
719
      res.a[i] = ~a[i];
720
    }
721
722
    if constexpr (not_interested > 0) {
723
      res.a[base_type_count - 1] = ~a[base_type_count - 1] & last_value_max;
724
    }
725
    return res;
726
  }
727
728
  constexpr bitset& set() noexcept {
729
    for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) {
730
      a[i] = ~base_type{0};
731
    }
732
733
    if constexpr (not_interested > 0) {
734
      a[base_type_count - 1] = last_value_max;
735
    }
736
    return *this;
737
  }
738
739
512
  constexpr bitset& set(E pos, bool value = true) {
740
512
    if (auto i = index_type::at(pos)) {
741
512
      reference{this, *i} = value;
742
512
      return *this;
743
512
    }
744
512
    MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::set: Unrecognized position"));
745
512
  }
746
747
512
  constexpr bitset& reset() noexcept { return *this = bitset{}; }
748
749
  constexpr bitset& reset(E pos) {
750
    if (auto i = index_type::at(pos)) {
751
      reference{this, *i} = false;
752
      return *this;
753
    }
754
    MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::reset: Unrecognized position"));
755
  }
756
757
  constexpr bitset& flip() noexcept { return *this = ~*this; }
758
759
  [[nodiscard]] friend constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept {
760
    bitset cp = lhs;
761
    cp &= rhs;
762
    return cp;
763
  }
764
765
  [[nodiscard]] friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept {
766
    bitset cp = lhs;
767
    cp |= rhs;
768
    return cp;
769
  }
770
771
  [[nodiscard]] friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept {
772
    bitset cp = lhs;
773
    cp ^= rhs;
774
    return cp;
775
  }
776
777
  template <typename V = E>
778
  [[nodiscard]] constexpr explicit operator std::enable_if_t<magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, E>() const {
779
    E res{};
780
    for (const auto& e : enum_values<E>()) {
781
      if (test(e)) {
782
        res |= e;
783
      }
784
    }
785
    return res;
786
  }
787
788
  [[nodiscard]] string to_string(char_type sep = static_cast<char_type>('|')) const {
789
    string name;
790
791
    for (const auto& e : enum_values<E>()) {
792
      if (test(e)) {
793
        if (!name.empty()) {
794
          name.append(1, sep);
795
        }
796
        auto n = enum_name(e);
797
        name.append(n.data(), n.size());
798
      }
799
    }
800
    return name;
801
  }
802
803
  [[nodiscard]] string to_string(detail::raw_access_t, char_type zero = static_cast<char_type>('0'), char_type one = static_cast<char_type>('1')) const {
804
    string name;
805
    name.reserve(size());
806
    for (std::size_t i = 0; i < size(); ++i) {
807
      name.append(1, const_reference{this, i} ? one : zero);
808
    }
809
    return name;
810
  }
811
812
  [[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { return to_<unsigned long long>(raw); }
813
814
  [[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { return to_<unsigned long>(raw); }
815
816
  friend std::ostream& operator<<(std::ostream& o, const bitset& bs) { return o << bs.to_string(); }
817
818
  friend std::istream& operator>>(std::istream& i, bitset& bs) {
819
    string s;
820
    if (i >> s; !s.empty()) {
821
      bs = bitset(string_view{s});
822
    }
823
    return i;
824
  }
825
826
 private:
827
  container_type a;
828
};
829
830
template <typename V, int = 0>
831
explicit bitset(V starter) -> bitset<V>;
832
833
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
834
//                                                           SET                                                             //
835
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
836
template <typename E, typename Cmp = std::less<E>>
837
class set {
838
  using index_type = detail::indexing<E, Cmp>;
839
  struct Getter {
840
    constexpr const E& operator()(const set*, const E* p) const noexcept { return *p; }
841
  };
842
  struct Predicate {
843
512
    constexpr bool operator()(const set* h, const E* e) const noexcept { return h->a[*e]; }
844
  };
845
846
 public:
847
  using container_type = bitset<E, index_type>;
848
  using key_type = E;
849
  using value_type = E;
850
  using size_type = std::size_t;
851
  using difference_type = std::ptrdiff_t;
852
  using key_compare = Cmp;
853
  using value_compare = Cmp;
854
  using reference = value_type&;
855
  using const_reference = const value_type&;
856
  using pointer = value_type*;
857
  using const_pointer = const value_type*;
858
  using iterator = detail::FilteredIterator<const set*, const E*, Getter, Predicate>;
859
  using const_iterator = detail::FilteredIterator<const set*, const E*, Getter, Predicate>;
860
  using reverse_iterator = std::reverse_iterator<iterator>;
861
  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
862
863
  constexpr set() noexcept = default;
864
865
  template <typename InputIt>
866
  constexpr set(InputIt first, InputIt last) {
867
    while (first != last) {
868
      insert(*first++);
869
    }
870
  }
871
872
512
  constexpr set(std::initializer_list<E> ilist) {
873
1.02k
    for (auto e : ilist) {
874
1.02k
      insert(e);
875
1.02k
    }
876
512
  }
877
  template <typename V, std::enable_if_t<std::is_same_v<V, E> && magic_enum::detail::subtype_v<V> == magic_enum::detail::enum_subtype::flags, int> = 0>
878
  constexpr explicit set(V starter) {
879
    auto u = enum_underlying(starter);
880
    for (E v : enum_values<E>()) {
881
      if ((enum_underlying(v) & u) != 0) {
882
        insert(v);
883
      }
884
    }
885
  }
886
887
  constexpr set(const set&) noexcept = default;
888
  constexpr set(set&&) noexcept = default;
889
890
  constexpr set& operator=(const set&) noexcept = default;
891
  constexpr set& operator=(set&&) noexcept = default;
892
  constexpr set& operator=(std::initializer_list<E> ilist) {
893
    for (auto e : ilist) {
894
      insert(e);
895
    }
896
  }
897
898
  constexpr const_iterator begin() const noexcept {
899
    return const_iterator{this, index_type::begin(), index_type::end(), index_type::begin()};
900
  }
901
902
0
  constexpr const_iterator end() const noexcept {
903
0
    return const_iterator{this, index_type::begin(), index_type::end(), index_type::end()};
904
0
  }
905
906
  constexpr const_iterator cbegin() const noexcept { return begin(); }
907
908
  constexpr const_iterator cend() const noexcept { return end(); }
909
910
  constexpr const_reverse_iterator rbegin() const noexcept { return {end()}; }
911
912
  constexpr const_reverse_iterator rend() const noexcept { return {begin()}; }
913
914
  constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
915
916
  constexpr const_reverse_iterator crend() const noexcept { return rend(); }
917
918
512
  [[nodiscard]] constexpr bool empty() const noexcept { return s == 0; }
919
920
512
  [[nodiscard]] constexpr size_type size() const noexcept { return s; }
921
922
  [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); }
923
924
512
  constexpr void clear() noexcept {
925
512
    a.reset();
926
512
    s = 0;
927
512
  }
928
929
1.53k
  constexpr std::pair<iterator, bool> insert(const value_type& value) noexcept {
930
1.53k
    if (auto i = index_type::at(value)) {
931
1.53k
      typename container_type::reference ref = a[value];
932
1.53k
      bool r = !ref;
933
1.53k
      if (r) {
934
1.53k
        ref = true;
935
1.53k
        ++s;
936
1.53k
      }
937
938
1.53k
      return {iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}, r};
939
1.53k
    }
940
0
    return {end(), false};
941
1.53k
  }
942
943
512
  constexpr std::pair<iterator, bool> insert(value_type&& value) noexcept { return insert(value); }
944
945
  constexpr iterator insert(const_iterator, const value_type& value) noexcept { return insert(value).first; }
946
947
  constexpr iterator insert(const_iterator hint, value_type&& value) noexcept { return insert(hint, value); }
948
949
  template <typename InputIt>
950
  constexpr void insert(InputIt first, InputIt last) noexcept {
951
    while (first != last) {
952
      insert(*first++);
953
    }
954
  }
955
956
  constexpr void insert(std::initializer_list<value_type> ilist) noexcept {
957
    for (auto v : ilist) {
958
      insert(v);
959
    }
960
  }
961
962
  template <typename... Args>
963
  constexpr std::pair<iterator, bool> emplace(Args&&... args) noexcept {
964
    return insert({std::forward<Args>(args)...});
965
  }
966
967
  template <typename... Args>
968
  constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept {
969
    return emplace(std::forward<Args>(args)...).first;
970
  }
971
972
  constexpr iterator erase(const_iterator pos) noexcept {
973
    erase(*pos++);
974
    return pos;
975
  }
976
977
  constexpr iterator erase(const_iterator first, const_iterator last) noexcept {
978
    while ((first = erase(first)) != last) {
979
    }
980
    return first;
981
  }
982
983
  constexpr size_type erase(const key_type& key) noexcept {
984
    typename container_type::reference ref = a[key];
985
    bool res = ref;
986
    if (res) {
987
      --s;
988
    }
989
    ref = false;
990
    return res;
991
  }
992
993
  template <typename K, typename KC = key_compare>
994
  constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> erase(K&& x) noexcept {
995
    size_type c = 0;
996
    for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last;) {
997
      c += erase(*first++);
998
    }
999
    return c;
1000
  }
1001
1002
  void swap(set& other) noexcept {
1003
    set cp = *this;
1004
    *this = other;
1005
    other = cp;
1006
  }
1007
1008
  [[nodiscard]] constexpr size_type count(const key_type& key) const noexcept { return index_type::at(key) && a[key]; }
1009
1010
  template <typename K, typename KC = key_compare>
1011
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> count(const K& x) const {
1012
    size_type c = 0;
1013
    for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) {
1014
      c += count(*first);
1015
    }
1016
    return c;
1017
  }
1018
1019
  [[nodiscard]] constexpr const_iterator find(const key_type& key) const noexcept {
1020
    if (auto i = index_type::at(key); i && a.test(key)) {
1021
      return const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)};
1022
    }
1023
    return end();
1024
  }
1025
1026
  template <typename K, typename KC = key_compare>
1027
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> find(const K& x) const {
1028
    for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) {
1029
      if (a.test(*first)) {
1030
        return find(*first);
1031
      }
1032
    }
1033
    return end();
1034
  }
1035
1036
  [[nodiscard]] constexpr bool contains(const key_type& key) const noexcept { return count(key); }
1037
1038
  template <typename K, typename KC = key_compare>
1039
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, bool> contains(const K& x) const noexcept {
1040
    return count(x) > 0;
1041
  }
1042
1043
  [[nodiscard]] constexpr std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const noexcept { return {lower_bound(key), upper_bound(key)}; }
1044
1045
  template <typename K, typename KC = key_compare>
1046
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, std::pair<const_iterator, const_iterator>> equal_range(const K& x) const noexcept {
1047
    return {lower_bound(x), upper_bound(x)};
1048
  }
1049
1050
  [[nodiscard]] constexpr const_iterator lower_bound(const key_type& key) const noexcept {
1051
    if (auto i = index_type::at(key)) {
1052
      auto it = const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)};
1053
      return a.test(key) ? it : std::next(it);
1054
    }
1055
    return end();
1056
  }
1057
1058
  template <typename K, typename KC = key_compare>
1059
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> lower_bound(const K& x) const noexcept {
1060
    auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{});
1061
    return first != last ? lower_bound(*first) : end();
1062
  }
1063
1064
  [[nodiscard]] constexpr const_iterator upper_bound(const key_type& key) const noexcept {
1065
    if (auto i = index_type::at(key)) {
1066
      return std::next(const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)});
1067
    }
1068
    return end();
1069
  }
1070
1071
  template <typename K, typename KC = key_compare>
1072
  [[nodiscard]] constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> upper_bound(const K& x) const noexcept {
1073
    auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{});
1074
    return first != last ? upper_bound(*std::prev(last)) : end();
1075
  }
1076
1077
  [[nodiscard]] constexpr key_compare key_comp() const { return {}; }
1078
1079
  [[nodiscard]] constexpr value_compare value_comp() const { return {}; }
1080
1081
  [[nodiscard]] constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept { return lhs.a == rhs.a; }
1082
1083
  [[nodiscard]] constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept { return lhs.a != rhs.a; }
1084
1085
  [[nodiscard]] constexpr friend bool operator<(const set& lhs, const set& rhs) noexcept {
1086
    if (lhs.s < rhs.s) {
1087
      return true;
1088
    }
1089
    if (rhs.s < lhs.s) {
1090
      return false;
1091
    }
1092
1093
    for (auto it = index_type::begin(); it != index_type::end(); ++it) {
1094
      if (auto c = rhs.contains(*it); c != lhs.contains(*it)) {
1095
        return c;
1096
      }
1097
    }
1098
    return false;
1099
  }
1100
1101
  [[nodiscard]] constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept { return !(rhs < lhs); }
1102
1103
  [[nodiscard]] constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept { return rhs < lhs; }
1104
1105
  [[nodiscard]] constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept { return !(lhs < rhs); }
1106
1107
  template <typename Pred>
1108
  size_type erase_if(Pred pred) {
1109
    auto old_size = size();
1110
    for (auto i = begin(), last = end(); i != last;) {
1111
      if (pred(*i)) {
1112
        i = erase(i);
1113
      } else {
1114
        ++i;
1115
      }
1116
    }
1117
    return old_size - size();
1118
  }
1119
1120
 private:
1121
  container_type a;
1122
  std::size_t s = 0;
1123
};
1124
1125
template <typename V, int = 0>
1126
explicit set(V starter) -> set<V>;
1127
1128
} // namespace magic_enum::containers
1129
1130
namespace std {
1131
1132
template <auto I, typename E, typename V, typename Index>
1133
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 {
1134
  return a.a[I];
1135
}
1136
1137
template <auto I, typename E, typename V, typename Index>
1138
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 {
1139
  return std::move(a.a[I]);
1140
}
1141
1142
template <auto I, typename E, typename V, typename Index>
1143
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 {
1144
  return a.a[I];
1145
}
1146
1147
template <auto I, typename E, typename V, typename Index>
1148
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 {
1149
  return std::move(a.a[I]);
1150
}
1151
1152
template <auto Enum, typename E, typename V, typename Index>
1153
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 {
1154
  return a[Enum];
1155
}
1156
1157
template <auto Enum, typename E, typename V, typename Index>
1158
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 {
1159
  return std::move(a[Enum]);
1160
}
1161
1162
template <auto Enum, typename E, typename V, typename Index>
1163
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 {
1164
  return a[Enum];
1165
}
1166
1167
template <auto Enum, typename E, typename V, typename Index>
1168
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 {
1169
  return std::move(a[Enum]);
1170
}
1171
1172
} // namespace std
1173
1174
#endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP