source: mainline/uspace/lib/cpp/include/impl/functional.hpp@ 9c00022

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9c00022 was 9c00022, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added function

  • Property mode set to 100644
File size: 33.5 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_FUNCTIONAL
30#define LIBCPP_FUNCTIONAL
31
32#include <limits>
33#include <memory>
34#include <typeinfo>
35#include <type_traits>
36#include <utility>
37
38namespace std
39{
40 namespace aux
41 {
42 /**
43 * 20.9.2, requirements:
44 */
45 template<class R, class T, class T1, class... Ts>
46 decltype(auto) invoke(R T::* f, T1&& t1, Ts&&... args)
47 {
48 if constexpr (is_member_function_pointer_v<decltype(f)>)
49 {
50 if constexpr (is_base_of_v<T, remove_reference_t<T1>>)
51 // (1.1)
52 return (t1.*f)(forward<Ts>(args)...);
53 else
54 // (1.2)
55 return ((*t1).*f)(forward<Ts>(args)...);
56 }
57 else if constexpr (is_member_object_pointer_v<decltype(f)> && sizeof...(args) == 0)
58 {
59 /**
60 * Note: Standard requires to N be equal to 1, but we take t1 directly
61 * so we need sizeof...(args) to be 0.
62 */
63 if constexpr (is_base_of_v<T, remove_reference_t<T1>>)
64 // (1.3)
65 return t1.*f;
66 else
67 // (1.4)
68 return (*t1).*f;
69 }
70
71 /**
72 * Note: If this condition holds this will not be reachable,
73 * but a new addition to the standard (17.7 point (8.1))
74 * prohibits us from simply using false as the condition here,
75 * so we use this because we know it is false here.
76 */
77 static_assert(is_member_function_pointer_v<decltype(f)>, "invalid invoke");
78 }
79
80 template<class F, class... Args>
81 decltype(auto) invoke(F&& f, Args&&... args)
82 {
83 // (1.5)
84 return f(forward<Args>(args)...);
85 }
86 }
87
88 /**
89 * 20.9.3, invoke:
90 */
91
92 template<class F, class... Args>
93 result_of_t<F&&(Args&&...)> invoke(F&& f, Args&&... args)
94 {
95 return aux::invoke(forward<F>(f)(forward<Args>(args)...));
96 }
97
98 /**
99 * 20.9.4, reference_wrapper:
100 */
101
102 template<class T>
103 class reference_wrapper
104 {
105 public:
106 using type = T;
107 // TODO: conditional typedefs
108
109 reference_wrapper(type& val) noexcept
110 : data_{&val}
111 { /* DUMMY BODY */ }
112
113 reference_wrapper(type&&) = delete;
114
115 reference_wrapper(const reference_wrapper& other) noexcept
116 : data_{other.data_}
117 { /* DUMMY BODY */ }
118
119 reference_wrapper& operator=(const reference_wrapper& other) noexcept
120 {
121 data_ = other.data_;
122
123 return *this;
124 }
125
126 operator type&() const noexcept
127 {
128 return *data_;
129 }
130
131 type& get() const noexcept
132 {
133 return *data_;
134 }
135
136 template<class... Args>
137 result_of_t<type&(Args&&...)> operator()(Args&&... args) const
138 {
139 return invoke(*data_, std::forward<Args>(args)...);
140 }
141
142 private:
143 type* data_;
144 };
145
146 template<class T>
147 reference_wrapper<T> ref(T& t) noexcept
148 {
149 return reference_wrapper<T>{t};
150 }
151
152 template<class T>
153 reference_wrapper<const T> cref(const T& t) noexcept
154 {
155 return reference_wrapper<const T>{t};
156 }
157
158 template<class T>
159 void ref(const T&&) = delete;
160
161 template<class T>
162 void cref(const T&&) = delete;
163
164 template<class T>
165 reference_wrapper<T> ref(reference_wrapper<T> t) noexcept
166 {
167 return ref(t.get());
168 }
169
170 template<class T>
171 reference_wrapper<const T> cref(reference_wrapper<T> t) noexcept
172 {
173 return cref(t.get());
174 }
175
176 /**
177 * 20.9.5, arithmetic operations:
178 */
179
180 template<class T = void>
181 struct plus
182 {
183 constexpr T operator()(const T& lhs, const T& rhs) const
184 {
185 return lhs + rhs;
186 }
187
188 using first_argument_type = T;
189 using second_argument_type = T;
190 using result_type = T;
191 };
192
193 template<class T = void>
194 struct minus
195 {
196 constexpr T operator()(const T& lhs, const T& rhs) const
197 {
198 return lhs - rhs;
199 }
200
201 using first_argument_type = T;
202 using second_argument_type = T;
203 using result_type = T;
204 };
205
206 template<class T = void>
207 struct multiplies
208 {
209 constexpr T operator()(const T& lhs, const T& rhs) const
210 {
211 return lhs * rhs;
212 }
213
214 using first_argument_type = T;
215 using second_argument_type = T;
216 using result_type = T;
217 };
218
219 template<class T = void>
220 struct divides
221 {
222 constexpr T operator()(const T& lhs, const T& rhs) const
223 {
224 return lhs / rhs;
225 }
226
227 using first_argument_type = T;
228 using second_argument_type = T;
229 using result_type = T;
230 };
231
232 template<class T = void>
233 struct modulus
234 {
235 constexpr T operator()(const T& lhs, const T& rhs) const
236 {
237 return lhs % rhs;
238 }
239
240 using first_argument_type = T;
241 using second_argument_type = T;
242 using result_type = T;
243 };
244
245 template<class T = void>
246 struct negate
247 {
248 constexpr T operator()(const T& x) const
249 {
250 return -x;
251 }
252
253 using argument_type = T;
254 using result_type = T;
255 };
256
257 namespace aux
258 {
259 /**
260 * Used by some functions like std::set::find to determine
261 * whether a functor is transparent.
262 */
263 struct transparent_t;
264
265 template<class T, class = void>
266 struct is_transparent: false_type
267 { /* DUMMY BODY */ };
268
269 template<class T>
270 struct is_transparent<T, void_t<typename T::is_transparent>>
271 : true_type
272 { /* DUMMY BODY */ };
273
274 template<class T>
275 inline constexpr bool is_transparent_v = is_transparent<T>::value;
276 }
277
278 template<>
279 struct plus<void>
280 {
281 template<class T, class U>
282 constexpr auto operator()(T&& lhs, U&& rhs) const
283 -> decltype(forward<T>(lhs) + forward<U>(rhs))
284 {
285 return forward<T>(lhs) + forward<T>(rhs);
286 }
287
288 using is_transparent = aux::transparent_t;
289 };
290
291 template<>
292 struct minus<void>
293 {
294 template<class T, class U>
295 constexpr auto operator()(T&& lhs, U&& rhs) const
296 -> decltype(forward<T>(lhs) - forward<U>(rhs))
297 {
298 return forward<T>(lhs) - forward<T>(rhs);
299 }
300
301 using is_transparent = aux::transparent_t;
302 };
303
304 template<>
305 struct multiplies<void>
306 {
307 template<class T, class U>
308 constexpr auto operator()(T&& lhs, U&& rhs) const
309 -> decltype(forward<T>(lhs) * forward<U>(rhs))
310 {
311 return forward<T>(lhs) * forward<T>(rhs);
312 }
313
314 using is_transparent = aux::transparent_t;
315 };
316
317 template<>
318 struct divides<void>
319 {
320 template<class T, class U>
321 constexpr auto operator()(T&& lhs, U&& rhs) const
322 -> decltype(forward<T>(lhs) / forward<U>(rhs))
323 {
324 return forward<T>(lhs) / forward<T>(rhs);
325 }
326
327 using is_transparent = aux::transparent_t;
328 };
329
330 template<>
331 struct modulus<void>
332 {
333 template<class T, class U>
334 constexpr auto operator()(T&& lhs, U&& rhs) const
335 -> decltype(forward<T>(lhs) % forward<U>(rhs))
336 {
337 return forward<T>(lhs) % forward<T>(rhs);
338 }
339
340 using is_transparent = aux::transparent_t;
341 };
342
343 template<>
344 struct negate<void>
345 {
346 template<class T>
347 constexpr auto operator()(T&& x) const
348 -> decltype(-forward<T>(x))
349 {
350 return -forward<T>(x);
351 }
352
353 using is_transparent = aux::transparent_t;
354 };
355
356 /**
357 * 20.9.6, comparisons:
358 */
359
360 template<class T = void>
361 struct equal_to
362 {
363 constexpr bool operator()(const T& lhs, const T& rhs) const
364 {
365 return lhs == rhs;
366 }
367
368 using first_argument_type = T;
369 using second_argument_type = T;
370 using result_type = bool;
371 };
372
373 template<class T = void>
374 struct not_equal_to
375 {
376 constexpr bool operator()(const T& lhs, const T& rhs) const
377 {
378 return lhs != rhs;
379 }
380
381 using first_argument_type = T;
382 using second_argument_type = T;
383 using result_type = bool;
384 };
385
386 template<class T = void>
387 struct greater
388 {
389 constexpr bool operator()(const T& lhs, const T& rhs) const
390 {
391 return lhs > rhs;
392 }
393
394 using first_argument_type = T;
395 using second_argument_type = T;
396 using result_type = bool;
397 };
398
399 template<class T = void>
400 struct less
401 {
402 constexpr bool operator()(const T& lhs, const T& rhs) const
403 {
404 return lhs < rhs;
405 }
406
407 using first_argument_type = T;
408 using second_argument_type = T;
409 using result_type = bool;
410 };
411
412 template<class T = void>
413 struct greater_equal
414 {
415 constexpr bool operator()(const T& lhs, const T& rhs) const
416 {
417 return lhs >= rhs;
418 }
419
420 using first_argument_type = T;
421 using second_argument_type = T;
422 using result_type = bool;
423 };
424
425 template<class T = void>
426 struct less_equal
427 {
428 constexpr bool operator()(const T& lhs, const T& rhs) const
429 {
430 return lhs <= rhs;
431 }
432
433 using first_argument_type = T;
434 using second_argument_type = T;
435 using result_type = bool;
436 };
437
438 template<>
439 struct equal_to<void>
440 {
441 template<class T, class U>
442 constexpr auto operator()(T&& lhs, U&& rhs) const
443 -> decltype(forward<T>(lhs) == forward<U>(rhs))
444 {
445 return forward<T>(lhs) == forward<U>(rhs);
446 }
447
448 using is_transparent = aux::transparent_t;
449 };
450
451 template<>
452 struct not_equal_to<void>
453 {
454 template<class T, class U>
455 constexpr auto operator()(T&& lhs, U&& rhs) const
456 -> decltype(forward<T>(lhs) != forward<U>(rhs))
457 {
458 return forward<T>(lhs) != forward<U>(rhs);
459 }
460
461 using is_transparent = aux::transparent_t;
462 };
463
464 template<>
465 struct greater<void>
466 {
467 template<class T, class U>
468 constexpr auto operator()(T&& lhs, U&& rhs) const
469 -> decltype(forward<T>(lhs) > forward<U>(rhs))
470 {
471 return forward<T>(lhs) > forward<U>(rhs);
472 }
473
474 using is_transparent = aux::transparent_t;
475 };
476
477 template<>
478 struct less<void>
479 {
480 template<class T, class U>
481 constexpr auto operator()(T&& lhs, U&& rhs) const
482 -> decltype(forward<T>(lhs) < forward<U>(rhs))
483 {
484 return forward<T>(lhs) < forward<U>(rhs);
485 }
486
487 using is_transparent = aux::transparent_t;
488 };
489
490 template<>
491 struct greater_equal<void>
492 {
493 template<class T, class U>
494 constexpr auto operator()(T&& lhs, U&& rhs) const
495 -> decltype(forward<T>(lhs) >= forward<U>(rhs))
496 {
497 return forward<T>(lhs) >= forward<U>(rhs);
498 }
499
500 using is_transparent = aux::transparent_t;
501 };
502
503 template<>
504 struct less_equal<void>
505 {
506 template<class T, class U>
507 constexpr auto operator()(T&& lhs, U&& rhs) const
508 -> decltype(forward<T>(lhs) <= forward<U>(rhs))
509 {
510 return forward<T>(lhs) <= forward<U>(rhs);
511 }
512
513 using is_transparent = aux::transparent_t;
514 };
515
516 /**
517 * 20.9.7, logical operations:
518 */
519
520 template<class T = void>
521 struct logical_and
522 {
523 constexpr bool operator()(const T& lhs, const T& rhs) const
524 {
525 return lhs && rhs;
526 }
527
528 using first_argument_type = T;
529 using second_argument_type = T;
530 using result_type = bool;
531 };
532
533 template<class T = void>
534 struct logical_or
535 {
536 constexpr bool operator()(const T& lhs, const T& rhs) const
537 {
538 return lhs || rhs;
539 }
540
541 using first_argument_type = T;
542 using second_argument_type = T;
543 using result_type = bool;
544 };
545
546 template<class T = void>
547 struct logical_not
548 {
549 constexpr bool operator()(const T& x) const
550 {
551 return !x;
552 }
553
554 using argument_type = T;
555 using result_type = bool;
556 };
557
558 template<>
559 struct logical_and<void>
560 {
561 template<class T, class U>
562 constexpr auto operator()(T&& lhs, U&& rhs) const
563 -> decltype(forward<T>(lhs) && forward<U>(rhs))
564 {
565 return forward<T>(lhs) && forward<U>(rhs);
566 }
567
568 using is_transparent = aux::transparent_t;
569 };
570
571 template<>
572 struct logical_or<void>
573 {
574 template<class T, class U>
575 constexpr auto operator()(T&& lhs, U&& rhs) const
576 -> decltype(forward<T>(lhs) || forward<U>(rhs))
577 {
578 return forward<T>(lhs) || forward<U>(rhs);
579 }
580
581 using is_transparent = aux::transparent_t;
582 };
583
584 template<>
585 struct logical_not<void>
586 {
587 template<class T>
588 constexpr auto operator()(T&& x) const
589 -> decltype(!forward<T>(x))
590 {
591 return !forward<T>(x);
592 }
593
594 using is_transparent = aux::transparent_t;
595 };
596
597 /**
598 * 20.9.8, bitwise operations:
599 */
600
601 template<class T = void>
602 struct bit_and
603 {
604 constexpr T operator()(const T& lhs, const T& rhs) const
605 {
606 return lhs & rhs;
607 }
608
609 using first_argument_type = T;
610 using second_argument_type = T;
611 using result_type = T;
612 };
613
614 template<class T = void>
615 struct bit_or
616 {
617 constexpr T operator()(const T& lhs, const T& rhs) const
618 {
619 return lhs | rhs;
620 }
621
622 using first_argument_type = T;
623 using second_argument_type = T;
624 using result_type = T;
625 };
626
627 template<class T = void>
628 struct bit_xor
629 {
630 constexpr T operator()(const T& lhs, const T& rhs) const
631 {
632 return lhs ^ rhs;
633 }
634
635 using first_argument_type = T;
636 using second_argument_type = T;
637 using result_type = T;
638 };
639
640 template<class T = void>
641 struct bit_not
642 {
643 constexpr bool operator()(const T& x) const
644 {
645 return ~x;
646 }
647
648 using argument_type = T;
649 using result_type = T;
650 };
651
652 template<>
653 struct bit_and<void>
654 {
655 template<class T, class U>
656 constexpr auto operator()(T&& lhs, U&& rhs) const
657 -> decltype(forward<T>(lhs) & forward<U>(rhs))
658 {
659 return forward<T>(lhs) & forward<U>(rhs);
660 }
661
662 using is_transparent = aux::transparent_t;
663 };
664
665 template<>
666 struct bit_or<void>
667 {
668 template<class T, class U>
669 constexpr auto operator()(T&& lhs, U&& rhs) const
670 -> decltype(forward<T>(lhs) | forward<U>(rhs))
671 {
672 return forward<T>(lhs) | forward<U>(rhs);
673 }
674
675 using is_transparent = aux::transparent_t;
676 };
677
678 template<>
679 struct bit_xor<void>
680 {
681 template<class T, class U>
682 constexpr auto operator()(T&& lhs, U&& rhs) const
683 -> decltype(forward<T>(lhs) ^ forward<U>(rhs))
684 {
685 return forward<T>(lhs) ^ forward<U>(rhs);
686 }
687
688 using is_transparent = aux::transparent_t;
689 };
690
691 template<>
692 struct bit_not<void>
693 {
694 template<class T>
695 constexpr auto operator()(T&& x) const
696 -> decltype(~forward<T>(x))
697 {
698 return ~forward<T>(x);
699 }
700
701 using is_transparent = aux::transparent_t;
702 };
703
704 /**
705 * 20.9.9, negators:
706 */
707
708 template<class Predicate>
709 class unary_negate;
710
711 template<class Predicate>
712 constexpr unary_negate<Predicate> not1(const Predicate& pred);
713
714 template<class Predicate>
715 class binary_negate;
716
717 template<class Predicate>
718 constexpr binary_negate<Predicate> not2(const Predicate& pred);
719
720 /**
721 * 20.9.10, bind:
722 */
723
724 template<class T>
725 struct is_bind_expression;
726
727 template<class T>
728 struct is_placeholder;
729
730 // TODO: void should be /unspecified/
731 template<class F, class... Args>
732 void bind(F&& f, Args&&... args);
733
734 template<class R, class F, class... Args>
735 void bind(F&& f, Args&&... args);
736
737 namespace placeholders
738 {
739 /**
740 * TODO: for X from 1 to implementation defined M
741 * extern /unspecified/ _X;
742 */
743 }
744
745 /**
746 * 20.9.11, member function adaptors:
747 */
748
749 // TODO: void should be /unspecified/
750 template<class R, class T>
751 void mem_fn(R T::* f);
752
753 /**
754 * 20.9.12, polymorphic function adaptors:
755 */
756
757 namespace aux
758 {
759 // TODO: fix this
760 /* template<class, class T, class... Args> */
761 /* struct is_callable_impl: false_type */
762 /* { /1* DUMMY BODY *1/ }; */
763
764 /* template<class, class R, class... Args> */
765 /* struct is_callable_impl< */
766 /* void_t<decltype(aux::invoke(declval<R(Args...)>(), declval<Args>()..., R))>, */
767 /* R, Args... */
768 /* > : true_type */
769 /* { /1* DUMMY BODY *1/ }; */
770
771 /* template<class T> */
772 /* struct is_callable: is_callable_impl<void_t<>, T> */
773 /* { /1* DUMMY BODY *1/ }; */
774
775 template<class Callable, class R, class... Args>
776 R invoke_callable(Callable* clbl, Args&&... args)
777 {
778 return (*clbl)(forward<Args>(args)...);
779 }
780
781 template<class Callable>
782 void copy_callable(Callable* to, Callable* from)
783 {
784 new(to) Callable{*from};
785 }
786
787 template<class Callable>
788 void destroy_callable(Callable* clbl)
789 {
790 if (clbl)
791 clbl->~Callable();
792 }
793 }
794
795 class bad_function_call;
796
797 template<class>
798 class function; // undefined
799
800 /**
801 * Note: Ideally, this implementation wouldn't
802 * copy the target if it was a pointer to
803 * a function, but for the simplicity of the
804 * implementation, we do copy even in that
805 * case for now. It would be a nice optimization
806 * if this was changed in the future.
807 */
808 template<class R, class... Args>
809 class function<R(Args...)>
810 {
811 public:
812 using result_type = R;
813 // TODO: conditional typedefs
814
815 /**
816 * 20.9.12.2.1, construct/copy/destroy:
817 */
818
819 function() noexcept
820 : callable_{}, callable_size_{}, call_{},
821 copy_{}, dest_{}
822 { /* DUMMY BODY */ }
823
824 function(nullptr_t) noexcept
825 : function{}
826 { /* DUMMY BODY */ }
827
828 function(const function& other)
829 : callable_{}, callable_size_{other.callable_size_},
830 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
831 {
832 callable_ = new uint8_t[callable_size_];
833 (*copy_)(callable_, other.callable_);
834 }
835
836 function(function&& other)
837 : callable_{other.callable_}, callable_size_{other.callable_size_},
838 call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
839 {
840 other.callable_ = nullptr;
841 other.callable_size_ = size_t{};
842 other.call_ = nullptr;
843 other.copy_ = nullptr;
844 other.dest_ = nullptr;
845 }
846
847 // TODO: shall not participate in overloading unless aux::is_callable<F>
848 template<class F>
849 function(F f)
850 : callable_{}, callable_size_{sizeof(F)},
851 call_{(call_t)aux::invoke_callable<F, R, Args...>},
852 copy_{(copy_t)aux::copy_callable<F>},
853 dest_{(dest_t)aux::destroy_callable<F>}
854 {
855 callable_ = new uint8_t[callable_size_];
856 (*copy_)(callable_, (uint8_t*)&f);
857 }
858
859 /**
860 * Note: For the moment we're ignoring the allocator
861 * for simplicity of the implementation.
862 */
863
864 template<class A>
865 function(allocator_arg_t, const A& a) noexcept
866 : function{}
867 { /* DUMMY BODY */ }
868
869 template<class A>
870 function(allocator_arg_t, const A& a, nullptr_t) noexcept
871 : function{}
872 { /* DUMMY BODY */ }
873
874 template<class A>
875 function(allocator_arg_t, const A& a, const function& other)
876 : function{other}
877 { /* DUMMY BODY */ }
878
879 template<class A>
880 function(allocator_arg_t, const A& a, function&& other)
881 : function{move(other)}
882 { /* DUMMY BODY */ }
883
884 // TODO: shall not participate in overloading unless aux::is_callable<F>
885 template<class F, class A>
886 function(allocator_arg_t, const A& a, F f)
887 : function{f}
888 { /* DUMMY BODY */ }
889
890 function& operator=(const function& rhs)
891 {
892 function{rhs}.swap(*this);
893
894 return *this;
895 }
896
897 /**
898 * Note: We have to copy call_, copy_
899 * and dest_ because they can be templated
900 * by a type F we don't know.
901 */
902 function& operator=(function&& rhs)
903 {
904 clear_();
905
906 callable_ = rhs.callable_;
907 callable_size_ = rhs.callable_size_;
908 call_ = rhs.call_;
909 copy_ = rhs.copy_;
910 dest_ = rhs.dest_;
911
912 rhs.callable_ = nullptr;
913 rhs.callable_size_ = size_t{};
914 rhs.call_ = nullptr;
915 rhs.copy_ = nullptr;
916 rhs.dest_ = nullptr;
917
918 return *this;
919 }
920
921 function& operator=(nullptr_t) noexcept
922 {
923 clear_();
924
925 return *this;
926 }
927
928 // TODO: shall not participate in overloading unless aux::is_callable<F>
929 template<class F>
930 function& operator=(F&& f)
931 {
932 callable_size_ = sizeof(F);
933 callable_ = new uint8_t[callable_size_];
934 call_ = aux::invoke_callable<F, R, Args...>;
935 copy_ = aux::copy_callable<F>;
936 dest_ = aux::destroy_callable<F>;
937
938 (*copy_)(callable_, (uint8_t*)&f);
939 }
940
941 template<class F>
942 function& operator=(reference_wrapper<F> ref) noexcept
943 {
944 return (*this) = ref.get();
945 }
946
947 ~function()
948 {
949 if (callable_)
950 {
951 (*dest_)(callable_);
952 delete[] callable_;
953 }
954 }
955
956 /**
957 * 20.9.12.2.2, function modifiers:
958 */
959
960 void swap(function& other) noexcept
961 {
962 std::swap(callable_, other.callable_);
963 std::swap(callable_size_, other.callable_size_);
964 std::swap(call_, other.call_);
965 std::swap(copy_, other.copy_);
966 std::swap(dest_, other.dest_);
967 }
968
969 template<class F, class A>
970 void assign(F&& f, const A& a)
971 {
972 function{allocator_arg, a, forward<F>(f)}.swap(*this);
973 }
974
975 /**
976 * 20.9.12.2.3, function capacity:
977 */
978
979 explicit operator bool() const noexcept
980 {
981 return callable_ != nullptr;
982 }
983
984 /**
985 * 20.9.12.2.4, function invocation:
986 */
987
988 result_type operator()(Args... args) const
989 {
990 // TODO: throw bad_function_call if !callable_ || !call_
991 if constexpr (is_same_v<R, void>)
992 (*call_)(callable_, forward<Args>(args)...);
993 else
994 return (*call_)(callable_, forward<Args>(args)...);
995 }
996
997 /**
998 * 20.9.12.2.5, function target access:
999 */
1000
1001 const type_info& target_type() const noexcept
1002 {
1003 return typeid(*callable_);
1004 }
1005
1006 template<class T>
1007 T* target() noexcept
1008 {
1009 if (target_type() == typeid(T))
1010 return (T*)callable_;
1011 else
1012 return nullptr;
1013 }
1014
1015 template<class T>
1016 const T* target() const noexcept
1017 {
1018 if (target_type() == typeid(T))
1019 return (T*)callable_;
1020 else
1021 return nullptr;
1022 }
1023
1024 private:
1025 using call_t = R(*)(uint8_t*, Args&&...);
1026 using copy_t = void (*)(uint8_t*, uint8_t*);
1027 using dest_t = void (*)(uint8_t*);
1028
1029 uint8_t* callable_;
1030 size_t callable_size_;
1031 call_t call_;
1032 copy_t copy_;
1033 dest_t dest_;
1034
1035 void clear_()
1036 {
1037 if (callable_)
1038 {
1039 (*dest_)(callable_);
1040 delete[] callable_;
1041 callable_ = nullptr;
1042 }
1043 }
1044 };
1045
1046 /**
1047 * 20.9.12.2.7, specialized algorithms:
1048 */
1049
1050 template<class R, class... Args>
1051 void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
1052 {
1053 f1.swap(f2);
1054 }
1055
1056 /**
1057 * 20.9.12.2.6, null pointer comparisons:
1058 */
1059
1060 template<class R, class... Args>
1061 bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
1062 {
1063 return !f;
1064 }
1065
1066 template<class R, class... Args>
1067 bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
1068 {
1069 return !f;
1070 }
1071
1072 template<class R, class... Args>
1073 bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
1074 {
1075 return (bool)f;
1076 }
1077
1078 template<class R, class... Args>
1079 bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
1080 {
1081 return (bool)f;
1082 }
1083
1084 /**
1085 * 20.9.13, hash function primary template:
1086 */
1087
1088 namespace aux
1089 {
1090 template<class T>
1091 union converter
1092 {
1093 T value;
1094 uint64_t converted;
1095 };
1096
1097 template<class T>
1098 T hash_(uint64_t x) noexcept
1099 {
1100 /**
1101 * Note: std::hash is used for indexing in
1102 * unordered containers, not for cryptography.
1103 * Because of this, we decided to simply convert
1104 * the value to uin64_t, which will help us
1105 * with testing (since in order to create
1106 * a collision in a multiset or multimap
1107 * we simply need 2 values that congruent
1108 * by the size of the table.
1109 */
1110 return static_cast<T>(x);
1111 }
1112
1113 template<class T>
1114 size_t hash(T x) noexcept
1115 {
1116 static_assert(is_arithmetic_v<T> || is_pointer_v<T>,
1117 "invalid type passed to aux::hash");
1118
1119 converter<T> conv;
1120 conv.value = x;
1121
1122 return hash_<size_t>(conv.converted);
1123 }
1124 }
1125
1126 template<class T>
1127 struct hash
1128 { /* DUMMY BODY */ };
1129
1130 template<>
1131 struct hash<bool>
1132 {
1133 size_t operator()(bool x) const noexcept
1134 {
1135 return aux::hash(x);
1136 }
1137
1138 using argument_type = bool;
1139 using result_type = size_t;
1140 };
1141
1142 template<>
1143 struct hash<char>
1144 {
1145 size_t operator()(char x) const noexcept
1146 {
1147 return aux::hash(x);
1148 }
1149
1150 using argument_type = char;
1151 using result_type = size_t;
1152 };
1153
1154 template<>
1155 struct hash<signed char>
1156 {
1157 size_t operator()(signed char x) const noexcept
1158 {
1159 return aux::hash(x);
1160 }
1161
1162 using argument_type = signed char;
1163 using result_type = size_t;
1164 };
1165
1166 template<>
1167 struct hash<unsigned char>
1168 {
1169 size_t operator()(unsigned char x) const noexcept
1170 {
1171 return aux::hash(x);
1172 }
1173
1174 using argument_type = unsigned char;
1175 using result_type = size_t;
1176 };
1177
1178 template<>
1179 struct hash<char16_t>
1180 {
1181 size_t operator()(char16_t x) const noexcept
1182 {
1183 return aux::hash(x);
1184 }
1185
1186 using argument_type = char16_t;
1187 using result_type = size_t;
1188 };
1189
1190 template<>
1191 struct hash<char32_t>
1192 {
1193 size_t operator()(char32_t x) const noexcept
1194 {
1195 return aux::hash(x);
1196 }
1197
1198 using argument_type = char32_t;
1199 using result_type = size_t;
1200 };
1201
1202 template<>
1203 struct hash<wchar_t>
1204 {
1205 size_t operator()(wchar_t x) const noexcept
1206 {
1207 return aux::hash(x);
1208 }
1209
1210 using argument_type = wchar_t;
1211 using result_type = size_t;
1212 };
1213
1214 template<>
1215 struct hash<short>
1216 {
1217 size_t operator()(short x) const noexcept
1218 {
1219 return aux::hash(x);
1220 }
1221
1222 using argument_type = short;
1223 using result_type = size_t;
1224 };
1225
1226 template<>
1227 struct hash<unsigned short>
1228 {
1229 size_t operator()(unsigned short x) const noexcept
1230 {
1231 return aux::hash(x);
1232 }
1233
1234 using argument_type = unsigned short;
1235 using result_type = size_t;
1236 };
1237
1238 template<>
1239 struct hash<int>
1240 {
1241 size_t operator()(int x) const noexcept
1242 {
1243 return aux::hash(x);
1244 }
1245
1246 using argument_type = int;
1247 using result_type = size_t;
1248 };
1249
1250 template<>
1251 struct hash<unsigned int>
1252 {
1253 size_t operator()(unsigned int x) const noexcept
1254 {
1255 return aux::hash(x);
1256 }
1257
1258 using argument_type = unsigned int;
1259 using result_type = size_t;
1260 };
1261
1262 template<>
1263 struct hash<long>
1264 {
1265 size_t operator()(long x) const noexcept
1266 {
1267 return aux::hash(x);
1268 }
1269
1270 using argument_type = long;
1271 using result_type = size_t;
1272 };
1273
1274 template<>
1275 struct hash<long long>
1276 {
1277 size_t operator()(long long x) const noexcept
1278 {
1279 return aux::hash(x);
1280 }
1281
1282 using argument_type = long long;
1283 using result_type = size_t;
1284 };
1285
1286 template<>
1287 struct hash<unsigned long>
1288 {
1289 size_t operator()(unsigned long x) const noexcept
1290 {
1291 return aux::hash(x);
1292 }
1293
1294 using argument_type = unsigned long;
1295 using result_type = size_t;
1296 };
1297
1298 template<>
1299 struct hash<unsigned long long>
1300 {
1301 size_t operator()(unsigned long long x) const noexcept
1302 {
1303 return aux::hash(x);
1304 }
1305
1306 using argument_type = unsigned long long;
1307 using result_type = size_t;
1308 };
1309
1310 template<>
1311 struct hash<float>
1312 {
1313 size_t operator()(float x) const noexcept
1314 {
1315 return aux::hash(x);
1316 }
1317
1318 using argument_type = float;
1319 using result_type = size_t;
1320 };
1321
1322 template<>
1323 struct hash<double>
1324 {
1325 size_t operator()(double x) const noexcept
1326 {
1327 return aux::hash(x);
1328 }
1329
1330 using argument_type = double;
1331 using result_type = size_t;
1332 };
1333
1334 template<>
1335 struct hash<long double>
1336 {
1337 size_t operator()(long double x) const noexcept
1338 {
1339 return aux::hash(x);
1340 }
1341
1342 using argument_type = long double;
1343 using result_type = size_t;
1344 };
1345
1346 template<class T>
1347 struct hash<T*>
1348 {
1349 size_t operator()(T* x) const noexcept
1350 {
1351 return aux::hash(x);
1352 }
1353
1354 using argument_type = T*;
1355 using result_type = size_t;
1356 };
1357}
1358
1359#endif
Note: See TracBrowser for help on using the repository browser.