opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
enum_helpers.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <iterator>
5#include <optional>
6#include <type_traits>
7#include <utility>
8
9namespace osc
10{
11 // satisfied if an enum contains a `NUM_OPTIONS` member
12 //
13 // - enums that use `NUM_OPTIONS` are assumed to have their first value at
14 // zero, their last value at `NUM_OPTIONS-1`, and all options one-after-another
15 // with no gaps
16 template<typename TEnum>
17 concept DenselyPackedOptionsEnum = requires(TEnum v) {
18 requires std::is_enum_v<TEnum>;
19 TEnum::NUM_OPTIONS;
20 };
21
22 // returns the number of options in `TEnum` (effectively, returns `NUM_OPTIONS`)
23 template<DenselyPackedOptionsEnum TEnum>
24 constexpr size_t num_options()
25 {
26 return static_cast<size_t>(TEnum::NUM_OPTIONS);
27 }
28
29 // a compile-time list of options in `TEnum`
30 //
31 // - the caller must instantiate this template with each option
32 template<DenselyPackedOptionsEnum TEnum, TEnum... TEnumOptions>
33 struct OptionList {
34 static_assert(sizeof...(TEnumOptions) == num_options<TEnum>());
35 };
36
37 // returns the value of `v` cast to a `size_t` (i.e. `v` should probably satisfy
38 // `DenselyPackedOptionsEnum` for this to work
39 template<DenselyPackedOptionsEnum TEnum>
40 constexpr size_t to_index(TEnum v)
41 {
42 return static_cast<size_t>(std::to_underlying(v));
43 }
44
45 // if `pos` is within the range of densely-packed enum options, returns the enum member
46 // that has an integer value equal to `pos`; otherwise, returns `std::nullopt`
47 template<DenselyPackedOptionsEnum TEnum>
48 constexpr std::optional<TEnum> from_index(size_t pos)
49 {
50 if (pos < num_options<TEnum>()) {
51 return static_cast<TEnum>(pos);
52 }
53 else {
54 return std::nullopt;
55 }
56 }
57
58 // an iterable adaptor for a `DenselyPackedOptionsEnum` that, when iterated, emits
59 // each enum option projected via `Proj`
60 template<
61 DenselyPackedOptionsEnum TEnum,
62 typename Proj = std::identity
63 >
65 public:
66 class Iterator {
67 public:
69 using value_type = std::remove_cvref_t<decltype(Proj{}(std::declval<TEnum>()))>;
70 using pointer = void;
72 using iterator_category = std::forward_iterator_tag;
73
74 Iterator() = default;
76 current_{current},
77 proj_{&proj}
78 {}
79
80 friend bool operator==(const Iterator&, const Iterator&) = default;
81
83 {
84 return std::invoke(*proj_, current_);
85 }
86
88 {
89 current_ = static_cast<TEnum>(std::to_underlying(current_) + 1);
90 return *this;
91 }
92
94 {
95 Iterator copy{*this};
96 ++(*this);
97 return copy;
98 }
99 private:
100 TEnum current_ = static_cast<TEnum>(0);
101 const Proj* proj_ = nullptr;
102 };
103
104 using value_type = decltype(Proj{}(std::declval<TEnum>()));
107
109 proj_{proj}
110 {}
111
112 auto front() const { return std::invoke(proj_, static_cast<TEnum>(0)); }
113 auto back() const { return std::invoke(proj_, static_cast<TEnum>(std::to_underlying(TEnum::NUM_OPTIONS)-1)); }
114 Iterator begin() const { return Iterator{proj_, static_cast<TEnum>(0)}; }
115 Iterator end() const { return Iterator{proj_, TEnum::NUM_OPTIONS}; }
116
117 private:
118 Proj proj_;
119 };
120
121 // returns a `DenselyPackedOptionsIterable` that, when iterated, projects each enum value via `proj`
122 template<DenselyPackedOptionsEnum TEnum, typename Proj = std::identity>
127
128 // satisfied if the given enum contains a `NUM_FLAGS` member
129 //
130 // - enums that use `NUM_FLAGS` are assumed to have their first flag at 1<<0, their last
131 // flag at 1<<NUM_FLAGS-1, and all flags one-bit-next-to-the-other (i.e. dense)
132 template<typename TEnum>
133 concept FlagsEnum = requires(TEnum v) {
134 requires std::is_enum_v<TEnum>;
135 requires std::is_unsigned_v<std::underlying_type_t<TEnum>>;
136 TEnum::NUM_FLAGS;
137 };
138
139 // returns the number of flags in `TEnum`
140 template<FlagsEnum TEnum>
141 constexpr size_t num_flags()
142 {
143 return static_cast<size_t>(TEnum::NUM_FLAGS);
144 }
145}
Iterator operator++(int)
Definition enum_helpers.h:93
std::remove_cvref_t< decltype(Proj{}(std::declval< TEnum >()))> value_type
Definition enum_helpers.h:69
Iterator & operator++()
Definition enum_helpers.h:87
std::forward_iterator_tag iterator_category
Definition enum_helpers.h:72
void pointer
Definition enum_helpers.h:70
friend bool operator==(const Iterator &, const Iterator &)=default
value_type operator*() const
Definition enum_helpers.h:82
Iterator(const Proj &proj, TEnum current)
Definition enum_helpers.h:75
value_type reference
Definition enum_helpers.h:71
ptrdiff_t difference_type
Definition enum_helpers.h:68
Definition enum_helpers.h:64
Iterator end() const
Definition enum_helpers.h:115
Iterator begin() const
Definition enum_helpers.h:114
decltype(Proj{}(std::declval< TEnum >())) value_type
Definition enum_helpers.h:104
constexpr DenselyPackedOptionsIterable(Proj proj={})
Definition enum_helpers.h:108
auto back() const
Definition enum_helpers.h:113
auto front() const
Definition enum_helpers.h:112
Definition enum_helpers.h:17
Definition enum_helpers.h:133
Definition custom_decoration_generator.h:5
constexpr DenselyPackedOptionsIterable< TEnum, Proj > make_option_iterable(Proj &&proj={})
Definition enum_helpers.h:123
constexpr std::optional< TEnum > from_index(size_t pos)
Definition enum_helpers.h:48
constexpr U to(T &&value)
Definition conversion.h:56
constexpr size_t to_index(TEnum v)
Definition enum_helpers.h:40
constexpr size_t num_options()
Definition enum_helpers.h:24
constexpr size_t num_flags()
Definition enum_helpers.h:141
Definition enum_helpers.h:33