@auto_js/utility 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CMakeLists.txt +45 -0
  2. package/LICENSE +13 -0
  3. package/_module.cc +14 -0
  4. package/assertions.cc +32 -0
  5. package/container/mutable_priority_queue.cc +35 -0
  6. package/container/sealed_map.cc +121 -0
  7. package/container/segmented_priority_queue.cc +105 -0
  8. package/container/tinker_queue.cc +73 -0
  9. package/functional/bind.cc +151 -0
  10. package/functional/elide.cc +52 -0
  11. package/functional/flat_tuple.cc +90 -0
  12. package/functional/function_constant.cc +58 -0
  13. package/functional/function_ref.cc +68 -0
  14. package/functional/functional.cc +107 -0
  15. package/functional/regular_return.cc +55 -0
  16. package/include/auto_js/chunk_view.h +363 -0
  17. package/include/auto_js/no_unique_address.h +8 -0
  18. package/memory/autorelease_pool.cc +281 -0
  19. package/memory/comparator.cc +53 -0
  20. package/memory/memory.cc +64 -0
  21. package/memory/noinit_allocator.cc +64 -0
  22. package/meta/algorithm.cc +74 -0
  23. package/package.json +11 -0
  24. package/platform/lockable.cc +261 -0
  25. package/platform/shim/darwin.cc +8 -0
  26. package/platform/stop_token.cc +107 -0
  27. package/platform/timer.cc +175 -0
  28. package/platform/timer.h.cc +36 -0
  29. package/type_traits/function_traits.cc +173 -0
  30. package/type_traits/transform.cc +60 -0
  31. package/type_traits/type_of.cc +72 -0
  32. package/type_traits/type_pack.cc +116 -0
  33. package/type_traits/type_traits.cc +5 -0
  34. package/utility/constant_wrapper.cc +57 -0
  35. package/utility/covariant_value.cc +33 -0
  36. package/utility/facade.cc +126 -0
  37. package/utility/hash.cc +37 -0
  38. package/utility/ranges.cc +55 -0
  39. package/utility/string.cc +328 -0
  40. package/utility/utility.cc +150 -0
  41. package/utility/variant.cc +26 -0
@@ -0,0 +1,175 @@
1
+ module;
2
+ #include <algorithm>
3
+ #include <array>
4
+ #include <chrono>
5
+ #include <functional>
6
+ #include <memory>
7
+ #include <ranges>
8
+ #include <stop_token>
9
+ #include <thread>
10
+ #include <utility>
11
+ #include <vector>
12
+ module util;
13
+ import :functional;
14
+ import :platform.lockable;
15
+ import :platform.timer;
16
+
17
+ namespace util {
18
+
19
+ namespace {
20
+ util::lockable_with<std::weak_ptr<timer_thread>, {.shared = true}> shared_thread;
21
+ }
22
+
23
+ // Internal thread which manages timers
24
+ class timer_thread : util::non_moveable {
25
+ public:
26
+ class timer;
27
+ using clock_type = timer_stop_token::clock_type;
28
+
29
+ timer_thread();
30
+ auto insert(std::stop_source stop_source, clock_type::duration timeout) -> void;
31
+ static auto acquire() -> std::shared_ptr<timer_thread>;
32
+
33
+ private:
34
+ using timer_queue_type = std::vector<timer>;
35
+ using request_type = util::function_ref<auto(timer_queue_type&)->void>;
36
+ using request_queue_type = std::vector<request_type>;
37
+
38
+ template <class Invocable>
39
+ auto dispatch(Invocable invocable, auto&&... args);
40
+
41
+ auto dispatch(request_type request) -> void;
42
+ auto loop(std::stop_token stop_token) -> void;
43
+
44
+ util::lockable_with<request_queue_type, {.interuptable = true, .shared = true}> requests_;
45
+ timer_queue_type timers_;
46
+ std::jthread thread_;
47
+ };
48
+
49
+ // Internal thread-managed timer
50
+ class timer_thread::timer : public util::pointer_facade {
51
+ public:
52
+ explicit timer(clock_type::time_point time_point, std::stop_source&& stop_source) :
53
+ time_point_{time_point},
54
+ stop_source_{std::move(stop_source)} {}
55
+
56
+ auto operator*() & -> std::stop_source& { return stop_source_; }
57
+ auto operator*() const& -> const std::stop_source& { return stop_source_; }
58
+
59
+ [[nodiscard]] auto time_point() const -> clock_type::time_point { return time_point_; }
60
+
61
+ private:
62
+ clock_type::time_point time_point_;
63
+ std::stop_source stop_source_;
64
+ };
65
+
66
+ // ---
67
+
68
+ // `timer_thread`
69
+ timer_thread::timer_thread() :
70
+ thread_{[ & ](std::stop_token stop_token) -> void { loop(stop_token); }} {}
71
+
72
+ auto timer_thread::loop(std::stop_token stop_token) -> void {
73
+ auto lock = requests_.write_waitable(std::not_fn(&request_queue_type::empty));
74
+ while (!stop_token.stop_requested()) {
75
+ // wait for requests or timeout
76
+ const auto has_requests = [ & ]() -> bool {
77
+ if (timers_.empty()) {
78
+ return lock.wait(stop_token);
79
+ } else {
80
+ auto next = timers_.back().time_point();
81
+ return lock.wait(stop_token, next);
82
+ }
83
+ }();
84
+ // dispatch timer requests
85
+ if (has_requests) {
86
+ for (const auto& request : *lock) {
87
+ request(timers_);
88
+ }
89
+ lock->clear();
90
+ lock.notify_all();
91
+ }
92
+ // expire timers
93
+ auto now = clock_type::now();
94
+ auto expired_timer_view =
95
+ std::ranges::reverse_view{timers_} |
96
+ std::views::take_while([ & ](const auto& timer) {
97
+ return timer.time_point() <= now;
98
+ });
99
+ for (auto& timer : expired_timer_view) {
100
+ timer->request_stop();
101
+ timers_.pop_back();
102
+ }
103
+ }
104
+ }
105
+
106
+ auto timer_thread::dispatch(request_type request) -> void {
107
+ requests_.write_notify()->push_back(request);
108
+ constexpr auto cast = [](const request_type& item) -> auto {
109
+ return std::bit_cast<std::array<std::byte, sizeof(request_type)>>(item);
110
+ };
111
+ auto does_not_contain = [ & ](const auto& queue) -> bool {
112
+ return !std::ranges::contains(queue, cast(request), cast);
113
+ };
114
+ requests_.read_waitable(does_not_contain).wait();
115
+ }
116
+
117
+ template <class Invocable>
118
+ auto timer_thread::dispatch(Invocable invocable, auto&&... args) {
119
+ auto implementation = util::regular_return{
120
+ [ invocable = std::move(invocable),
121
+ ... args = std::forward<decltype(args)>(args) ](
122
+ timer_queue_type& queue
123
+ ) mutable -> void {
124
+ return invocable(queue, std::forward<decltype(args)>(args)...);
125
+ }
126
+ };
127
+ using result_type = std::invoke_result_t<decltype(implementation), timer_queue_type&>;
128
+ std::optional<result_type> result;
129
+ auto request = [ & ](timer_queue_type& queue) -> void {
130
+ result = implementation(queue);
131
+ };
132
+ dispatch(request_type{request});
133
+ return *std::move(result).value_or(util::elide{[]() -> result_type {
134
+ std::unreachable();
135
+ }});
136
+ }
137
+
138
+ auto timer_thread::insert(std::stop_source stop_source, clock_type::duration timeout) -> void {
139
+ dispatch([ & ](timer_queue_type& queue) -> void {
140
+ auto time_point = clock_type::now() + timeout;
141
+ constexpr auto projection = [](const timer_thread::timer& timer) -> timer_thread::clock_type::time_point {
142
+ return timer.time_point();
143
+ };
144
+ auto it = std::ranges::upper_bound(queue, time_point, std::greater{}, projection);
145
+ queue.emplace(it, time_point, std::move(stop_source));
146
+ });
147
+ }
148
+
149
+ auto timer_thread::acquire() -> std::shared_ptr<timer_thread> {
150
+ auto acquired = shared_thread.read()->lock();
151
+ if (!acquired) {
152
+ auto lock = shared_thread.write();
153
+ acquired = lock->lock();
154
+ if (!acquired) {
155
+ *lock = acquired = std::make_shared<timer_thread>();
156
+ }
157
+ }
158
+ return acquired;
159
+ }
160
+
161
+ // `timer_stop_token`
162
+ timer_stop_token::timer_stop_token(clock_type::duration duration) :
163
+ thread_{timer_thread::acquire()} {
164
+ thread_->insert(stop_source_, duration);
165
+ }
166
+
167
+ auto timer_stop_token::get_source() const -> const std::stop_source& {
168
+ return stop_source_;
169
+ }
170
+
171
+ auto timer_stop_token::get_token() const -> std::stop_token {
172
+ return stop_source_.get_token();
173
+ }
174
+
175
+ } // namespace util
@@ -0,0 +1,36 @@
1
+ module;
2
+ #include <chrono>
3
+ #include <memory>
4
+ #include <stop_token>
5
+ export module util:platform.timer;
6
+
7
+ namespace util {
8
+
9
+ class timer_thread;
10
+
11
+ // Manages a `std::stop_token` which is stopped after a duration, using a background thread.
12
+ export class timer_stop_token {
13
+ public:
14
+ using clock_type = std::chrono::steady_clock;
15
+
16
+ explicit timer_stop_token(clock_type::duration duration);
17
+
18
+ template <class Rep, class Period>
19
+ explicit timer_stop_token(std::chrono::duration<Rep, Period> duration) :
20
+ timer_stop_token(std::chrono::duration_cast<clock_type::duration>(duration)) {}
21
+
22
+ timer_stop_token(const timer_stop_token&) = delete;
23
+ timer_stop_token(timer_stop_token&&) noexcept = default;
24
+ ~timer_stop_token() = default;
25
+ auto operator=(const timer_stop_token&) -> timer_stop_token& = delete;
26
+ auto operator=(timer_stop_token&&) -> timer_stop_token& = delete;
27
+
28
+ [[nodiscard]] auto get_source() const -> const std::stop_source&;
29
+ [[nodiscard]] auto get_token() const -> std::stop_token;
30
+
31
+ private:
32
+ std::shared_ptr<timer_thread> thread_;
33
+ std::stop_source stop_source_;
34
+ };
35
+
36
+ } // namespace util
@@ -0,0 +1,173 @@
1
+ module;
2
+ #include <concepts>
3
+ #include <type_traits>
4
+ export module util:type_traits.function_traits;
5
+ import :type_traits.transform;
6
+
7
+ namespace util {
8
+
9
+ // Apply the cvref qualifier of `From` to a function signature
10
+ export template <class From, class Fn>
11
+ struct apply_function_cvref;
12
+
13
+ export template <class From, class Fn>
14
+ using apply_function_cvref_t = apply_function_cvref<From, Fn>::type;
15
+
16
+ // Extract the cvref qualifier of a function signature applied to `int`. For example:
17
+ // `auto() const& -> void` == `const int&`
18
+ export template <class Fn>
19
+ struct extract_function_cvref;
20
+
21
+ export template <class Fn>
22
+ using extract_function_cvref_t = extract_function_cvref<Fn>::type;
23
+
24
+ // Remove cvref qualifier from a function signature. Used as a requirement it approximates
25
+ // `std::is_function`, without support for C-style variadic functions.
26
+ export template <class Fn>
27
+ struct remove_function_cvref;
28
+
29
+ export template <class Fn>
30
+ using remove_function_cvref_t = remove_function_cvref<Fn>::type;
31
+
32
+ // Generated specializations for `apply_function_cvref`, `extract_function_cvref`, and `remove_function_cvref`
33
+ // NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
34
+ #define MAKE_CVREF(CV, REF) \
35
+ template <class From, class... Args, bool Nx, class Result> \
36
+ struct apply_function_cvref<CV From REF, auto(Args...) noexcept(Nx)->Result> { \
37
+ using type = auto(Args...) CV REF noexcept(Nx) -> Result; \
38
+ }; \
39
+ template <class... Args, bool Nx, class Result> \
40
+ struct extract_function_cvref<auto(Args...) CV REF noexcept(Nx)->Result> { \
41
+ using type = CV int REF; \
42
+ }; \
43
+ template <class... Args, bool Nx, class Result> \
44
+ struct remove_function_cvref<auto(Args...) CV REF noexcept(Nx)->Result> { \
45
+ using type = auto(Args...) noexcept(Nx) -> Result; \
46
+ };
47
+ // NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
48
+
49
+ MAKE_CVREF(, )
50
+ MAKE_CVREF(, &)
51
+ MAKE_CVREF(, &&)
52
+ MAKE_CVREF(const, )
53
+ MAKE_CVREF(const, &)
54
+ MAKE_CVREF(const, &&)
55
+ MAKE_CVREF(volatile, )
56
+ MAKE_CVREF(volatile, &)
57
+ MAKE_CVREF(volatile, &&)
58
+ MAKE_CVREF(const volatile, )
59
+ MAKE_CVREF(const volatile, &)
60
+ MAKE_CVREF(const volatile, &&)
61
+ #undef MAKE_CVREF
62
+
63
+ // Add the given arguments to the front of a function signature
64
+ template <class Signature, class... Types>
65
+ struct signature_args_push_front;
66
+
67
+ template <class... Args, bool Nx, class Result, class... Types>
68
+ struct signature_args_push_front<auto(Args...) noexcept(Nx)->Result, Types...> {
69
+ using type = auto(Types..., Args...) noexcept(Nx) -> Result;
70
+ };
71
+
72
+ // Given a member function pointer type, extract the required `this` object type
73
+ template <class Function>
74
+ struct member_invocable_type;
75
+
76
+ template <class Function>
77
+ using member_invocable_type_t = member_invocable_type<Function>::type;
78
+
79
+ // Traditional member function pointer
80
+ template <class Type, class Function>
81
+ struct member_invocable_type<Function Type::*>
82
+ : ensure_reference<apply_cvref_t<extract_function_cvref_t<Function>, Type>> {};
83
+
84
+ // Explicit-this member function
85
+ template <class Type, class... Args, bool Nx, class Result>
86
+ struct member_invocable_type<auto (*)(Type, Args...) noexcept(Nx)->Result> {
87
+ using type = Type;
88
+ };
89
+
90
+ // Convert a member function pointer type to a free function type, with the object type as the first
91
+ // parameter
92
+ template <class Type>
93
+ struct unbound_member_function_signature;
94
+
95
+ template <class Type>
96
+ using unbound_member_function_signature_t = unbound_member_function_signature<Type>::type;
97
+
98
+ // Traditional member function pointer
99
+ template <class Type, class Function>
100
+ struct unbound_member_function_signature<Function Type::*>
101
+ : signature_args_push_front<remove_function_cvref_t<Function>, member_invocable_type_t<Function Type::*>> {};
102
+
103
+ // Explicit-this member function
104
+ template <class... Args, bool Nx, class Result>
105
+ struct unbound_member_function_signature<auto (*)(Args...) noexcept(Nx)->Result> {
106
+ using type = auto(Args...) noexcept(Nx) -> Result;
107
+ };
108
+
109
+ // Function signature of any invocable type
110
+ export template <class Function>
111
+ struct function_signature;
112
+
113
+ export template <class Function>
114
+ using function_signature_t = function_signature<Function>::type;
115
+
116
+ template <class Type, class Function>
117
+ struct function_operator_signature;
118
+
119
+ // Function type. `std::decay_t` performs function-to-pointer conversion.
120
+ template <class Function>
121
+ requires requires { typename remove_function_cvref_t<std::remove_pointer_t<std::decay_t<Function>>>; }
122
+ struct function_signature<Function>
123
+ : remove_function_cvref<std::remove_pointer_t<std::decay_t<Function>>> {};
124
+
125
+ // Struct type with `operator()` (lambda, etc)
126
+ template <class Type>
127
+ requires requires { &std::remove_cvref_t<Type>::operator(); }
128
+ struct function_signature<Type>
129
+ : function_operator_signature<Type, unbound_member_function_signature_t<decltype(&std::remove_cvref_t<Type>::operator())>> {};
130
+
131
+ // Member function pointer
132
+ template <class Type, class Function>
133
+ struct function_signature<Function Type::*>
134
+ : unbound_member_function_signature<Function Type::*> {};
135
+
136
+ // Strips the first parameter, which is the unbound object type. Also checks invocability of `Type`,
137
+ // taking into account cvref qualifiers.
138
+ template <class That, class... Args, std::invocable<Args...> Type, bool Nx, class Result>
139
+ struct function_operator_signature<Type, auto(That, Args...) noexcept(Nx)->Result> {
140
+ using type = auto(Args...) noexcept(Nx) -> Result;
141
+ };
142
+
143
+ // Canonicalize the cvref type of an invocable. Functions are value types, invocables are whatever
144
+ // `this` expects.
145
+ export template <class Type>
146
+ struct invocable_type;
147
+
148
+ export template <class Type>
149
+ using invocable_type_t = invocable_type<Type>::type;
150
+
151
+ template <class Function>
152
+ requires requires { typename remove_function_cvref_t<std::remove_pointer_t<std::decay_t<Function>>>; }
153
+ struct invocable_type<Function>
154
+ : remove_function_cvref<std::remove_pointer_t<std::decay_t<Function>>> {};
155
+
156
+ template <class Type>
157
+ requires requires { &std::remove_cvref_t<Type>::operator(); }
158
+ struct invocable_type<Type>
159
+ : member_invocable_type<decltype(&std::remove_cvref_t<Type>::operator())> {};
160
+
161
+ // Result type of a function signature
162
+ export template <class Type>
163
+ struct signature_result;
164
+
165
+ export template <class Type>
166
+ using signature_result_t = signature_result<Type>::type;
167
+
168
+ template <class... Args, bool Nx, class Result>
169
+ struct signature_result<auto(Args...) noexcept(Nx)->Result> {
170
+ using type = Result;
171
+ };
172
+
173
+ } // namespace util
@@ -0,0 +1,60 @@
1
+ module;
2
+ #include <type_traits>
3
+ export module util:type_traits.transform;
4
+
5
+ namespace util {
6
+
7
+ // Add lvalue reference qualifier if it is not already a reference
8
+ export template <class Type>
9
+ struct ensure_reference;
10
+
11
+ export template <class Type>
12
+ using ensure_reference_t = ensure_reference<Type>::type;
13
+
14
+ template <class Type>
15
+ struct ensure_reference {
16
+ using type = Type&;
17
+ };
18
+
19
+ template <class Type>
20
+ struct ensure_reference<Type&&> {
21
+ using type = Type&&;
22
+ };
23
+
24
+ // Copy cvref qualifiers of `From` to `To`
25
+ template <class From, class To>
26
+ struct apply_cvref_impl;
27
+
28
+ export template <class From, class To>
29
+ requires(!(std::is_const_v<To> || std::is_volatile_v<To> || std::is_reference_v<To>))
30
+ struct apply_cvref : apply_cvref_impl<From, To> {};
31
+
32
+ export template <class From, class To>
33
+ using apply_cvref_t = apply_cvref<From, To>::type;
34
+
35
+ template <class From, class To>
36
+ struct apply_cvref_impl : std::type_identity<To> {};
37
+
38
+ // Generated specializations for `apply_ref_impl`
39
+ // NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
40
+ #define MAKE_CVREF(CV, REF) \
41
+ template <class From, class To> \
42
+ struct apply_cvref_impl<CV From REF, To> { \
43
+ using type = CV To REF; \
44
+ }; \
45
+ // NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
46
+
47
+ MAKE_CVREF(, &)
48
+ MAKE_CVREF(, &&)
49
+ MAKE_CVREF(const, )
50
+ MAKE_CVREF(const, &)
51
+ MAKE_CVREF(const, &&)
52
+ MAKE_CVREF(volatile, )
53
+ MAKE_CVREF(volatile, &)
54
+ MAKE_CVREF(volatile, &&)
55
+ MAKE_CVREF(const volatile, )
56
+ MAKE_CVREF(const volatile, &)
57
+ MAKE_CVREF(const volatile, &&)
58
+ #undef MAKE_CVREF
59
+
60
+ } // namespace util
@@ -0,0 +1,72 @@
1
+ module;
2
+ #include <type_traits>
3
+ export module util:type_traits.type_of;
4
+
5
+ namespace util {
6
+
7
+ // "ADL firewall"
8
+ // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2538r0.html#solution
9
+ template <class Type>
10
+ struct hidden {
11
+ struct of {
12
+ using type = Type;
13
+ };
14
+ };
15
+
16
+ template <class Type>
17
+ using hidden_t = hidden<Type>::of;
18
+
19
+ // Metaprogramming helper
20
+ // nb: Intentionally not exported, it should only be used via the `type` variable template.
21
+ template <class Hidden>
22
+ struct type_of;
23
+
24
+ } // namespace util
25
+
26
+ // `util::type_of<Type>{}` alias
27
+ export template <class Type>
28
+ constexpr auto type = util::type_of<util::hidden_t<Type>>{};
29
+
30
+ // Extract the `type` of a value metatype
31
+ export template <auto Type>
32
+ using type_t = decltype(Type)::type;
33
+
34
+ namespace util {
35
+
36
+ // `type_of`
37
+ template <class Hidden>
38
+ struct type_of : std::type_identity<typename Hidden::type> {
39
+ consteval type_of() = default;
40
+
41
+ template <class Type>
42
+ requires std::is_same_v<typename Type::type, typename Hidden::type>
43
+ explicit consteval type_of(Type /*type*/){};
44
+
45
+ // Equality operators
46
+ consteval auto operator==(type_of /*op*/) const -> bool { return true; }
47
+
48
+ template <class Op>
49
+ consteval auto operator==(type_of<Op> /*op*/) const -> bool { return false; }
50
+
51
+ template <class Op>
52
+ consteval auto operator==(Op /*op*/) const -> bool { return std::is_same_v<typename Hidden::type, typename Op::type>; }
53
+
54
+ // `true` represents a valid type
55
+ consteval explicit operator bool() const { return true; }
56
+
57
+ // Invoke result. Returns `std::false_type` if not invocable.
58
+ consteval auto operator()(auto... types) const {
59
+ if constexpr (requires { std::declval<typename Hidden::type>()(std::declval<type_t<types>>()...); }) {
60
+ return type<decltype(std::declval<typename Hidden::type>()(std::declval<type_t<types>>()...))>;
61
+ } else {
62
+ return std::false_type{};
63
+ }
64
+ }
65
+ };
66
+
67
+ export template <class Type>
68
+ consteval auto remove_cvref(Type /*type*/) {
69
+ return type<std::remove_cvref_t<typename Type::type>>;
70
+ }
71
+
72
+ } // namespace util
@@ -0,0 +1,116 @@
1
+ module;
2
+ #include <tuple>
3
+ #include <type_traits>
4
+ export module util:type_traits.type_pack;
5
+ import :type_traits.type_of;
6
+
7
+ namespace util {
8
+
9
+ // Capture a pack of types into a single type
10
+ export template <class... Types>
11
+ struct type_pack;
12
+
13
+ // Prevent `type_pack{type_pack{}}` from flattening itself via copy construction
14
+ template <class... Types>
15
+ type_pack(type_pack<Types...>) -> type_pack<type_pack<Types...>>;
16
+
17
+ // Accept any `T::type` producing structure
18
+ template <class... Types>
19
+ type_pack(Types...) -> type_pack<typename Types::type...>;
20
+
21
+ // ADL-safe pack (not exported)
22
+ template <class... Hidden>
23
+ struct type_pack_of : type_pack<typename Hidden::type...> {
24
+ using type_pack<typename Hidden::type...>::type_pack;
25
+ };
26
+
27
+ // Prevent `type_pack_of{type_pack_of{}}` from flattening itself via copy construction
28
+ template <class... Types>
29
+ type_pack_of(type_pack_of<Types...>) -> type_pack_of<hidden_t<type_pack_of<Types...>>>;
30
+
31
+ // Accept any `T::type` producing structure
32
+ template <class... Types>
33
+ type_pack_of(Types...) -> type_pack_of<hidden_t<typename Types::type>...>;
34
+
35
+ // Capture a pack of types into a single type
36
+ export template <class... Types>
37
+ struct type_pack : std::type_identity<type_pack<Types...>> {
38
+ consteval type_pack() = default;
39
+
40
+ template <class... Args>
41
+ explicit consteval type_pack(Args... /*types*/)
42
+ requires((... && (type<typename Args::type> == type<Types>))) {}
43
+
44
+ [[nodiscard]] consteval auto at(auto index) const { return get<index>(); }
45
+
46
+ // Structured binding accessor
47
+ // Explicit return type causes error:
48
+ // "candidate template ignored: substitution failure [with Index = 0]: invalid index 0 for pack 'Types' of size 0"
49
+ // ...even with `requires(Index < sizeof...(Types))` on the template and/or signature
50
+ template <std::size_t Index>
51
+ [[nodiscard]] consteval auto get() const /* -> std::type_identity<Types... [ Index ]> */ {
52
+ // return {};
53
+ return type<Types...[ Index ]>;
54
+ }
55
+
56
+ // Find the index of the given type, or `size()` if not found
57
+ template <class Type>
58
+ [[nodiscard]] consteval auto find(std::type_identity<Type> subject) const -> std::size_t {
59
+ constexpr auto type_switch = [ = ]<std::size_t Index>(this const auto& self, std::integral_constant<std::size_t, Index> /*index*/) -> std::size_t {
60
+ if constexpr (Index == sizeof...(Types)) {
61
+ return sizeof...(Types);
62
+ } else if constexpr (type<Types...[ Index ]> == subject) {
63
+ return Index;
64
+ } else {
65
+ return self(std::integral_constant<std::size_t, Index + 1>{});
66
+ }
67
+ };
68
+ return type_switch(std::integral_constant<std::size_t, 0>{});
69
+ }
70
+
71
+ [[nodiscard]] consteval auto size() const -> std::size_t { return sizeof...(Types); }
72
+
73
+ // Concatenate two `type_pack`s (into a `type_pack_of`)
74
+ template <class... Right>
75
+ [[nodiscard]] consteval auto operator+(type_pack<Right...> /*right*/) const
76
+ -> type_pack_of<hidden_t<Types>..., hidden_t<Right>...> {
77
+ return {};
78
+ }
79
+
80
+ template <class... Right>
81
+ [[nodiscard]] consteval auto operator==(type_pack<Right...> /*right*/) const -> bool {
82
+ if constexpr (sizeof...(Types) == 0 && sizeof...(Right) == 0) {
83
+ return true;
84
+ } else if constexpr (sizeof...(Types) != sizeof...(Right)) {
85
+ return false;
86
+ } else {
87
+ return ((type<Types> == type<Right>) && ...);
88
+ }
89
+ }
90
+ };
91
+
92
+ } // namespace util
93
+
94
+ namespace std {
95
+
96
+ // `util::type_pack` destructuring specializations
97
+ template <std::size_t Index, class... Types>
98
+ struct tuple_element<Index, util::type_pack<Types...>> {
99
+ using type = util::type_of<util::hidden_t<Types...[ Index ]>>;
100
+ };
101
+
102
+ template <class... Types>
103
+ struct tuple_size<util::type_pack<Types...>> {
104
+ constexpr static auto value = sizeof...(Types);
105
+ };
106
+
107
+ // `util::type_pack_of` destructuring specializations
108
+ template <std::size_t Index, class... Hidden>
109
+ struct tuple_element<Index, util::type_pack_of<Hidden...>>
110
+ : tuple_element<Index, util::type_pack<typename Hidden::type...>> {};
111
+
112
+ template <class... Hidden>
113
+ struct tuple_size<util::type_pack_of<Hidden...>>
114
+ : tuple_size<util::type_pack<typename Hidden::type...>> {};
115
+
116
+ } // namespace std
@@ -0,0 +1,5 @@
1
+ export module util:type_traits;
2
+ export import :type_traits.function_traits;
3
+ export import :type_traits.transform;
4
+ export import :type_traits.type_of;
5
+ export import :type_traits.type_pack;
@@ -0,0 +1,57 @@
1
+ module;
2
+ #include <algorithm>
3
+ export module util:utility.constant_wrapper;
4
+
5
+ // Lifted from P2781R8:
6
+ // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2781r8.html
7
+
8
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-array-to-pointer-decay, modernize-avoid-c-arrays)
9
+ namespace util {
10
+
11
+ template <class Type>
12
+ struct fixed_value {
13
+ using type = Type;
14
+ // NOLINTNEXTLINE(google-explicit-constructor)
15
+ consteval fixed_value(type value) noexcept : value{value} {}
16
+ type value;
17
+ };
18
+
19
+ template <class Type, std::size_t Extent>
20
+ struct fixed_value<Type[ Extent ]> {
21
+ using type = Type[ Extent ];
22
+ // NOLINTNEXTLINE(google-explicit-constructor)
23
+ consteval fixed_value(const type& init) noexcept { std::copy_n(init, Extent, value); }
24
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
25
+ type value;
26
+ };
27
+
28
+ template <class Type, std::size_t Extent>
29
+ fixed_value(const Type (&)[ Extent ]) -> fixed_value<Type[ Extent ]>;
30
+
31
+ export template <fixed_value Value>
32
+ struct constant_wrapper;
33
+
34
+ template <class Value>
35
+ concept constexpr_param = requires { typename constant_wrapper<Value::value>; };
36
+
37
+ struct cw_operators {
38
+ template <constexpr_param Left, constexpr_param Right>
39
+ constexpr friend auto operator==(Left, Right) noexcept -> constant_wrapper<(Left::value == Right::value)> { return {}; }
40
+ };
41
+
42
+ template <fixed_value Value>
43
+ struct constant_wrapper : cw_operators {
44
+ using value_type = decltype(Value)::type;
45
+ using type = constant_wrapper;
46
+
47
+ constexpr static auto& value = Value.value;
48
+
49
+ // NOLINTNEXTLINE(google-explicit-constructor)
50
+ consteval operator const value_type&() const noexcept { return value; }
51
+ };
52
+
53
+ export template <fixed_value Value>
54
+ constexpr auto cw = constant_wrapper<Value>{};
55
+
56
+ } // namespace util
57
+ // NOLINTEND(cppcoreguidelines-pro-bounds-array-to-pointer-decay, modernize-avoid-c-arrays)