scc 2026.07
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 new(store_.get()) functor_type(::std::forward<T>(f));
88 object_ptr_ = store_.get();
89 stub_ptr_ = functor_stub<functor_type>;
90 deleter_ = deleter_stub<functor_type>;
91 }
92
93 delegate& operator=(delegate const&) = default;
94
95 delegate& operator=(delegate&&) = default;
96
97 template <class C> delegate& operator=(R (C::*const rhs)(A...)) { return *this = from(static_cast<C*>(object_ptr_), rhs); }
98
99 template <class C> delegate& operator=(R (C::*const rhs)(A...) const) { return *this = from(static_cast<C const*>(object_ptr_), rhs); }
100
101 template <typename T, typename = typename ::std::enable_if<!::std::is_same<delegate, typename ::std::decay<T>::type>{}>::type>
102 delegate& operator=(T&& f) {
103 using functor_type = typename ::std::decay<T>::type;
104
105 if((sizeof(functor_type) > store_size_) || store_.use_count() != 1) {
106 store_.reset(operator new(sizeof(functor_type)), functor_deleter<functor_type>);
107 store_size_ = sizeof(functor_type);
108 } else {
109 deleter_(store_.get());
110 }
111
112 new(store_.get()) functor_type(::std::forward<T>(f));
113
114 object_ptr_ = store_.get();
115
116 stub_ptr_ = functor_stub<functor_type>;
117
118 deleter_ = deleter_stub<functor_type>;
119
120 return *this;
121 }
122
123 template <R (*const function_ptr)(A...)> static delegate from() noexcept { return {nullptr, function_stub<function_ptr>}; }
124
125 template <class C, R (C::*const method_ptr)(A...)> static delegate from(C* const object_ptr) noexcept {
126 return {object_ptr, method_stub<C, method_ptr>};
127 }
128
129 template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const* const object_ptr) noexcept {
130 return {const_cast<C*>(object_ptr), const_method_stub<C, method_ptr>};
131 }
132
133 template <class C, R (C::*const method_ptr)(A...)> static delegate from(C& object) noexcept {
134 return {&object, method_stub<C, method_ptr>};
135 }
136
137 template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const& object) noexcept {
138 return {const_cast<C*>(&object), const_method_stub<C, method_ptr>};
139 }
140
141 template <typename T> static delegate from(T&& f) { return ::std::forward<T>(f); }
142
143 static delegate from(R (*const function_ptr)(A...)) { return function_ptr; }
144
145 template <class C> using member_pair = ::std::pair<C* const, R (C::*const)(A...)>;
146
147 template <class C> using const_member_pair = ::std::pair<C const* const, R (C::*const)(A...) const>;
148
149 template <class C> static delegate from(C* const object_ptr, R (C::*const method_ptr)(A...)) {
150 return member_pair<C>(object_ptr, method_ptr);
151 }
152
153 template <class C> static delegate from(C const* const object_ptr, R (C::*const method_ptr)(A...) const) {
154 return const_member_pair<C>(object_ptr, method_ptr);
155 }
156
157 template <class C> static delegate from(C& object, R (C::*const method_ptr)(A...)) { return member_pair<C>(&object, method_ptr); }
158
159 template <class C> static delegate from(C const& object, R (C::*const method_ptr)(A...) const) {
160 return const_member_pair<C>(&object, method_ptr);
161 }
162
163 void reset() {
164 stub_ptr_ = nullptr;
165 store_.reset();
166 }
167
168 void reset_stub() noexcept { stub_ptr_ = nullptr; }
169
170 void swap(delegate& other) noexcept { ::std::swap(*this, other); }
171
172 bool operator==(delegate const& rhs) const noexcept { return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_); }
173
174 bool operator!=(delegate const& rhs) const noexcept { return !operator==(rhs); }
175
176 bool operator<(delegate const& rhs) const noexcept {
177 return (object_ptr_ < rhs.object_ptr_) || ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_));
178 }
179
180 bool operator==(::std::nullptr_t const) const noexcept { return !stub_ptr_; }
181
182 bool operator!=(::std::nullptr_t const) const noexcept { return stub_ptr_; }
183
184 explicit operator bool() const noexcept { return stub_ptr_; }
185
186 R operator()(A... args) const {
187 // assert(stub_ptr);
188 return stub_ptr_(object_ptr_, ::std::forward<A>(args)...);
189 }
190
191private:
192 friend struct ::std::hash<delegate>;
193
194 using deleter_type = void (*)(void*);
195
196 void* object_ptr_{nullptr};
197 stub_ptr_type stub_ptr_{nullptr};
198
199 deleter_type deleter_{};
200
201 ::std::shared_ptr<void> store_;
202 ::std::size_t store_size_{0};
203
204 template <class T> static void functor_deleter(void* const p) {
205 static_cast<T*>(p)->~T();
206
207 operator delete(p);
208 }
209
210 template <class T> static void deleter_stub(void* const p) { static_cast<T*>(p)->~T(); }
211
212 template <R (*function_ptr)(A...)> static R function_stub(void* const, A&&... args) { return function_ptr(::std::forward<A>(args)...); }
213
214 template <class C, R (C::*method_ptr)(A...)> static R method_stub(void* const object_ptr, A&&... args) {
215 return (static_cast<C*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
216 }
217
218 template <class C, R (C::*method_ptr)(A...) const> static R const_method_stub(void* const object_ptr, A&&... args) {
219 return (static_cast<C const*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
220 }
221
222 template <typename> struct is_member_pair : std::false_type {};
223
224 template <class C> struct is_member_pair<::std::pair<C* const, R (C::*const)(A...)>> : std::true_type {};
225
226 template <typename> struct is_const_member_pair : std::false_type {};
227
228 template <class C> struct is_const_member_pair<::std::pair<C const* const, R (C::*const)(A...) const>> : std::true_type {};
229
230 template <typename T>
231 static typename ::std::enable_if<!(is_member_pair<T>{} || is_const_member_pair<T>{}), R>::type functor_stub(void* const object_ptr,
232 A&&... args) {
233 return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
234 }
235
236 template <typename T>
237 static typename ::std::enable_if<is_member_pair<T>{} || is_const_member_pair<T>{}, R>::type functor_stub(void* const object_ptr,
238 A&&... args) {
239 return (static_cast<T*>(object_ptr)->first->*static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
240 }
241};
242} // namespace util
244
245namespace std {
246template <typename R, typename... A> struct hash<util::delegate<R(A...)>> {
247 size_t operator()(util::delegate<R(A...)> const& d) const noexcept {
248 auto const seed(hash<void*>()(d.object_ptr_));
249
250 return hash<typename util::delegate<R(A...)>::stub_ptr_type>()(d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
251 }
252};
253} // namespace std
254
255#endif /* SC_COMPONENTS_INCL_UTIL_DELEGATE_H_ */
SCC common utilities.
Definition bit_field.h:30