Nugget
function_detail.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
5 #ifndef EASTL_FUNCTION_DETAIL_H
6 #define EASTL_FUNCTION_DETAIL_H
7 
8 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
9  #pragma once
10 #endif
11 
12 #include <EABase/eabase.h>
13 #include <EABase/nullptr.h>
14 #include <EABase/config/eacompilertraits.h>
15 
16 #include <EASTL/internal/config.h>
17 #include <EASTL/internal/functional_base.h>
18 #include <EASTL/internal/move_help.h>
19 #include <EASTL/internal/function_help.h>
20 
21 #include <EASTL/type_traits.h>
22 #include <EASTL/utility.h>
23 #include <EASTL/allocator.h>
24 
25 #if EASTL_RTTI_ENABLED
26  #include <typeinfo>
27 #endif
28 
29 #if EASTL_EXCEPTIONS_ENABLED
30  EA_DISABLE_ALL_VC_WARNINGS()
31  #include <new>
32  #include <exception>
33  EA_RESTORE_ALL_VC_WARNINGS()
34 #endif
35 
36 namespace eastl
37 {
38  #if EASTL_EXCEPTIONS_ENABLED
39  class bad_function_call : public std::exception
40  {
41  public:
42  bad_function_call() EA_NOEXCEPT = default;
43 
44  const char* what() const EA_NOEXCEPT EA_OVERRIDE
45  {
46  return "bad function_detail call";
47  }
48  };
49  #endif
50 
51  namespace internal
52  {
53  class unused_class {};
54 
56  {
57  void (*unused_func_ptr)(void);
58  void (unused_class::*unused_func_mem_ptr)(void);
59  void* unused_ptr;
60  };
61 
62  template <int SIZE_IN_BYTES>
64  {
65  static_assert(SIZE_IN_BYTES >= 0, "local buffer storage cannot have a negative size!");
66  template <typename Ret>
67  Ret& GetStorageTypeRef() const
68  {
69  return *reinterpret_cast<Ret*>(const_cast<char*>(&storage[0]));
70  }
71 
72  union
73  {
75  char storage[SIZE_IN_BYTES];
76  };
77  };
78 
79  template <>
80  struct functor_storage<0>
81  {
82  template <typename Ret>
83  Ret& GetStorageTypeRef() const
84  {
85  return *reinterpret_cast<Ret*>(const_cast<char*>(&storage[0]));
86  }
87 
88  union
89  {
91  char storage[sizeof(functor_storage_alignment)];
92  };
93  };
94 
95  template <typename Functor, int SIZE_IN_BYTES>
97  {
98  static EA_CONSTEXPR bool value =
99  sizeof(Functor) <= sizeof(functor_storage<SIZE_IN_BYTES>) &&
100  (eastl::alignment_of_v<functor_storage<SIZE_IN_BYTES>> % eastl::alignment_of_v<Functor>) == 0;
101  };
102 
103 
106  template <int SIZE_IN_BYTES>
108  {
109  public:
111  FunctorStorageType mStorage;
112 
113  enum ManagerOperations : int
114  {
115  MGROPS_DESTRUCT_FUNCTOR = 0,
116  MGROPS_COPY_FUNCTOR = 1,
117  MGROPS_MOVE_FUNCTOR = 2,
118  #if EASTL_RTTI_ENABLED
119  MGROPS_GET_TYPE_INFO = 3,
120  MGROPS_GET_FUNC_PTR = 4,
121  #endif
122  };
123 
124  // Functor can be allocated inplace
125  template <typename Functor, typename = void>
127  {
128  public:
129 
130  static Functor* GetFunctorPtr(const FunctorStorageType& storage) EA_NOEXCEPT
131  {
132  return &(storage.template GetStorageTypeRef<Functor>());
133  }
134 
135  template <typename T>
136  static void CreateFunctor(FunctorStorageType& storage, T&& functor)
137  {
138  ::new (GetFunctorPtr(storage)) Functor(eastl::forward<T>(functor));
139  }
140 
141  static void DestructFunctor(FunctorStorageType& storage)
142  {
143  GetFunctorPtr(storage)->~Functor();
144  }
145 
146  static void CopyFunctor(FunctorStorageType& to, const FunctorStorageType& from)
147  {
148  ::new (GetFunctorPtr(to)) Functor(*GetFunctorPtr(from));
149  }
150 
151  static void MoveFunctor(FunctorStorageType& to, FunctorStorageType& from) EA_NOEXCEPT
152  {
153  ::new (GetFunctorPtr(to)) Functor(eastl::move(*GetFunctorPtr(from)));
154  }
155 
156  static void* Manager(void* to, void* from, typename function_base_detail::ManagerOperations ops) EA_NOEXCEPT
157  {
158  switch (ops)
159  {
160  case MGROPS_DESTRUCT_FUNCTOR:
161  {
162  DestructFunctor(*static_cast<FunctorStorageType*>(to));
163  }
164  break;
165  case MGROPS_COPY_FUNCTOR:
166  {
167  CopyFunctor(*static_cast<FunctorStorageType*>(to),
168  *static_cast<const FunctorStorageType*>(from));
169  }
170  break;
171  case MGROPS_MOVE_FUNCTOR:
172  {
173  MoveFunctor(*static_cast<FunctorStorageType*>(to), *static_cast<FunctorStorageType*>(from));
174  DestructFunctor(*static_cast<FunctorStorageType*>(from));
175  }
176  break;
177  default:
178  break;
179  }
180  return nullptr;
181  }
182  };
183 
184  // Functor is allocated on the heap
185  template <typename Functor>
186  class function_manager_base<Functor, typename eastl::enable_if<!is_functor_inplace_allocatable<Functor, SIZE_IN_BYTES>::value>::type>
187  {
188  public:
189  static Functor* GetFunctorPtr(const FunctorStorageType& storage) EA_NOEXCEPT
190  {
191  return storage.template GetStorageTypeRef<Functor*>();
192  }
193 
194  static Functor*& GetFunctorPtrRef(const FunctorStorageType& storage) EA_NOEXCEPT
195  {
196  return storage.template GetStorageTypeRef<Functor*>();
197  }
198 
199  template <typename T>
200  static void CreateFunctor(FunctorStorageType& storage, T&& functor)
201  {
202  auto& allocator = *EASTLAllocatorDefault();
203  Functor* func = static_cast<Functor*>(allocator.allocate(sizeof(Functor), alignof(Functor), 0));
204 
205  #if EASTL_EXCEPTIONS_ENABLED
206  if (!func)
207  {
208  throw std::bad_alloc();
209  }
210  #else
211  EASTL_ASSERT_MSG(func != nullptr, "Allocation failed!");
212  #endif
213 
214  ::new (static_cast<void*>(func)) Functor(eastl::forward<T>(functor));
215  GetFunctorPtrRef(storage) = func;
216  }
217 
218  static void DestructFunctor(FunctorStorageType& storage)
219  {
220  Functor* func = GetFunctorPtr(storage);
221  if (func)
222  {
223  auto& allocator = *EASTLAllocatorDefault();
224  func->~Functor();
225  allocator.deallocate(static_cast<void*>(func), sizeof(Functor));
226  }
227  }
228 
229  static void CopyFunctor(FunctorStorageType& to, const FunctorStorageType& from)
230  {
231  auto& allocator = *EASTLAllocatorDefault();
232  Functor* func = static_cast<Functor*>(allocator.allocate(sizeof(Functor), alignof(Functor), 0));
233  #if EASTL_EXCEPTIONS_ENABLED
234  if (!func)
235  {
236  throw std::bad_alloc();
237  }
238  #else
239  EASTL_ASSERT_MSG(func != nullptr, "Allocation failed!");
240  #endif
241  ::new (static_cast<void*>(func)) Functor(*GetFunctorPtr(from));
242  GetFunctorPtrRef(to) = func;
243  }
244 
245  static void MoveFunctor(FunctorStorageType& to, FunctorStorageType& from) EA_NOEXCEPT
246  {
247  Functor* func = GetFunctorPtr(from);
248  GetFunctorPtrRef(to) = func;
249  GetFunctorPtrRef(from) = nullptr;
250  }
251 
252  static void* Manager(void* to, void* from, typename function_base_detail::ManagerOperations ops) EA_NOEXCEPT
253  {
254  switch (ops)
255  {
256  case MGROPS_DESTRUCT_FUNCTOR:
257  {
258  DestructFunctor(*static_cast<FunctorStorageType*>(to));
259  }
260  break;
261  case MGROPS_COPY_FUNCTOR:
262  {
263  CopyFunctor(*static_cast<FunctorStorageType*>(to),
264  *static_cast<const FunctorStorageType*>(from));
265  }
266  break;
267  case MGROPS_MOVE_FUNCTOR:
268  {
269  MoveFunctor(*static_cast<FunctorStorageType*>(to), *static_cast<FunctorStorageType*>(from));
270  // Moved ptr, no need to destruct ourselves
271  }
272  break;
273  default:
274  break;
275  }
276  return nullptr;
277  }
278  };
279 
280  template <typename Functor, typename R, typename... Args>
281  class function_manager final : public function_manager_base<Functor>
282  {
283  public:
285 
286  #if EASTL_RTTI_ENABLED
287  static void* GetTypeInfo() EA_NOEXCEPT
288  {
289  return reinterpret_cast<void*>(const_cast<std::type_info*>(&typeid(Functor)));
290  }
291 
292  static void* Manager(void* to, void* from, typename function_base_detail::ManagerOperations ops) EA_NOEXCEPT
293  {
294  switch (ops)
295  {
296  case MGROPS_GET_TYPE_INFO:
297  {
298  return GetTypeInfo();
299  }
300  break;
301  case MGROPS_GET_FUNC_PTR:
302  {
303  return static_cast<void*>(Base::GetFunctorPtr(*static_cast<FunctorStorageType*>(to)));
304  }
305  break;
306  default:
307  {
308  return Base::Manager(to, from, ops);
309  }
310  break;
311  }
312  }
313  #endif // EASTL_RTTI_ENABLED
314 
394  static R Invoker(Args... args, const FunctorStorageType& functor)
395  {
396  return eastl::invoke(*Base::GetFunctorPtr(functor), eastl::forward<Args>(args)...);
397  }
398  };
399 
400  function_base_detail() EA_NOEXCEPT = default;
401  ~function_base_detail() EA_NOEXCEPT = default;
402  };
403 
404  #define EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(FUNCTOR, RET, ARGS, BASE, MYSELF) \
405  typename eastl::enable_if_t<eastl::is_invocable_r_v<RET, FUNCTOR, ARGS> && \
406  !eastl::is_base_of_v<BASE, eastl::decay_t<FUNCTOR>> && \
407  !eastl::is_same_v<eastl::decay_t<FUNCTOR>, MYSELF>>
408 
409  #define EASTL_INTERNAL_FUNCTION_DETAIL_VALID_FUNCTION_ARGS(FUNCTOR, RET, ARGS, MYSELF) \
410  EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(FUNCTOR, RET, ARGS, MYSELF, MYSELF)
411 
412 
415  template <int, typename>
417 
418  template <int SIZE_IN_BYTES, typename R, typename... Args>
419  class function_detail<SIZE_IN_BYTES, R(Args...)> : public function_base_detail<SIZE_IN_BYTES>
420  {
421  public:
422  using result_type = R;
423 
424  protected:
427  using Base::mStorage;
428 
429  public:
430  function_detail() EA_NOEXCEPT = default;
431  function_detail(std::nullptr_t) EA_NOEXCEPT {}
432 
433  function_detail(const function_detail& other)
434  {
435  if (this != &other)
436  {
437  Copy(other);
438  }
439  }
440 
442  {
443  if (this != &other)
444  {
445  Move(eastl::move(other));
446  }
447  }
448 
449  template <typename Functor, typename = EASTL_INTERNAL_FUNCTION_DETAIL_VALID_FUNCTION_ARGS(Functor, R, Args..., function_detail)>
450  function_detail(Functor functor)
451  {
452  CreateForwardFunctor(eastl::move(functor));
453  }
454 
455  ~function_detail() EA_NOEXCEPT
456  {
457  Destroy();
458  }
459 
460  function_detail& operator=(const function_detail& other)
461  {
462  if (this != &other)
463  {
464  Destroy();
465  Copy(other);
466  }
467 
468  return *this;
469  }
470 
471  function_detail& operator=(function_detail&& other)
472  {
473  if(this != &other)
474  {
475  Destroy();
476  Move(eastl::move(other));
477  }
478 
479  return *this;
480  }
481 
482  function_detail& operator=(std::nullptr_t) EA_NOEXCEPT
483  {
484  Destroy();
485  mMgrFuncPtr = nullptr;
486  mInvokeFuncPtr = &DefaultInvoker;
487 
488  return *this;
489  }
490 
491  template <typename Functor, typename = EASTL_INTERNAL_FUNCTION_DETAIL_VALID_FUNCTION_ARGS(Functor, R, Args..., function_detail)>
492  function_detail& operator=(Functor&& functor)
493  {
494  Destroy();
495  CreateForwardFunctor(eastl::forward<Functor>(functor));
496  return *this;
497  }
498 
499  template <typename Functor>
500  function_detail& operator=(eastl::reference_wrapper<Functor> f) EA_NOEXCEPT
501  {
502  Destroy();
503  CreateForwardFunctor(f);
504  return *this;
505  }
506 
507  void swap(function_detail& other) EA_NOEXCEPT
508  {
509  if(this == &other)
510  return;
511 
512  FunctorStorageType tempStorage;
513  if (other.HaveManager())
514  {
515  (void)(*other.mMgrFuncPtr)(static_cast<void*>(&tempStorage), static_cast<void*>(&other.mStorage),
516  Base::ManagerOperations::MGROPS_MOVE_FUNCTOR);
517  }
518 
519  if (HaveManager())
520  {
521  (void)(*mMgrFuncPtr)(static_cast<void*>(&other.mStorage), static_cast<void*>(&mStorage),
522  Base::ManagerOperations::MGROPS_MOVE_FUNCTOR);
523  }
524 
525  if (other.HaveManager())
526  {
527  (void)(*other.mMgrFuncPtr)(static_cast<void*>(&mStorage), static_cast<void*>(&tempStorage),
528  Base::ManagerOperations::MGROPS_MOVE_FUNCTOR);
529  }
530 
531  eastl::swap(mMgrFuncPtr, other.mMgrFuncPtr);
532  eastl::swap(mInvokeFuncPtr, other.mInvokeFuncPtr);
533  }
534 
535  explicit operator bool() const EA_NOEXCEPT
536  {
537  return HaveManager();
538  }
539 
540  EASTL_FORCE_INLINE R operator ()(Args... args) const
541  {
542  return (*mInvokeFuncPtr)(eastl::forward<Args>(args)..., this->mStorage);
543  }
544 
545  #if EASTL_RTTI_ENABLED
546  const std::type_info& target_type() const EA_NOEXCEPT
547  {
548  if (HaveManager())
549  {
550  void* ret = (*mMgrFuncPtr)(nullptr, nullptr, Base::ManagerOperations::MGROPS_GET_TYPE_INFO);
551  return *(static_cast<const std::type_info*>(ret));
552  }
553  return typeid(void);
554  }
555 
556  template <typename Functor>
557  Functor* target() EA_NOEXCEPT
558  {
559  if (HaveManager() && target_type() == typeid(Functor))
560  {
561  void* ret = (*mMgrFuncPtr)(static_cast<void*>(&mStorage), nullptr,
562  Base::ManagerOperations::MGROPS_GET_FUNC_PTR);
563  return ret ? static_cast<Functor*>(ret) : nullptr;
564  }
565  return nullptr;
566  }
567 
568  template <typename Functor>
569  const Functor* target() const EA_NOEXCEPT
570  {
571  if (HaveManager() && target_type() == typeid(Functor))
572  {
573  void* ret = (*mMgrFuncPtr)(static_cast<void*>(&mStorage), nullptr,
574  Base::ManagerOperations::MGROPS_GET_FUNC_PTR);
575  return ret ? static_cast<const Functor*>(ret) : nullptr;
576  }
577  return nullptr;
578  }
579  #endif // EASTL_RTTI_ENABLED
580 
581  private:
582  bool HaveManager() const EA_NOEXCEPT
583  {
584  return (mMgrFuncPtr != nullptr);
585  }
586 
587  void Destroy() EA_NOEXCEPT
588  {
589  if (HaveManager())
590  {
591  (void)(*mMgrFuncPtr)(static_cast<void*>(&mStorage), nullptr,
592  Base::ManagerOperations::MGROPS_DESTRUCT_FUNCTOR);
593  }
594  }
595 
596  void Copy(const function_detail& other)
597  {
598  if (other.HaveManager())
599  {
600  (void)(*other.mMgrFuncPtr)(static_cast<void*>(&mStorage),
601  const_cast<void*>(static_cast<const void*>(&other.mStorage)),
602  Base::ManagerOperations::MGROPS_COPY_FUNCTOR);
603  }
604 
605  mMgrFuncPtr = other.mMgrFuncPtr;
606  mInvokeFuncPtr = other.mInvokeFuncPtr;
607  }
608 
609  void Move(function_detail&& other)
610  {
611  if (other.HaveManager())
612  {
613  (void)(*other.mMgrFuncPtr)(static_cast<void*>(&mStorage), static_cast<void*>(&other.mStorage),
614  Base::ManagerOperations::MGROPS_MOVE_FUNCTOR);
615  }
616 
617  mMgrFuncPtr = other.mMgrFuncPtr;
618  mInvokeFuncPtr = other.mInvokeFuncPtr;
619  other.mMgrFuncPtr = nullptr;
620  other.mInvokeFuncPtr = &DefaultInvoker;
621  }
622 
623  template <typename Functor>
624  void CreateForwardFunctor(Functor&& functor)
625  {
626  using DecayedFunctorType = typename eastl::decay<Functor>::type;
627  using FunctionManagerType = typename Base::template function_manager<DecayedFunctorType, R, Args...>;
628 
629  if (internal::is_null(functor))
630  {
631  mMgrFuncPtr = nullptr;
632  mInvokeFuncPtr = &DefaultInvoker;
633  }
634  else
635  {
636  mMgrFuncPtr = &FunctionManagerType::Manager;
637  mInvokeFuncPtr = &FunctionManagerType::Invoker;
638  FunctionManagerType::CreateFunctor(mStorage, eastl::forward<Functor>(functor));
639  }
640  }
641 
642  private:
643  typedef void* (*ManagerFuncPtr)(void*, void*, typename Base::ManagerOperations);
644  typedef R (*InvokeFuncPtr)(Args..., const FunctorStorageType&);
645 
646  EA_DISABLE_GCC_WARNING(-Wreturn-type);
647  EA_DISABLE_CLANG_WARNING(-Wreturn-type);
648  EA_DISABLE_VC_WARNING(4716); // 'function' must return a value
649  // We cannot assume that R is default constructible.
650  // This function is called only when the function object CANNOT be called because it is empty,
651  // it will always throw or assert so we never use the return value anyways and neither should the caller.
652  static R DefaultInvoker(Args... /*args*/, const FunctorStorageType& /*functor*/)
653  {
654  #if EASTL_EXCEPTIONS_ENABLED
655  throw eastl::bad_function_call();
656  #else
657  EASTL_ASSERT_MSG(false, "function_detail call on an empty function_detail<R(Args..)>");
658  #endif
659  };
660  EA_RESTORE_VC_WARNING();
661  EA_RESTORE_CLANG_WARNING();
662  EA_RESTORE_GCC_WARNING();
663 
664 
665  ManagerFuncPtr mMgrFuncPtr = nullptr;
666  InvokeFuncPtr mInvokeFuncPtr = &DefaultInvoker;
667  };
668 
669  } // namespace internal
670 
671 } // namespace eastl
672 
673 #endif // EASTL_FUNCTION_DETAIL_H
Definition: allocator.h:52
static R Invoker(Args... args, const FunctorStorageType &functor)
Definition: function_detail.h:394
Definition: function_detail.h:108
Definition: function_detail.h:416
Definition: function_detail.h:53
reference_wrapper
Definition: functional_base.h:221
EA Standard Template Library.
Definition: algorithm.h:288
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:170
Definition: type_traits.h:494
Definition: type_traits.h:442
Definition: function_detail.h:64
Definition: function_detail.h:97
Definition: function_detail.h:56