sandbox
Loading...
Searching...
No Matches
function_traits.hpp
1#ifndef LIBSBX_SIGNAL_FUNCTION_TRAITS_HPP_
2#define LIBSBX_SIGNAL_FUNCTION_TRAITS_HPP_
3
4#include <utility>
5#include <ranges>
6#include <cstring>
7
8#include <libsbx/memory/observer_ptr.hpp>
9
10namespace sbx::signals {
11
12namespace detail {
13
14struct a { virtual ~a() = default; void f(); virtual void g(); static void h(); };
15struct b { virtual ~b() = default; void f(); virtual void g(); };
16struct c : a, b { void f(); void g() override; };
17struct d : virtual a { void g() override; };
18
20 decltype(&d::g) dm;
21 decltype(&c::g) mm;
22 decltype(&c::g) mvm;
23 decltype(&a::f) m;
24 decltype(&a::g) vm;
25 decltype(&a::h) s;
26 void (*f)();
27 void *o;
28}; // function_types
29
30} // namespace detail
31
33
34public:
35
37 : _size{0} {
38 std::ranges::fill(_data, '\n');
39 }
40
41 template<typename Type>
42 void store(const Type& value) {
43 const auto* ptr = reinterpret_cast<const std::uint8_t*>(std::addressof(value));
44
45 std::memcpy(_data, ptr, sizeof(Type));
46 }
47
48 template<typename Type>
50 if (sizeof(Type) != _size) {
51 return nullptr;
52 }
53
54 return reinterpret_cast<const Type*>(_data);
55 }
56
57private:
58
59 alignas(sizeof(detail::function_types)) std::uint8_t _data[sizeof(detail::function_types)];
60 std::size_t _size;
61
62}; // struct function_ptr
63
64template<typename, typename = void>
65struct has_call_operator : std::false_type {};
66
67template<typename Type>
68struct has_call_operator<Type, std::void_t<decltype(&std::remove_reference_t<Type>::operator())>> : std::true_type {};
69
70template<typename Type>
71constexpr auto has_call_operator_v = has_call_operator<Type>::value;
72
73template<typename Type, typename = void>
75 static constexpr auto is_disconnectable_v = false;
76 static constexpr auto must_check_object_v = true;
77
78 static auto ptr(const Type& /*t*/, function_ptr& /*d*/) -> void {
79
80 }
81
82 static auto eq(const Type& /*t*/, const function_ptr& /*d*/) -> bool {
83 return false;
84 }
85}; // struct function_traits
86
87template<typename Type>
88struct function_traits<Type, std::enable_if_t<std::is_function_v<Type>>> {
89 static constexpr bool is_disconnectable_v = true;
90 static constexpr bool must_check_object_v = false;
91
92 static auto ptr(Type& value, function_ptr& ptr) -> void {
93 ptr.store(std::addressof(value));
94 }
95
96 static auto eq(Type& value, const function_ptr& ptr) -> bool {
97 const auto* result = ptr.as<const Type*>();
98
99 return result && *result == std::addressof(value);
100 }
101}; // struct function_traits
102
103template<typename Type>
104struct function_traits<Type*, std::enable_if_t<std::is_function_v<Type>>> {
105 static constexpr bool is_disconnectable_v = true;
106 static constexpr bool must_check_object_v = false;
107
108 static auto ptr(memory::observer_ptr<Type> value, function_ptr& ptr) -> void {
109 function_traits<Type>::ptr(*value, ptr);
110 }
111
112 static auto eq(memory::observer_ptr<Type> value, const function_ptr& ptr) -> bool {
113 return function_traits<Type>::eq(*value, ptr);
114 }
115}; // struct function_traits
116
117template<typename Type>
118struct function_traits<Type, std::enable_if_t<std::is_member_function_pointer_v<Type>>> {
119 static constexpr bool is_disconnectable_v = false;
120 static constexpr bool must_check_object_v = true;
121
122 static auto ptr(Type value, function_ptr& ptr) -> void {
123 ptr.store(value);
124 }
125
126 static auto eq(Type value, const function_ptr& ptr) -> bool {
127 const auto* result = ptr.as<const Type>();
128
129 return result && *result == value;
130 }
131}; // struct function_traits
132
133template<typename Type>
134struct function_traits<Type, std::enable_if_t<has_call_operator_v<Type>>> {
135 using call_type = decltype(&std::remove_reference_t<Type>::operator());
136
137 static constexpr bool is_disconnectable_v = function_traits<call_type>::is_disconnectable_v;
138 static constexpr bool must_check_object_v = function_traits<call_type>::must_check_object_v;
139
140 static auto ptr(const Type& /*t*/, function_ptr& ptr) -> void {
141 function_traits<call_type>::ptr(&Type::operator(), ptr);
142 }
143
144 static auto eq(const Type& /*t*/, const function_ptr& ptr) -> bool {
145 return function_traits<call_type>::eq(&Type::operator(), ptr);
146 }
147}; // struct function_traits
148
149template<typename Type>
150auto get_function_ptr(const Type& value) -> function_ptr {
151 auto ptr = function_ptr{};
152
153 function_traits<std::decay_t<Type>>::ptr(value, ptr);
154
155 return ptr;
156}
157
158template<typename Type>
159auto eq_function_ptr(const Type& value, const function_ptr& ptr) -> bool {
160 return function_traits<std::decay_t<Type>>::eq(value, ptr);
161}
162
163} // namespace sbx::signals
164
165#endif // LIBSBX_SIGNAL_FUNCTION_TRAITS_HPP_
A non-owning pointer that can be used to observe the value of a pointer.
Definition: observer_ptr.hpp:27
Definition: function_traits.hpp:32
Definition: function_traits.hpp:14
Definition: function_traits.hpp:15
Definition: function_traits.hpp:16
Definition: function_traits.hpp:17
Definition: function_traits.hpp:74
Definition: function_traits.hpp:65
Definition: function_traits.hpp:19