repr 0.1
Reconstructable string representations and more
Loading...
Searching...
No Matches
search.h
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <bit>
4#include <cstddef>
5#include <limits>
6#include <type_traits>
7#include <utility>
8
9#include <librepr/feature.h>
13
14#include "range.h"
15#include "util.h"
16#include "range_list.h"
17#include "accessor.h"
18
19namespace librepr::ctei {
20
21constexpr std::size_t find_first(bool const* array, std::size_t min, std::size_t max, bool value) {
22 for (auto idx = min; idx < max; ++idx) {
23 if (array[idx] == value) {
24 return idx;
25 }
26 }
27 return max;
28}
29
30template <auto array, auto Offset, typename Acc, auto ArrayOffset = 0>
31static consteval auto rangify() {
32 using underlying = decltype(Offset);
33 if constexpr (array.empty()) {
34 return Acc{};
35 } else {
36 constexpr auto first = find_first(array.data(), ArrayOffset, array.size(), true);
37 if constexpr (first == array.size()) {
38 return Acc{};
39 } else {
40 constexpr auto last = find_first(array.data(), first, array.size(), false);
41 return rangify<array, Offset,
42 typename Acc::template add_range<
43 Range<Offset + static_cast<underlying>(first), Offset + static_cast<underlying>(last - 1)>>,
44 last>();
45 }
46 }
47}
48
49template <typename T>
50constexpr T clamp(auto value) {
51 constexpr auto min = std::numeric_limits<T>::min();
52 constexpr auto max = std::numeric_limits<T>::max();
53 if (std::cmp_less(value, min)) {
54 return min;
55 }
56 return std::cmp_less(max, value) ? max : static_cast<T>(value);
57}
58
59#if USING(LIBREPR_COMPILER_CLANG) && __has_warning("-Wenum-constexpr-conversion")
61// https://github.com/llvm/llvm-project/issues/68489
62LIBREPR_WARNING_DISABLE_CLANG("-Wenum-constexpr-conversion")
63#endif
64
65template <typename T>
66 requires std::is_enum_v<T>
67struct Search {
69
70 template <underlying Offset, underlying Max>
71 constexpr static auto search_chunk() {
72 return []<std::size_t... Idx>(std::index_sequence<Idx...>) {
73 return std::array{
74 dump_quick<std::bit_cast<T>(static_cast<underlying>(Idx) + Offset)>()[0] != '(' ...
75 // is_enum_value<T, Offset + Idx>()...
76 };
78 }
79
80 template <underlying Offset, underlying Max>
81 constexpr static auto search_chunk_multi() {
82 auto array = std::array<bool, Max - Offset>{};
83
84 auto list = []<std::size_t... Idx>(std::index_sequence<Idx...>) {
85 return dump_list<std::bit_cast<T>(static_cast<underlying>(Idx) + Offset)...>();
87
88 array[0] = list[0] != '(';
90
91 for (std::size_t idx = 0; idx < list.length(); ++idx) {
92 if (list[idx] == ',') {
93 // TODO check if all compilers insert a space after the comma
94 array[out_idx++] = list[idx + 2] != '(';
95 }
96 }
97 return array;
98 }
99
100 template <underlying Offset, underlying Max, typename Acc = RangeList<>, underlying N = 0>
101 static consteval auto search_range() {
102 if constexpr (N == Max) {
103 return Acc{};
104 } else {
105 constexpr auto index = Offset + N;
107 }
108 }
109
110 template <underlying Offset, underlying Max, typename Acc = RangeList<>>
112
113 template <underlying Offset, underlying Max, typename Acc = RangeList<>>
115
116 template <underlying Offset, underlying Max, typename Acc = RangeList<>>
118
119 template <underlying Offset, underlying Max, typename Acc = RangeList<>>
120 using do_search =
121#if USING(REPR_ENUM_RECURSIVE_SEARCH)
123#elif USING(REPR_ENUM_FAST_SEARCH)
125#else
127#endif
128
129 template <auto Offset, auto Max, auto ChunkSize = REPR_ENUM_CHUNKSIZE, typename Acc = RangeList<>, auto N = 0>
130 static consteval auto search_ranges() {
131 constexpr auto offset = Offset + N * ChunkSize;
132
133 if constexpr (offset >= Max) {
134 return Acc{};
135 } else if constexpr (offset + ChunkSize > Max) {
136 return do_search<offset, Max - offset, Acc>{};
137 } else {
139 }
140 }
141
142 static consteval auto reflected_min() {
143 if constexpr (has_search_range<T>) {
145 }
146
147 if constexpr (std::is_signed_v<underlying>) {
149 } else {
151 }
152 }
153
154 static consteval auto reflected_max() {
155 if constexpr (has_search_range<T>) {
157 }
158
159 if constexpr (std::is_signed_v<underlying>) {
161 } else {
163 }
164 }
165
167 constexpr static int largest_flag_multi() {
168 auto array = std::array<bool, Max>{};
169
170 auto list = []<std::size_t... Idx>(std::index_sequence<Idx...>) {
171 return dump_list<std::bit_cast<T>(static_cast<underlying>(1ULL << Idx))...>();
173
174 array[0] = list[0] != '(';
176
177 for (std::size_t idx = 0; idx < list.length(); ++idx) {
178 if (list[idx] == ',') {
179 // TODO check if all compilers insert a space after the comma
180 array[out_idx++] = list[idx + 2] != '(';
181 }
182 }
183
184 const auto last = std::find(array.rbegin(), array.rend(), true);
185 if (last == array.rend()) {
186 if constexpr (is_enum_value<T, 0>()) {
187 return 0;
188 }
189 return -1;
190 }
191 return std::distance(array.begin(), last.base());
192 }
193
195 constexpr static int largest_flag_chunk() {
196 const auto result = []<std::size_t... Idx>(std::index_sequence<Idx...>) {
197 return std::array{
198 dump_quick<std::bit_cast<T>(static_cast<underlying>(1ULL << Idx))>()[0] != '(' ...};
200
201 const auto last = std::find(result.rbegin(), result.rend(), true);
202 if (last == result.rend()) {
203 if constexpr (is_enum_value<T, 0>()) {
204 return 0;
205 }
206 return -1;
207 }
208 return std::distance(result.begin(), last.base());
209 }
210
212 requires std::is_unsigned_v<underlying>
213 static consteval int largest_flag() {
214 if constexpr (is_enum_value<T, 1ULL << N>()) {
215 return N + 1;
216 }
217
218 if constexpr (N == 0) {
219 if constexpr (is_enum_value<T, 0>()) {
220 return 0;
221 }
222 return -1;
223 } else {
224 return largest_flag<N - 1>();
225 }
226 }
227
228 static consteval auto search() {
229 using enum EnumKind;
230 constexpr auto min = reflected_min();
231 constexpr auto max = reflected_max();
232 using linear_search = decltype(search_ranges<min, max>());
233
234 if constexpr (linear_search::size == 0) {
235 return Accessor<T, Empty>{};
236 } else {
237 if constexpr (std::is_unsigned_v<underlying> && linear_search::is_binary_powers()) {
238// all found values were flag-like so far, try all bits
239#if USING(REPR_ENUM_RECURSIVE_SEARCH)
240 constexpr auto flag_max = largest_flag();
241#elif USING(REPR_ENUM_FAST_SEARCH)
242 constexpr auto flag_max = largest_flag_multi();
243#else
244 constexpr auto flag_max = largest_flag_chunk();
245#endif
246 if constexpr (flag_max == -1) {
247 // something went terribly wrong - none of the powers of 2 are valid values
248 // assume the range was empty to begin with
249 return Accessor<T, Empty>{};
250 } else {
252 }
253 } else {
255 }
256 }
257 }
258};
259
260#if USING(LIBREPR_COMPILER_CLANG) && __has_warning("-Wenum-constexpr-conversion")
262#endif
263
264template <typename T>
265 requires std::is_enum_v<T>
266using dump_enum = decltype(Search<T>::search());
267
268} // namespace librepr::ctei
Definition customization/enum.h:12
#define REPR_ENUM_MAX_UNSIGNED
Definition default.h:66
#define REPR_ENUM_MIN_SIGNED
Definition default.h:54
#define REPR_ENUM_MIN_UNSIGNED
Definition default.h:62
#define REPR_ENUM_MAX_SIGNED
Definition default.h:58
T distance(T... args)
T find(T... args)
T max(T... args)
T min(T... args)
Definition accessor.h:14
constexpr T clamp(auto value)
Definition search.h:50
decltype(Search< T >::search()) dump_enum
Definition search.h:266
EnumKind
Definition enum/util.h:13
constexpr std::size_t find_first(bool const *array, std::size_t min, std::size_t max, bool value)
Definition search.h:21
std::string code_for()
Definition repr:39
Definition customization.h:12
Definition accessor.h:18
Definition search.h:67
search_chunked< Offset, Max, Acc > do_search
Definition search.h:126
static consteval auto reflected_min()
Definition search.h:142
static consteval auto search_range()
Definition search.h:101
static consteval auto search()
Definition search.h:228
decltype(rangify< search_chunk_multi< Offset, Offset+Max >(), Offset, Acc >()) search_fast
Definition search.h:117
static consteval int largest_flag()
Definition search.h:213
static constexpr int largest_flag_chunk()
Definition search.h:195
static consteval auto reflected_max()
Definition search.h:154
decltype(rangify< search_chunk< Offset, Offset+Max >(), Offset, Acc >()) search_chunked
Definition search.h:114
decltype(search_range< Offset, Max, Acc >()) search_recursive
Definition search.h:111
static constexpr int largest_flag_multi()
Definition search.h:167
static constexpr auto search_chunk_multi()
Definition search.h:81
static constexpr auto search_chunk()
Definition search.h:71
static consteval auto search_ranges()
Definition search.h:130
#define LIBREPR_WARNING_DISABLE_CLANG(...)
Definition warning.h:24