C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
functional.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include "boolean.hpp"
26
27#include <concepts>
28#include <cstddef>
29#include <functional>
30#include <optional>
31#include <type_traits>
32#include <utility>
33
34namespace essence::detail {
35 template <typename R, typename T, typename... Args>
37 using std_function_type = std::function<R(Args...)>;
38
39 template <auto Function, std::convertible_to<T> U>
40 requires std::is_member_function_pointer_v<decltype(Function)>
41 && std::is_invocable_r_v<R, decltype(std::mem_fn(Function)), U, Args...>
42 static std::function<R(Args...)> make(U&& obj) {
43 return
44 [&]<typename... Unbound>(Unbound&&... args) { return (obj.*Function)(std::forward<Unbound>(args)...); };
45 }
46 };
47
48 template <typename Function>
50
51#define MAKE_MEMBER_FUNCTION_WRAPPER(...) \
52 template <typename R, typename T, typename... Args> \
53 struct member_function_wrapper<R (T::*)(Args...) __VA_ARGS__> : member_function_wrapper_base<R, T, Args...> {}
54
55 MAKE_MEMBER_FUNCTION_WRAPPER();
56 MAKE_MEMBER_FUNCTION_WRAPPER(const);
57 MAKE_MEMBER_FUNCTION_WRAPPER(volatile);
58 MAKE_MEMBER_FUNCTION_WRAPPER(const volatile);
59 MAKE_MEMBER_FUNCTION_WRAPPER(&);
60 MAKE_MEMBER_FUNCTION_WRAPPER(const&);
61 MAKE_MEMBER_FUNCTION_WRAPPER(volatile&);
62 MAKE_MEMBER_FUNCTION_WRAPPER(const volatile&);
63 MAKE_MEMBER_FUNCTION_WRAPPER(&&);
64 MAKE_MEMBER_FUNCTION_WRAPPER(const&&);
65 MAKE_MEMBER_FUNCTION_WRAPPER(volatile&&);
66 MAKE_MEMBER_FUNCTION_WRAPPER(const volatile&&);
67} // namespace essence::detail
68
69namespace essence {
70 template <auto Function, typename T>
71 requires std::is_member_function_pointer_v<decltype(Function)>
72 auto make_member_function(T&& obj) {
73 return detail::member_function_wrapper<decltype(Function)>::template make<Function>(std::forward<T>(obj));
74 }
75
76 template <typename Function>
78 using type = decltype(std::function{std::declval<Function>()});
79 };
80
81 template <typename Function>
82 requires std::is_member_function_pointer_v<Function>
83 struct make_std_function<Function> {
85 };
86
87 template <typename Function>
88 using make_std_function_t = typename make_std_function<Function>::type;
89
90 template <typename StdFunction>
92
93 template <typename R, typename... Args>
94 struct std_function_traits<std::function<R(Args...)>> {
95 using return_type = R;
96
97 template <std::size_t I>
98 using arg_type = std::tuple_element_t<I, std::tuple<Args...>>;
99
100 static constexpr std::size_t arg_count = sizeof...(Args);
101 };
102
103 template <typename Function>
105 using std_func_type = make_std_function_t<Function>;
106 using return_type = typename std_function_traits<std_func_type>::return_type;
107
108 template <std::size_t I>
109 using arg_type = typename std_function_traits<std_func_type>::template arg_type<I>;
110
111 static constexpr std::size_t arg_count = std_function_traits<std_func_type>::arg_count;
112 };
113
114 template <typename Function>
115 using function_return_type = typename function_traits<Function>::return_type;
116
117 template <typename Function, std::size_t I = 0>
118 using function_arg_type = typename function_traits<Function>::template arg_type<I>;
119
120 template <typename Callable, typename... Args>
121 concept invocable = std::invocable<Callable, Args...>;
122
123 template <typename Callable, typename R, typename... Args>
124 concept invocable_r = std::is_invocable_r_v<R, Callable, Args...>;
125
126 template <typename Callable, typename R, typename... Args>
127 concept invocable_not_r = invocable<Callable, Args...> && !std::same_as<std::invoke_result_t<Callable, Args...>, R>;
128
129 template <typename Callable, typename... Args>
130 concept nothrow_invocable = std::is_nothrow_invocable_v<Callable, Args...>;
131
132 template <typename Callable, typename R, typename... Args>
133 concept nothrow_invocable_r = std::is_nothrow_invocable_r_v<R, Callable, Args...>;
134
135 template <typename Callable, typename R, typename... Args>
137 nothrow_invocable<Callable, Args...> && !std::same_as<std::invoke_result_t<Callable, Args...>, R>;
138
139 template <typename Callable, typename... Args>
140 concept nullptr_or_invocable = std::is_null_pointer_v<std::decay_t<Callable>> || invocable<Callable, Args...>;
141
142 template <typename Callable, typename R, typename... Args>
144 std::is_null_pointer_v<std::decay_t<Callable>> || invocable_r<Callable, R, Args...>;
145
146 template <typename Callable, typename R, typename... Args>
148 std::is_null_pointer_v<std::decay_t<Callable>> || invocable_not_r<Callable, R, Args...>;
149
150 template <typename Callable, typename... Args>
152 std::is_null_pointer_v<std::decay_t<Callable>> || nothrow_invocable<Callable, Args...>;
153
154 template <typename Callable, typename R, typename... Args>
156 std::is_null_pointer_v<std::decay_t<Callable>> || nothrow_invocable_r<Callable, R, Args...>;
157
158 template <typename Callable, typename R, typename... Args>
160 std::is_null_pointer_v<std::decay_t<Callable>> || nothrow_invocable_not_r<Callable, R, Args...>;
161
162 template <typename Callable, typename... Args>
163 requires nullptr_or_invocable<Callable, Args...>
164 constexpr auto invoke_optional(Callable&& callable, Args&&... args) noexcept(
165 nullptr_or_nothrow_invocable<Callable, Args...>) {
166 // Simply returns nullptr if the type of std::decay_t<Callable>> is std::nullptr_t.
167 if constexpr (std::is_null_pointer_v<std::decay_t<Callable>>) {
168 return nullptr;
169 } else {
170 using result_type = std::invoke_result_t<Callable, Args...>;
171
172 auto valid = convert_to_boolean(callable);
173
174 if constexpr (std::is_void_v<result_type>) {
175 if (valid) {
176 std::invoke(std::forward<Callable>(callable), std::forward<Args>(args)...);
177 }
178 } else {
179 if (valid) {
180 return std::optional{std::invoke(std::forward<Callable>(callable), std::forward<Args>(args)...)};
181 }
182
183 // Uses a concrete type std::optional<T> instead of std::nullopt unless the return type is explicitly
184 // specified by std::optional<T>.
185 return std::optional<result_type>{};
186 }
187 }
188 }
189
190 template <typename Callable, typename R, typename... Args>
191 requires nullptr_or_invocable_not_r<Callable, void, Args...>
192 constexpr auto invoke_optional_or(Callable&& callable, R&& default_value, Args&&... args) noexcept(
193 nullptr_or_nothrow_invocable_not_r<Callable, void, Args...>) {
194 // Due to the "requires" clause, it never returns void.
195 auto result = invoke_optional(std::forward<Callable>(callable), std::forward<Args>(args)...);
196
197 if constexpr (std::is_null_pointer_v<decltype(result)>) {
198 return std::forward<R>(default_value);
199 } else {
200 return std::move(result).value_or(std::forward<R>(default_value));
201 }
202 }
203} // namespace essence
Definition functional.hpp:127
Definition functional.hpp:124
Definition functional.hpp:121
Definition functional.hpp:136
Definition functional.hpp:133
Definition functional.hpp:130
Definition functional.hpp:147
Definition functional.hpp:143
Definition functional.hpp:140
Definition functional.hpp:159
Definition functional.hpp:155
Definition functional.hpp:151
Definition functional.hpp:49
Definition functional.hpp:104
Definition functional.hpp:77
Definition functional.hpp:91