7#include "min-cpp-version/cpp17.h"
12#if defined(__cpp_lib_bit_cast)
23 template <
typename... ARGS>
26 return[func = std::move(func)](
auto&&... args)
mutable {
27 if (func) std::exchange(func, {})(std::forward<
decltype(args)>(args)...);
32 template <
typename FUNC>
39 template <
typename T,
typename FUNC>
40 [[nodiscard]]
constexpr auto transformed(std::optional<T>
const& value, FUNC&& func) ->
decltype(std::optional{ func(value.value()) })
42 return value ? std::optional{ func(value.value()) } : std::nullopt;
46 template <
typename T,
typename FUNC>
47 [[nodiscard]]
constexpr auto transformed(std::optional<T>&& value, FUNC&& func) ->
decltype(std::optional{ func(value.value()) })
49 return value ? std::optional{ func(std::move(value).value()) } : std::nullopt;
53 std::optional<T> to_optional(T* value)
noexcept {
return value ? *value : std::nullopt; }
56 std::optional<T> move_to_optional(T* value)
noexcept {
return value ? std::move(*value) : std::nullopt; }
59 template <
typename T> [[nodiscard]]
constexpr auto flattened(std::optional<std::optional<T>>&& value) {
return value ? flatten(std::move(value).value()) : std::nullopt; }
60 template <
typename T> [[nodiscard]]
constexpr auto flattened(std::optional<T>&& value) {
return value; }
61 template <
typename T> [[nodiscard]]
constexpr auto flattened(std::optional<std::optional<T>>
const& value) {
return value ? flatten(value.value()) : std::nullopt; }
62 template <
typename T> [[nodiscard]]
constexpr auto flattened(std::optional<T>
const& value) {
return value; }
73 template <
class... Ts>
struct overloaded : Ts... {
using Ts::operator()...; };
76 #define GHPL_OVERLOAD(...) [&](auto &&... args) -> decltype(auto) { \
77 return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
85 [[nodiscard]]
constexpr auto always_true() {
return [](
auto&& other) {
return true; }; }
87 template <
typename T> [[nodiscard]]
constexpr auto equal_to(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other == val; }; }
88 template <
typename T> [[nodiscard]]
constexpr auto not_equal_to(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other != val; }; }
89 template <
typename T> [[nodiscard]]
constexpr auto less_than(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other < val; }; }
90 template <
typename T> [[nodiscard]]
constexpr auto less_than_or_equal_to(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other <= val; }; }
91 template <
typename T> [[nodiscard]]
constexpr auto greater_than(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other > val; }; }
92 template <
typename T> [[nodiscard]]
constexpr auto greater_than_or_equal_to(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other >= val; }; }
94 template <
typename T> [[nodiscard]]
constexpr auto eq(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other == val; }; }
95 template <
typename T> [[nodiscard]]
constexpr auto ne(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other != val; }; }
96 template <
typename T> [[nodiscard]]
constexpr auto lt(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other < val; }; }
97 template <
typename T> [[nodiscard]]
constexpr auto le(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other <= val; }; }
98 template <
typename T> [[nodiscard]]
constexpr auto gt(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other > val; }; }
99 template <
typename T> [[nodiscard]]
constexpr auto ge(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return other >= val; }; }
101 [[nodiscard]]
constexpr auto is_null()
noexcept {
return [](
auto&& other) {
return other ==
nullptr; }; }
102 [[nodiscard]]
constexpr auto is_not_null()
noexcept {
return [](
auto&& other) {
return other !=
nullptr; }; }
103 [[nodiscard]]
constexpr auto is_empty()
noexcept {
return [](
auto&& other) {
return std::empty(other); }; }
104 [[nodiscard]]
constexpr auto is_not_empty()
noexcept {
return [](
auto&& other) {
return !std::empty(other); }; }
105 [[nodiscard]]
constexpr auto is_true()
noexcept {
return [](
auto&& other) {
return !!other; }; }
106 [[nodiscard]]
constexpr auto is_false()
noexcept {
return [](
auto&& other) {
return !other; }; }
107 template <
typename T> [[nodiscard]]
constexpr auto is_in(T&& val) {
return [val = std::forward<T>(val)](
auto&& other) {
return std::find(std::begin(val), std::end(val), other) != std::end(val); }; }
109 template <
typename... FUNCS>
110 [[nodiscard]]
constexpr auto when_any(FUNCS&&... funcs) {
111 return [funcs = std::make_tuple(std::forward<FUNCS>(funcs)...)](
auto&&... args) {
112 return std::apply([&](
auto&&... funcs) {
113 return (funcs(args...) || ...);
118 template <
typename... FUNCS>
119 [[nodiscard]]
constexpr auto when_all(FUNCS&&... funcs) {
120 return [funcs = std::make_tuple(std::forward<FUNCS>(funcs)...)](
auto&&... args) {
121 return std::apply([&](
auto&&... funcs) {
122 return (funcs(args...) && ...);
127 template <
typename... FUNCS>
128 [[nodiscard]]
constexpr auto when_none(FUNCS&&... funcs) {
129 return [funcs = std::make_tuple(std::forward<FUNCS>(funcs)...)](
auto&&... args) {
130 return std::apply([&](
auto&&... funcs) {
131 return !(funcs(args...) || ...);
150 template <
typename T> [[nodiscard]]
constexpr auto push_back_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.push_back(std::forward<
decltype(val)>(val)); }; }
151 template <
typename T> [[nodiscard]]
constexpr auto emplace_back_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.emplace_back(std::forward<
decltype(val)>(val)); }; }
152 template <
typename T> [[nodiscard]]
constexpr auto push_front_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.push_front(std::forward<
decltype(val)>(val)); }; }
153 template <
typename T> [[nodiscard]]
constexpr auto emplace_front_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.emplace_front(std::forward<
decltype(val)>(val)); }; }
154 template <
typename T> [[nodiscard]]
constexpr auto append_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.append(std::forward<
decltype(val)>(val)); }; }
155 template <
typename T> [[nodiscard]]
constexpr auto insert_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to.insert(std::forward<
decltype(val)>(val)); }; }
157 template <
typename T, GHPL_TYPENAME(std::output_iterator<T>) IT>
158 [[nodiscard]]
constexpr auto output_to(IT&&
to) {
return [
to = std::forward<IT>(
to)](
auto&& val) { *
to++ = std::forward<decltype(val)>(val); }; }
160 template <
typename T> [[nodiscard]]
constexpr auto assign_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to = std::forward<decltype(val)>(val); }; }
161 template <
typename T> [[nodiscard]]
constexpr auto add_to(T&
to)
noexcept {
return [&
to](
auto&& val) {
to += std::forward<decltype(val)>(val); }; }
163 template <
typename T> [[nodiscard]]
constexpr auto stream_from(T& from)
noexcept {
return [&from](
auto&& val) { from >> std::forward<decltype(val)>(val); }; }
167 template <
typename... FUNCS>
168 [[nodiscard]]
constexpr auto call_all(FUNCS&&... funcs)
170 return [funcs = std::make_tuple(std::forward<FUNCS>(funcs)...)](
auto&&... args) {
171 return std::apply([&](
auto&&... funcs) {
172 return (funcs(args...), ...);
177 template <
typename F>
180 return std::forward<F>(f);
184 template <
typename F,
typename ... Fs>
187 return [first = std::forward<F>(f), rest =
call_composed(std::forward<Fs>(
fs)...)](
auto&&... args) {
188 return first(rest(std::forward<
decltype(args)>(args)...));
192 template <
typename F>
195 return std::forward<F>(f);
199 template <
typename F,
typename ... Fs>
202 return [first = std::forward<F>(f), rest =
call_composed(std::forward<Fs>(
fs)...)](
auto&&... args) {
203 return rest(first(std::forward<
decltype(args)>(args)...));
208 template <
typename THEN,
typename IF>
211 return [predicate = std::forward<IF>(predicate),
op = std::forward<THEN>(
op)](
auto&&... args) {
212 if (predicate(args...))
213 op(std::forward<
decltype(args)>(args)...);
218 template <
typename THEN,
typename IF,
typename ELSE_VAL>
219 [[nodiscard]]
constexpr auto call_when(THEN&&
op, IF&& predicate, ELSE_VAL&& elseval)
221 return [predicate = std::forward<IF>(predicate),
op = std::forward<THEN>(
op), elseval = std::forward<ELSE_VAL>(elseval)](
auto&&... args)
222 -> std::common_type_t<
223 decltype(
op(std::forward<
decltype(args)>(args)...)),
224 decltype(std::forward<ELSE_VAL>(elseval))
227 if (predicate(args...))
228 return op(std::forward<
decltype(args)>(args)...);
229 return std::forward<ELSE_VAL>(elseval);
234 template <
typename THEN,
typename IF,
typename ELSE>
237 return [predicate = std::forward<IF>(predicate),
op = std::forward<THEN>(
op), elseop = std::forward<ELSE>(elseop)](
auto&&... args)
238 -> std::common_type_t<
239 decltype(
op(std::forward<
decltype(args)>(args)...)),
240 decltype(elseop(std::forward<
decltype(args)>(args)...))
243 if (predicate(args...))
244 return op(std::forward<
decltype(args)>(args)...);
246 return elseop(std::forward<
decltype(args)>(args)...);
255 [[nodiscard]]
constexpr auto identity()
noexcept {
return [](
auto&& val) {
return std::forward<decltype(val)>(val); }; }
256 constexpr auto identity_l = [] (
auto&& val)
noexcept {
return std::forward<decltype(val)>(val); };
258 template <
typename T> [[nodiscard]]
constexpr auto cast_to()
noexcept {
return [](
auto&& val) {
return (T)std::forward<decltype(val)>(val); }; }
259 template <
typename T> [[nodiscard]]
constexpr auto dynamic_cast_to()
noexcept {
return [](
auto&& val) {
return dynamic_cast<T
>(std::forward<decltype(val)>(val)); }; }
260#if defined(__cpp_lib_bit_cast)
261 template <
typename T> [[nodiscard]]
constexpr auto bit_cast_to()
noexcept {
return [](
auto&& val) {
return std::bit_cast<T>(std::forward<
decltype(val)>(val)); }; }
263 template <
typename T> [[nodiscard]]
constexpr auto constructed_as()
noexcept {
return [](
auto&& val) {
return T{ std::forward<decltype(val)>(val) }; }; }
264 [[nodiscard]]
constexpr auto called()
noexcept {
return [](
auto&& val) {
return std::forward<decltype(val)>(val)(); }; }
266 template <
typename T> [[nodiscard]]
constexpr auto added_to(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) + other; }; }
267 template <
typename T> [[nodiscard]]
constexpr auto subtracted_from(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return other - std::forward<decltype(val)>(val); }; }
268 template <
typename T> [[nodiscard]]
constexpr auto decremented_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) - other; }; }
269 template <
typename T> [[nodiscard]]
constexpr auto divided_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) / other; }; }
270 template <
typename T> [[nodiscard]]
constexpr auto overed_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return other / std::forward<decltype(val)>(val); }; }
271 template <
typename T> [[nodiscard]]
constexpr auto modulo_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) % other; }; }
272 template <
typename T> [[nodiscard]]
constexpr auto multiplied_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) * other; }; }
273 [[nodiscard]]
constexpr auto complemented()
noexcept {
return [](
auto&& val) {
return -std::forward<decltype(val)>(val); }; }
275 [[nodiscard]]
constexpr auto negated()
noexcept {
return [](
auto&& val) {
return !std::forward<decltype(val)>(val); }; }
277 [[nodiscard]]
constexpr auto bit_inverted()
noexcept {
return [](
auto&& val) {
return ~std::forward<decltype(val)>(val); }; }
278 template <
typename T> [[nodiscard]]
constexpr auto bit_anded_with(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) & other; }; }
279 template <
typename T> [[nodiscard]]
constexpr auto bit_ored_with(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) | other; }; }
280 template <
typename T> [[nodiscard]]
constexpr auto bit_xored_with(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) ^ other; }; }
281 template <
typename T> [[nodiscard]]
constexpr auto shifted_left_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) << other; }; }
282 template <
typename T> [[nodiscard]]
constexpr auto shifted_right_by(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) >> other; }; }
284 template <
typename T> [[nodiscard]]
constexpr auto field(T&& field_ptr)
noexcept {
285 return [field_ptr = std::forward<T>(field_ptr)](
auto&& val) {
286 using arg_type = remove_cvref_t<
decltype(val)>;
287 if constexpr (std::is_pointer_v<arg_type>)
288 return (std::forward<
decltype(val)>(val)->*field_ptr);
290 return (std::forward<
decltype(val)>(val).*field_ptr);
294#ifdef __cpp_impl_three_way_comparison
295 template <
typename T> [[nodiscard]]
constexpr auto compared_with(T&& other)
noexcept {
return [other = std::forward<T>(other)](
auto&& val) {
return std::forward<decltype(val)>(val) <=> other; }; }
302#define std_call(func) ([](auto&&... vals) { return std::func(std::forward<decltype(vals)>(vals)...); })
305 template <
typename T,
typename FUNC>
315 template <
typename Ret,
typename Arg,
typename = std::enable_if_t<
316 std::is_lvalue_reference_v<Arg> &&
317 !std::is_const_v<std::remove_reference_t<Arg>>&&
318 std::is_default_constructible_v<std::remove_reference_t<Arg>>>
320 constexpr auto detect_first_arg(std::function<Ret(Arg)>) {
321 return type_identity<Arg>{};
323 constexpr auto detect_first_arg(...) {
324 return type_identity<void>{};
329 template <
typename FUNC>
330 GHPL_REQUIRES((!std::is_void_v<
typename decltype(detail::detect_first_arg(std::function{ std::declval<FUNC>() }))::type>&&
requires { std::function{ std::declval<FUNC>() }; }))
335 using arg_type =
typename decltype(detail::detect_first_arg(std::function{ std::declval<FUNC>() }))::type;
336 static_assert(!std::is_void_v<arg_type>,
"function must take a single l-value reference argument");
337 std::remove_reference_t<arg_type> result{};
345 template <
typename T,
typename... ARGS>
346 [[nodiscard]]
constexpr std::optional<T>
optional_get(std::variant<ARGS...>
const& var)
noexcept
348 if (std::holds_alternative<T>(var))
349 return std::get<T>(var);
366 template<
class... T>
struct mp_list {};
368 template <
typename T,
typename... TT>
369 constexpr bool mp_set_contains() {
return (std::is_same_v<TT, T> || ...); }
370 template <
typename T,
typename... TT>
371 constexpr bool mp_set_contains(mp_list<TT...>) {
return (std::is_same_v<TT, T> || ...); }
373 template <
typename...TT,
typename T>
374 constexpr auto operator&(mp_list<TT...>, mp_list<T>) ->
375 std::conditional_t<(std::is_same_v<TT, T> || ...),
379 template <
typename...TT,
typename T>
380 constexpr auto operator+(mp_list<TT...>, mp_list<T>) -> mp_list<TT..., T>;
382 template <
template <
typename...>
typename TMPL,
typename... Ts>
383 constexpr auto mp_apply(mp_list<Ts...>) -> TMPL<Ts...>;
393 template<
template<
class...>
class L,
class... T>
394 constexpr auto mp_make_unique(L<T...>) ->
decltype(mp_apply<L>((mp_list<>{} & ... & mp_list<T>{})));
398 template <
typename FUNC,
typename... Ts>
399 constexpr auto transformed(std::variant<Ts...>
const& var, FUNC&& func)
401 using result_type =
decltype(detail::mp_make_unique(std::variant<
402 decltype(func(std::declval<Ts>()))...
404 return std::visit([&func](
auto&& val) -> result_type {
return result_type(func(std::forward<
decltype(val)>(val))); }, var);
411 template <
typename... Ts1,
typename... Ts2>
412 constexpr auto cat_lists(mp_list<Ts1...>, mp_list<Ts2...>) -> mp_list<Ts1..., Ts2...>;
414 template <
typename... Ts>
415 constexpr auto flatten(mp_list<std::variant<Ts...>>) ->
decltype(flatten(mp_list<Ts...>{}));
417 template <
typename T>
418 constexpr auto flatten(mp_list<T>) -> mp_list<T>;
420 template <
typename T,
typename T2,
typename... Ts>
421 constexpr auto flatten(mp_list<T, T2, Ts...>)
422 ->
decltype(cat_lists(cat_lists(flatten(mp_list<T>{}), flatten(mp_list<T2>{})), mp_list<Ts... >{}));
424 template <
typename... Ts>
425 using flattened =
decltype(flatten(mp_list<Ts...>{}));
427 template <
template <
typename...>
typename TMPL,
typename T1,
typename T2,
typename... Ts>
428 constexpr auto mp_apply_or_single(mp_list<T1, T2, Ts...>) -> TMPL<T1, T2, Ts...>;
429 template <
template <
typename...>
typename TMPL,
typename T>
430 constexpr auto mp_apply_or_single(mp_list<T>) -> T;
433 template <
typename T,
typename... Ts>
434 using variant_flat_t =
decltype(mp_apply_or_single<std::variant>(detail::mp_make_unique(flattened<T, Ts...>{})));
437 template <
typename... TYPES>
438 struct convertible_to_variant
440 std::variant<TYPES...> value;
442 convertible_to_variant() noexcept = delete;
443 convertible_to_variant(convertible_to_variant&&) noexcept = default;
444 convertible_to_variant& operator=(convertible_to_variant&&) noexcept = default;
446 convertible_to_variant(std::variant<TYPES...> val) noexcept : value(std::move(val)) {}
447 convertible_to_variant& operator=(std::variant<TYPES...> val)
noexcept { std::swap(value, val);
return *
this; }
449 template <
typename... OTHER_TYPES,
450 typename = std::enable_if_t<!std::is_same_v<
decltype(value), std::variant<OTHER_TYPES...>>>,
451 typename = std::enable_if_t<(detail::mp_set_contains<TYPES, OTHER_TYPES...>() && ...)>
453 operator std::variant<OTHER_TYPES...>() &&
noexcept
455 static_assert((detail::mp_set_contains<TYPES, OTHER_TYPES...>() && ...),
"not every type in source variant is present in destination variant");
457 return std::visit(overloaded{
458 [](TYPES&& val) -> std::variant<OTHER_TYPES...> {
459 return std::variant<OTHER_TYPES...>(std::move(val));
461 }, std::move(value));
464 operator std::variant<TYPES...>() &&
noexcept {
465 return std::move(value);
469 template <
typename... TYPES>
470 convertible_to_variant(std::variant<TYPES...>) -> convertible_to_variant<TYPES...>;
471 template <
typename T>
472 convertible_to_variant(T) -> convertible_to_variant<remove_cvref_t<T>>;
476 template <
typename FUNC,
typename... Ts>
479 using result_type =
decltype(detail::mp_make_unique(
480 detail::variant_flat_t<
decltype(func(std::declval<Ts>()))...>{}
482 return std::visit([&func](
auto&& val) -> result_type {
return convertible_to_variant(func(std::forward<
decltype(val)>(val))); }, var);
constexpr auto transformed_flattened(std::variant< Ts... > const &var, FUNC &&func)
Returns a new variant transformed by func, flattened.
constexpr auto make_single_time_function(std::function< void(ARGS...)> func)
Returns a function that calls func when invoked, but only the first time.
constexpr T resulting(FUNC &&func)
Returns a new T transformed by func.
constexpr auto transformed(std::optional< T > const &value, FUNC &&func) -> decltype(std::optional{ func(value.value()) })
Pre C++23 transform/fmap.
constexpr std::optional< T > optional_get(std::variant< ARGS... > const &var) noexcept
Variant operations.
constexpr CONTAINER to(RANGE &&range, TYPES &&... args)
to<container>();
The below code is based on Sun's libm library code, which is licensed under the following license:
Contains functions that return functors that perform an operation without output; appropriate for fun...
constexpr auto call_when(THEN &&op, IF &&predicate)
Acts as if (predicate(args...)) op(args...);.
constexpr auto call_piped(F &&f)
forwarding F can throw
constexpr auto call_composed(F &&f)
forwarding F can throw
constexpr auto call_when_else(THEN &&op, IF &&predicate, ELSE &&elseop)
Acts as if (predicate(args...)) return op(args...); else return elseop(args...);.
constexpr auto call_all(FUNCS &&... funcs)
For funcs a, b, c, calls them as return (a(args...), b(args...), c(args...)).
Contains functions that return predicates; appropriate for functions like std::all_of.
Contains functions that return functors which transform and return their inputs somehow; appropriate ...
Primary namespace for everything in this library.
GHPL_REQUIRES(std::is_enum_v< ENUM_TYPE >) struct circular_enum
TODO: Finish this.
Can be used to create an object with an overload set of operator() if constructed from multiple lambd...