scc 2025.09
SystemC components library
delegate.h
1/*******************************************************************************
2 * Copyright 2018 MINRES Technologies GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16/*
17 * delegate.h according https://codereview.stackexchange.com/questions/14730/impossibly-fast-delegate-in-c11
18 */
19
20#ifndef _UTIL_DELEGATE_H_
21#define _UTIL_DELEGATE_H_
22
23#include <cassert>
24#include <memory>
25#include <new>
26#include <type_traits>
27#include <utility>
28
36namespace util {
37template <typename T> class delegate;
49template <class R, class... A> class delegate<R(A...)> {
50 using stub_ptr_type = R (*)(void*, A&&...);
51
52 delegate(void* const o, stub_ptr_type const m) noexcept
53 : object_ptr_(o)
54 , stub_ptr_(m) {}
55
56public:
57 delegate() = default;
58
59 delegate(delegate const&) = default;
60
61 delegate(delegate&&) = default;
62
63 delegate(::std::nullptr_t const) noexcept
64 : delegate() {}
65
66 template <class C, typename = typename ::std::enable_if<::std::is_class<C>{}>::type>
67 explicit delegate(C const* const o) noexcept
68 : object_ptr_(const_cast<C*>(o)) {}
69
70 template <class C, typename = typename ::std::enable_if<::std::is_class<C>{}>::type>
71 explicit delegate(C const& o) noexcept
72 : object_ptr_(const_cast<C*>(&o)) {}
73
74 template <class C> delegate(C* const object_ptr, R (C::*const method_ptr)(A...)) { *this = from(object_ptr, method_ptr); }
75
76 template <class C> delegate(C* const object_ptr, R (C::*const method_ptr)(A...) const) { *this = from(object_ptr, method_ptr); }
77
78 template <class C> delegate(C& object, R (C::*const method_ptr)(A...)) { *this = from(object, method_ptr); }
79
80 template <class C> delegate(C const& object, R (C::*const method_ptr)(A...) const) { *this = from(object, method_ptr); }
81
82 template <typename T, typename = typename ::std::enable_if<!::std::is_same<delegate, typename ::std::decay<T>::type>{}>::type>
83 delegate(T&& f)
84 : store_(operator new(sizeof(typename ::std::decay<T>::type)), functor_deleter<typename ::std::decay<T>::type>)
85 , store_size_(sizeof(typename ::std::decay<T>::type)) {
86 using functor_type = typename ::std::decay<T>::type;
87
88 new(store_.get()) functor_type(::std::forward<T>(f));
89
90 object_ptr_ = store_.get();
91
92 stub_ptr_ = functor_stub<functor_type>;
93
94 deleter_ = deleter_stub<functor_type>;
95 }
96
97 delegate& operator=(delegate const&) = default;
98
99 delegate& operator=(delegate&&) = default;
100
101 template <class C> delegate& operator=(R (C::*const rhs)(A...)) { return *this = from(static_cast<C*>(object_ptr_), rhs); }
102
103 template <class C> delegate& operator=(R (C::*const rhs)(A...) const) { return *this = from(static_cast<C const*>(object_ptr_), rhs); }
104
105 template <typename T, typename = typename ::std::enable_if<!::std::is_same<delegate, typename ::std::decay<T>::type>{}>::type>
106 delegate& operator=(T&& f) {
107 using functor_type = typename ::std::decay<T>::type;
108
109 if((sizeof(functor_type) > store_size_) || !store_.unique()) {
110 store_.reset(operator new(sizeof(functor_type)), functor_deleter<functor_type>);
111
112 store_size_ = sizeof(functor_type);
113 } else {
114 deleter_(store_.get());
115 }
116
117 new(store_.get()) functor_type(::std::forward<T>(f));
118
119 object_ptr_ = store_.get();
120
121 stub_ptr_ = functor_stub<functor_type>;
122
123 deleter_ = deleter_stub<functor_type>;
124
125 return *this;
126 }
127
128 template <R (*const function_ptr)(A...)> static delegate from() noexcept { return {nullptr, function_stub<function_ptr>}; }
129
130 template <class C, R (C::*const method_ptr)(A...)> static delegate from(C* const object_ptr) noexcept {
131 return {object_ptr, method_stub<C, method_ptr>};
132 }
133
134 template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const* const object_ptr) noexcept {
135 return {const_cast<C*>(object_ptr), const_method_stub<C, method_ptr>};
136 }
137
138 template <class C, R (C::*const method_ptr)(A...)> static delegate from(C& object) noexcept {
139 return {&object, method_stub<C, method_ptr>};
140 }
141
142 template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const& object) noexcept {
143 return {const_cast<C*>(&object), const_method_stub<C, method_ptr>};
144 }
145
146 template <typename T> static delegate from(T&& f) { return ::std::forward<T>(f); }
147
148 static delegate from(R (*const function_ptr)(A...)) { return function_ptr; }
149
150 template <class C> using member_pair = ::std::pair<C* const, R (C::*const)(A...)>;
151
152 template <class C> using const_member_pair = ::std::pair<C const* const, R (C::*const)(A...) const>;
153
154 template <class C> static delegate from(C* const object_ptr, R (C::*const method_ptr)(A...)) {
155 return member_pair<C>(object_ptr, method_ptr);
156 }
157
158 template <class C> static delegate from(C const* const object_ptr, R (C::*const method_ptr)(A...) const) {
159 return const_member_pair<C>(object_ptr, method_ptr);
160 }
161
162 template <class C> static delegate from(C& object, R (C::*const method_ptr)(A...)) { return member_pair<C>(&object, method_ptr); }
163
164 template <class C> static delegate from(C const& object, R (C::*const method_ptr)(A...) const) {
165 return const_member_pair<C>(&object, method_ptr);
166 }
167
168 void reset() {
169 stub_ptr_ = nullptr;
170 store_.reset();
171 }
172
173 void reset_stub() noexcept { stub_ptr_ = nullptr; }
174
175 void swap(delegate& other) noexcept { ::std::swap(*this, other); }
176
177 bool operator==(delegate const& rhs) const noexcept { return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_); }
178
179 bool operator!=(delegate const& rhs) const noexcept { return !operator==(rhs); }
180
181 bool operator<(delegate const& rhs) const noexcept {
182 return (object_ptr_ < rhs.object_ptr_) || ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_));
183 }
184
185 bool operator==(::std::nullptr_t const) const noexcept { return !stub_ptr_; }
186
187 bool operator!=(::std::nullptr_t const) const noexcept { return stub_ptr_; }
188
189 explicit operator bool() const noexcept { return stub_ptr_; }
190
191 R operator()(A... args) const {
192 // assert(stub_ptr);
193 return stub_ptr_(object_ptr_, ::std::forward<A>(args)...);
194 }
195
196private:
197 friend struct ::std::hash<delegate>;
198
199 using deleter_type = void (*)(void*);
200
201 void* object_ptr_{nullptr};
202 stub_ptr_type stub_ptr_{};
203
204 deleter_type deleter_{};
205
206 ::std::shared_ptr<void> store_;
207 ::std::size_t store_size_{0};
208
209 template <class T> static void functor_deleter(void* const p) {
210 static_cast<T*>(p)->~T();
211
212 operator delete(p);
213 }
214
215 template <class T> static void deleter_stub(void* const p) { static_cast<T*>(p)->~T(); }
216
217 template <R (*function_ptr)(A...)> static R function_stub(void* const, A&&... args) { return function_ptr(::std::forward<A>(args)...); }
218
219 template <class C, R (C::*method_ptr)(A...)> static R method_stub(void* const object_ptr, A&&... args) {
220 return (static_cast<C*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
221 }
222
223 template <class C, R (C::*method_ptr)(A...) const> static R const_method_stub(void* const object_ptr, A&&... args) {
224 return (static_cast<C const*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
225 }
226
227 template <typename> struct is_member_pair : std::false_type {};
228
229 template <class C> struct is_member_pair<::std::pair<C* const, R (C::*const)(A...)>> : std::true_type {};
230
231 template <typename> struct is_const_member_pair : std::false_type {};
232
233 template <class C> struct is_const_member_pair<::std::pair<C const* const, R (C::*const)(A...) const>> : std::true_type {};
234
235 template <typename T>
236 static typename ::std::enable_if<!(is_member_pair<T>{} || is_const_member_pair<T>{}), R>::type functor_stub(void* const object_ptr,
237 A&&... args) {
238 return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
239 }
240
241 template <typename T>
242 static typename ::std::enable_if<is_member_pair<T>{} || is_const_member_pair<T>{}, R>::type functor_stub(void* const object_ptr,
243 A&&... args) {
244 return (static_cast<T*>(object_ptr)->first->*static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
245 }
246};
247} // namespace util
249
250namespace std {
251template <typename R, typename... A> struct hash<util::delegate<R(A...)>> {
252 size_t operator()(util::delegate<R(A...)> const& d) const noexcept {
253 auto const seed(hash<void*>()(d.object_ptr_));
254
255 return hash<typename util::delegate<R(A...)>::stub_ptr_type>()(d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
256 }
257};
258} // namespace std
259
260#endif /* SC_COMPONENTS_INCL_UTIL_DELEGATE_H_ */
SCC common utilities.
Definition bit_field.h:30