scc  2022.4.0
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 
34 namespace util {
35 template <typename T> class delegate;
37 template <class R, class... A> class delegate<R(A...)> {
38  using stub_ptr_type = R (*)(void*, A&&...);
39 
40  delegate(void* const o, stub_ptr_type const m) noexcept
41  : object_ptr_(o)
42  , stub_ptr_(m) {}
43 
44 public:
45  delegate() = default;
46 
47  delegate(delegate const&) = default;
48 
49  delegate(delegate&&) = default;
50 
51  delegate(::std::nullptr_t const) noexcept
52  : delegate() {}
53 
54  template <class C, typename = typename ::std::enable_if<::std::is_class<C>{}>::type>
55  explicit delegate(C const* const o) noexcept
56  : object_ptr_(const_cast<C*>(o)) {}
57 
58  template <class C, typename = typename ::std::enable_if<::std::is_class<C>{}>::type>
59  explicit delegate(C const& o) noexcept
60  : object_ptr_(const_cast<C*>(&o)) {}
61 
62  template <class C> delegate(C* const object_ptr, R (C::*const method_ptr)(A...)) { *this = from(object_ptr, method_ptr); }
63 
64  template <class C> delegate(C* const object_ptr, R (C::*const method_ptr)(A...) const) { *this = from(object_ptr, method_ptr); }
65 
66  template <class C> delegate(C& object, R (C::*const method_ptr)(A...)) { *this = from(object, method_ptr); }
67 
68  template <class C> delegate(C const& object, R (C::*const method_ptr)(A...) const) { *this = from(object, method_ptr); }
69 
70  template <typename T, typename = typename ::std::enable_if<!::std::is_same<delegate, typename ::std::decay<T>::type>{}>::type>
71  delegate(T&& f)
72  : store_(operator new(sizeof(typename ::std::decay<T>::type)), functor_deleter<typename ::std::decay<T>::type>)
73  , store_size_(sizeof(typename ::std::decay<T>::type)) {
74  using functor_type = typename ::std::decay<T>::type;
75 
76  new(store_.get()) functor_type(::std::forward<T>(f));
77 
78  object_ptr_ = store_.get();
79 
80  stub_ptr_ = functor_stub<functor_type>;
81 
82  deleter_ = deleter_stub<functor_type>;
83  }
84 
85  delegate& operator=(delegate const&) = default;
86 
87  delegate& operator=(delegate&&) = default;
88 
89  template <class C> delegate& operator=(R (C::*const rhs)(A...)) { return *this = from(static_cast<C*>(object_ptr_), rhs); }
90 
91  template <class C> delegate& operator=(R (C::*const rhs)(A...) const) { return *this = from(static_cast<C const*>(object_ptr_), rhs); }
92 
93  template <typename T, typename = typename ::std::enable_if<!::std::is_same<delegate, typename ::std::decay<T>::type>{}>::type>
94  delegate& operator=(T&& f) {
95  using functor_type = typename ::std::decay<T>::type;
96 
97  if((sizeof(functor_type) > store_size_) || !store_.unique()) {
98  store_.reset(operator new(sizeof(functor_type)), functor_deleter<functor_type>);
99 
100  store_size_ = sizeof(functor_type);
101  } else {
102  deleter_(store_.get());
103  }
104 
105  new(store_.get()) functor_type(::std::forward<T>(f));
106 
107  object_ptr_ = store_.get();
108 
109  stub_ptr_ = functor_stub<functor_type>;
110 
111  deleter_ = deleter_stub<functor_type>;
112 
113  return *this;
114  }
115 
116  template <R (*const function_ptr)(A...)> static delegate from() noexcept { return {nullptr, function_stub<function_ptr>}; }
117 
118  template <class C, R (C::*const method_ptr)(A...)> static delegate from(C* const object_ptr) noexcept {
119  return {object_ptr, method_stub<C, method_ptr>};
120  }
121 
122  template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const* const object_ptr) noexcept {
123  return {const_cast<C*>(object_ptr), const_method_stub<C, method_ptr>};
124  }
125 
126  template <class C, R (C::*const method_ptr)(A...)> static delegate from(C& object) noexcept {
127  return {&object, method_stub<C, method_ptr>};
128  }
129 
130  template <class C, R (C::*const method_ptr)(A...) const> static delegate from(C const& object) noexcept {
131  return {const_cast<C*>(&object), const_method_stub<C, method_ptr>};
132  }
133 
134  template <typename T> static delegate from(T&& f) { return ::std::forward<T>(f); }
135 
136  static delegate from(R (*const function_ptr)(A...)) { return function_ptr; }
137 
138  template <class C> using member_pair = ::std::pair<C* const, R (C::*const)(A...)>;
139 
140  template <class C> using const_member_pair = ::std::pair<C const* const, R (C::*const)(A...) const>;
141 
142  template <class C> static delegate from(C* const object_ptr, R (C::*const method_ptr)(A...)) {
143  return member_pair<C>(object_ptr, method_ptr);
144  }
145 
146  template <class C> static delegate from(C const* const object_ptr, R (C::*const method_ptr)(A...) const) {
147  return const_member_pair<C>(object_ptr, method_ptr);
148  }
149 
150  template <class C> static delegate from(C& object, R (C::*const method_ptr)(A...)) { return member_pair<C>(&object, method_ptr); }
151 
152  template <class C> static delegate from(C const& object, R (C::*const method_ptr)(A...) const) {
153  return const_member_pair<C>(&object, method_ptr);
154  }
155 
156  void reset() {
157  stub_ptr_ = nullptr;
158  store_.reset();
159  }
160 
161  void reset_stub() noexcept { stub_ptr_ = nullptr; }
162 
163  void swap(delegate& other) noexcept { ::std::swap(*this, other); }
164 
165  bool operator==(delegate const& rhs) const noexcept { return (object_ptr_ == rhs.object_ptr_) && (stub_ptr_ == rhs.stub_ptr_); }
166 
167  bool operator!=(delegate const& rhs) const noexcept { return !operator==(rhs); }
168 
169  bool operator<(delegate const& rhs) const noexcept {
170  return (object_ptr_ < rhs.object_ptr_) || ((object_ptr_ == rhs.object_ptr_) && (stub_ptr_ < rhs.stub_ptr_));
171  }
172 
173  bool operator==(::std::nullptr_t const) const noexcept { return !stub_ptr_; }
174 
175  bool operator!=(::std::nullptr_t const) const noexcept { return stub_ptr_; }
176 
177  explicit operator bool() const noexcept { return stub_ptr_; }
178 
179  R operator()(A... args) const {
180  // assert(stub_ptr);
181  return stub_ptr_(object_ptr_, ::std::forward<A>(args)...);
182  }
183 
184 private:
185  friend class ::std::hash<delegate>;
186 
187  using deleter_type = void (*)(void*);
188 
189  void* object_ptr_{};
190  stub_ptr_type stub_ptr_{};
191 
192  deleter_type deleter_{};
193 
194  ::std::shared_ptr<void> store_;
195  ::std::size_t store_size_{0};
196 
197  template <class T> static void functor_deleter(void* const p) {
198  static_cast<T*>(p)->~T();
199 
200  operator delete(p);
201  }
202 
203  template <class T> static void deleter_stub(void* const p) { static_cast<T*>(p)->~T(); }
204 
205  template <R (*function_ptr)(A...)> static R function_stub(void* const, A&&... args) { return function_ptr(::std::forward<A>(args)...); }
206 
207  template <class C, R (C::*method_ptr)(A...)> static R method_stub(void* const object_ptr, A&&... args) {
208  return (static_cast<C*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
209  }
210 
211  template <class C, R (C::*method_ptr)(A...) const> static R const_method_stub(void* const object_ptr, A&&... args) {
212  return (static_cast<C const*>(object_ptr)->*method_ptr)(::std::forward<A>(args)...);
213  }
214 
215  template <typename> class is_member_pair : std::false_type {};
216 
217  template <class C> class is_member_pair<::std::pair<C* const, R (C::*const)(A...)>> : std::true_type {};
218 
219  template <typename> class is_const_member_pair : std::false_type {};
220 
221  template <class C> class is_const_member_pair<::std::pair<C const* const, R (C::*const)(A...) const>> : std::true_type {};
222 
223  template <typename T>
224  static typename ::std::enable_if<!(is_member_pair<T>{} || is_const_member_pair<T>{}), R>::type functor_stub(void* const object_ptr,
225  A&&... args) {
226  return (*static_cast<T*>(object_ptr))(::std::forward<A>(args)...);
227  }
228 
229  template <typename T>
230  static typename ::std::enable_if<is_member_pair<T>{} || is_const_member_pair<T>{}, R>::type functor_stub(void* const object_ptr,
231  A&&... args) {
232  return (static_cast<T*>(object_ptr)->first->*static_cast<T*>(object_ptr)->second)(::std::forward<A>(args)...);
233  }
234 };
235 } // namespace util
238 namespace std {
240 template <typename R, typename... A> class hash<util::delegate<R(A...)>> {
241 public:
242  size_t operator()(util::delegate<R(A...)> const& d) const noexcept {
243  auto const seed(hash<void*>()(d.object_ptr_));
244 
245  return hash<typename util::delegate<R(A...)>::stub_ptr_type>()(d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
246  }
247 };
248 } // namespace std
249 
250 #endif /* SC_COMPONENTS_INCL_UTIL_DELEGATE_H_ */
SCC common utilities.
Definition: bit_field.h:30