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