Changeset 9c00022 in mainline
- Timestamp:
- 2018-07-05T21:41:22Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 55540fca
- Parents:
- d2a66ae7
- git-author:
- Dzejrou <dzejrou@…> (2018-05-03 20:30:54)
- git-committer:
- Dzejrou <dzejrou@…> (2018-07-05 21:41:22)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/include/impl/functional.hpp
rd2a66ae7 r9c00022 31 31 32 32 #include <limits> 33 #include <memory> 34 #include <typeinfo> 33 35 #include <type_traits> 34 36 #include <utility> … … 753 755 */ 754 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 755 795 class bad_function_call; 756 796 … … 758 798 class function; // undefined 759 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 */ 760 808 template<class R, class... Args> 761 class function<R(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 */ 762 1049 763 1050 template<class R, class... Args> 764 void swap(function<R(Args...)>& f1, function<R(Args...)>& f2); 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 */ 765 1059 766 1060 template<class R, class... Args> 767 bool operator==(const function<R(Args...)>&, nullptr_t) noexcept; 1061 bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept 1062 { 1063 return !f; 1064 } 768 1065 769 1066 template<class R, class... Args> 770 bool operator==(nullptr_t, const function<R(Args...)>&) noexcept; 1067 bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept 1068 { 1069 return !f; 1070 } 771 1071 772 1072 template<class R, class... Args> 773 bool operator!=(const function<R(Args...)>&, nullptr_t) noexcept; 1073 bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept 1074 { 1075 return (bool)f; 1076 } 774 1077 775 1078 template<class R, class... Args> 776 bool operator!=(nullptr_t, const function<R(Args...)>&) noexcept; 1079 bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept 1080 { 1081 return (bool)f; 1082 } 777 1083 778 1084 /**
Note:
See TracChangeset
for help on using the changeset viewer.