halcheck 1.0
Loading...
Searching...
No Matches
move_only_function.hpp
1#ifndef HALCHECK_LIB_FUNCTIONAL_MOVE_ONLY_FUNCTION_HPP
2#define HALCHECK_LIB_FUNCTIONAL_MOVE_ONLY_FUNCTION_HPP
3
4#include <halcheck/lib/functional/invoke.hpp>
5#include <halcheck/lib/variant.hpp>
6
7#include <memory>
8
9namespace halcheck { namespace lib {
10
11template<typename T>
12class move_only_function;
13
19template<typename R, typename... Args>
20class move_only_function<R(Args...)> {
21public:
22 template<typename F>
23 static constexpr bool is_callable() {
25 }
26
27 move_only_function() = default;
28
29 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
30 : _impl(nullptr) {}
31
32 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
33 move_only_function(F &&f) // NOLINT: implicit conversion
34 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
35
36 template<
37 typename F,
38 typename... Args2,
39 HALCHECK_REQUIRE(is_callable<F>()),
41 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
42 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
43
44 template<
45 typename F,
46 typename T,
47 typename... Args2,
48 HALCHECK_REQUIRE(is_callable<F>()),
50 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
51 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
52
53 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
54
55 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
56 move_only_function &operator=(F &&func) noexcept {
57 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
58 }
59
60 R operator()(Args... args) { return (*_impl)(std::forward<Args>(args)...); }
61
62 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
63
64 explicit operator bool() const noexcept { return bool(_impl); }
65
66private:
67 struct base {
68 virtual ~base() = default;
69 virtual R operator()(Args...) = 0;
70 };
71
72 template<typename F>
73 struct derived : base {
74 template<typename... Args2>
75 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
76 R operator()(Args... args) override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
77 F func;
78 };
79
81};
82
88template<typename R, typename... Args>
89class move_only_function<R(Args...) const> {
90public:
91 template<typename F>
92 static constexpr bool is_callable() {
93 return lib::is_invocable_r<R, const F, Args...>() && lib::is_invocable_r<R, const F &, Args...>();
94 }
95
96 move_only_function() = default;
97
98 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
99 : _impl(nullptr) {}
100
101 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
102 move_only_function(F &&f) // NOLINT: implicit conversion
103 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
104
105 template<
106 typename F,
107 typename... Args2,
108 HALCHECK_REQUIRE(is_callable<F>()),
110 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
111 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
112
113 template<
114 typename F,
115 typename T,
116 typename... Args2,
117 HALCHECK_REQUIRE(is_callable<F>()),
119 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
120 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
121
122 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
123
124 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
125 move_only_function &operator=(F &&func) noexcept {
126 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
127 }
128
129 R operator()(Args... args) const { return (*_impl)(std::forward<Args>(args)...); }
130
131 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
132
133 explicit operator bool() const noexcept { return bool(_impl); }
134
135private:
136 struct base {
137 virtual ~base() = default;
138 virtual R operator()(Args...) const = 0;
139 };
140
141 template<typename F>
142 struct derived : base {
143 template<typename... Args2>
144 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
145 R operator()(Args... args) const override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
146 F func;
147 };
148
150};
151
157template<typename R, typename... Args>
158class move_only_function<R(Args...) const &> {
159public:
160 template<typename F>
161 static constexpr bool is_callable() {
162 return lib::is_invocable_r<R, const F &, Args...>();
163 }
164
165 move_only_function() = default;
166
167 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
168 : _impl(nullptr) {}
169
170 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
171 move_only_function(F &&f) // NOLINT: implicit conversion
172 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
173
174 template<
175 typename F,
176 typename... Args2,
177 HALCHECK_REQUIRE(is_callable<F>()),
179 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
180 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
181
182 template<
183 typename F,
184 typename T,
185 typename... Args2,
186 HALCHECK_REQUIRE(is_callable<F>()),
188 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
189 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
190
191 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
192
193 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
194 move_only_function &operator=(F &&func) noexcept {
195 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
196 }
197
198 R operator()(Args... args) const { return (*_impl)(std::forward<Args>(args)...); }
199
200 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
201
202 explicit operator bool() const noexcept { return bool(_impl); }
203
204private:
205 struct base {
206 virtual ~base() = default;
207 virtual R operator()(Args...) const & = 0;
208 };
209
210 template<typename F>
211 struct derived : base {
212 template<typename... Args2>
213 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
214 R operator()(Args... args) const & override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
215 F func;
216 };
217
219};
220
226template<typename R, typename... Args>
227class move_only_function<R(Args...) &> {
228public:
229 template<typename F>
230 static constexpr bool is_callable() {
231 return lib::is_invocable_r<R, F &, Args...>();
232 }
233
234 move_only_function() = default;
235
236 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
237 : _impl(nullptr) {}
238
239 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
240 move_only_function(F &&f) // NOLINT: implicit conversion
241 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
242
243 template<
244 typename F,
245 typename... Args2,
246 HALCHECK_REQUIRE(is_callable<F>()),
248 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
249 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
250
251 template<
252 typename F,
253 typename T,
254 typename... Args2,
255 HALCHECK_REQUIRE(is_callable<F>()),
257 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
258 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
259
260 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
261
262 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
263 move_only_function &operator=(F &&func) noexcept {
264 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
265 }
266
267 R operator()(Args... args) & { return (*_impl)(std::forward<Args>(args)...); }
268
269 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
270
271 explicit operator bool() const noexcept { return bool(_impl); }
272
273private:
274 struct base {
275 virtual ~base() = default;
276 virtual R operator()(Args...) & = 0;
277 };
278
279 template<typename F>
280 struct derived : base {
281 template<typename... Args2>
282 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
283 R operator()(Args... args) & override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
284 F func;
285 };
286
288};
289
295template<typename R, typename... Args>
296class move_only_function<R(Args...) const &&> {
297public:
298 template<typename F>
299 static constexpr bool is_callable() {
300 return lib::is_invocable_r<R, const F, Args...>();
301 }
302
303 move_only_function() = default;
304
305 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
306 : _impl(nullptr) {}
307
308 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
309 move_only_function(F &&f) // NOLINT: implicit conversion
310 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
311
312 template<
313 typename F,
314 typename... Args2,
315 HALCHECK_REQUIRE(is_callable<F>()),
317 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
318 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
319
320 template<
321 typename F,
322 typename T,
323 typename... Args2,
324 HALCHECK_REQUIRE(is_callable<F>()),
326 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
327 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
328
329 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
330
331 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
332 move_only_function &operator=(F &&func) noexcept {
333 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
334 }
335
336 R operator()(Args... args) const && { return std::move(*_impl)(std::forward<Args>(args)...); }
337
338 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
339
340 explicit operator bool() const noexcept { return bool(_impl); }
341
342private:
343 struct base {
344 virtual ~base() = default;
345 virtual R operator()(Args...) const & = 0;
346 };
347
348 template<typename F>
349 struct derived : base {
350 template<typename... Args2>
351 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
352 R operator()(Args... args) const && override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
353 F func;
354 };
355
357};
358
364template<typename R, typename... Args>
365class move_only_function<R(Args...) &&> {
366public:
367 template<typename F>
368 static constexpr bool is_callable() {
369 return lib::is_invocable_r<R, F, Args...>();
370 }
371
372 move_only_function() = default;
373
374 constexpr move_only_function(std::nullptr_t) noexcept // NOLINT
375 : _impl(nullptr) {}
376
377 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
378 move_only_function(F &&f) // NOLINT: implicit conversion
379 : move_only_function(lib::in_place_type_t<lib::decay_t<F>>(), std::forward<F>(f)) {}
380
381 template<
382 typename F,
383 typename... Args2,
384 HALCHECK_REQUIRE(is_callable<F>()),
386 explicit move_only_function(lib::in_place_type_t<F>, Args2... args)
387 : _impl(new derived<F>(std::forward<Args2>(args)...)) {}
388
389 template<
390 typename F,
391 typename T,
392 typename... Args2,
393 HALCHECK_REQUIRE(is_callable<F>()),
395 explicit move_only_function(lib::in_place_type_t<F>, std::initializer_list<T> il, Args2... args)
396 : _impl(new derived<F>(il, std::forward<F>(args)...)) {}
397
398 move_only_function &operator=(std::nullptr_t) noexcept { _impl.reset(); }
399
400 template<typename F, HALCHECK_REQUIRE(is_callable<lib::decay_t<F>>())>
401 move_only_function &operator=(F &&func) noexcept {
402 _impl.reset(new derived<lib::decay_t<F>>(std::forward<F>(func)));
403 }
404
405 R operator()(Args... args) && { return std::move(*_impl)(std::forward<Args>(args)...); }
406
407 void swap(move_only_function &other) noexcept { std::swap(_impl, other._impl); }
408
409 explicit operator bool() const noexcept { return bool(_impl); }
410
411private:
412 struct base {
413 virtual ~base() = default;
414 virtual R operator()(Args...) && = 0;
415 };
416
417 template<typename F>
418 struct derived : base {
419 template<typename... Args2>
420 explicit derived(Args2 &&...args) : func(std::forward<Args2>(args)...) {}
421 R operator()(Args... args) && override { return lib::invoke(std::move(func), std::forward<Args>(args)...); }
422 F func;
423 };
424
426};
427
428}} // namespace halcheck::lib
429
430#endif
T forward(T... args)
typename std::decay< T >::type decay_t
An implementation of std::decay_t.
Definition type_traits.hpp:101
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
An implementation of std::is_invocable_r.
Definition invoke.hpp:54
T swap(T... args)