You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

function2.hpp 70KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792
  1. // Copyright 2015-2020 Denis Blank <denis.blank at outlook dot com>
  2. // Distributed under the Boost Software License, Version 1.0
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef FU2_INCLUDED_FUNCTION2_HPP_
  6. #define FU2_INCLUDED_FUNCTION2_HPP_
  7. #include <cassert>
  8. #include <cstddef>
  9. #include <cstdlib>
  10. #include <memory>
  11. #include <tuple>
  12. #include <type_traits>
  13. #include <utility>
  14. // Defines:
  15. // - FU2_HAS_DISABLED_EXCEPTIONS
  16. #if defined(FU2_WITH_DISABLED_EXCEPTIONS) || \
  17. defined(FU2_MACRO_DISABLE_EXCEPTIONS)
  18. #define FU2_HAS_DISABLED_EXCEPTIONS
  19. #else // FU2_WITH_DISABLED_EXCEPTIONS
  20. #if defined(_MSC_VER)
  21. #if !defined(_HAS_EXCEPTIONS) || (_HAS_EXCEPTIONS == 0)
  22. #define FU2_HAS_DISABLED_EXCEPTIONS
  23. #endif
  24. #elif defined(__clang__)
  25. #if !(__EXCEPTIONS && __has_feature(cxx_exceptions))
  26. #define FU2_HAS_DISABLED_EXCEPTIONS
  27. #endif
  28. #elif defined(__GNUC__)
  29. #if !__EXCEPTIONS
  30. #define FU2_HAS_DISABLED_EXCEPTIONS
  31. #endif
  32. #endif
  33. #endif // FU2_WITH_DISABLED_EXCEPTIONS
  34. // - FU2_HAS_NO_FUNCTIONAL_HEADER
  35. #if !defined(FU2_WITH_NO_FUNCTIONAL_HEADER) && \
  36. !defined(FU2_NO_FUNCTIONAL_HEADER) && \
  37. !defined(FU2_HAS_DISABLED_EXCEPTIONS)
  38. #include <functional>
  39. #else
  40. #define FU2_HAS_NO_FUNCTIONAL_HEADER
  41. #endif
  42. // - FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  43. #if defined(FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE)
  44. #define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  45. #else // FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE
  46. #if defined(_MSC_VER)
  47. #if defined(_HAS_CXX17) && _HAS_CXX17
  48. #define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  49. #endif
  50. #elif defined(__cpp_noexcept_function_type)
  51. #define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  52. #elif defined(__cplusplus) && (__cplusplus >= 201703L)
  53. #define FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  54. #endif
  55. #endif // FU2_WITH_CXX17_NOEXCEPT_FUNCTION_TYPE
  56. // - FU2_HAS_NO_EMPTY_PROPAGATION
  57. #if defined(FU2_WITH_NO_EMPTY_PROPAGATION)
  58. #define FU2_HAS_NO_EMPTY_PROPAGATION
  59. #endif // FU2_WITH_NO_EMPTY_PROPAGATION
  60. #if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
  61. #include <exception>
  62. #endif
  63. #if defined(__cpp_constexpr) && (__cpp_constexpr >= 201304)
  64. #define FU2_DETAIL_CXX14_CONSTEXPR constexpr
  65. #elif defined(__clang__) && defined(__has_feature)
  66. #if __has_feature(__cxx_generic_lambdas__) && \
  67. __has_feature(__cxx_relaxed_constexpr__)
  68. #define FU2_DETAIL_CXX14_CONSTEXPR constexpr
  69. #endif
  70. #elif defined(_MSC_VER) && (_MSC_VER >= 1915) && (_MSVC_LANG >= 201402)
  71. #define FU2_DETAIL_CXX14_CONSTEXPR constexpr
  72. #endif
  73. #ifndef FU2_DETAIL_CXX14_CONSTEXPR
  74. #define FU2_DETAIL_CXX14_CONSTEXPR
  75. #endif
  76. /// Hint for the compiler that this point should be unreachable
  77. #if defined(_MSC_VER)
  78. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  79. #define FU2_DETAIL_UNREACHABLE_INTRINSIC() __assume(false)
  80. #elif defined(__GNUC__)
  81. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  82. #define FU2_DETAIL_UNREACHABLE_INTRINSIC() __builtin_unreachable()
  83. #elif defined(__has_builtin)
  84. #if __has_builtin(__builtin_unreachable)
  85. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  86. #define FU2_DETAIL_UNREACHABLE_INTRINSIC() __builtin_unreachable()
  87. #endif
  88. #endif
  89. #ifndef FU2_DETAIL_UNREACHABLE_INTRINSIC
  90. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  91. #define FU2_DETAIL_UNREACHABLE_INTRINSIC() abort()
  92. #endif
  93. /// Causes the application to exit abnormally
  94. #if defined(_MSC_VER)
  95. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  96. #define FU2_DETAIL_TRAP() __debugbreak()
  97. #elif defined(__GNUC__)
  98. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  99. #define FU2_DETAIL_TRAP() __builtin_trap()
  100. #elif defined(__has_builtin)
  101. #if __has_builtin(__builtin_trap)
  102. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  103. #define FU2_DETAIL_TRAP() __builtin_trap()
  104. #endif
  105. #endif
  106. #ifndef FU2_DETAIL_TRAP
  107. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  108. #define FU2_DETAIL_TRAP() *(volatile int*)0x11 = 0
  109. #endif
  110. #ifndef NDEBUG
  111. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  112. #define FU2_DETAIL_UNREACHABLE() ::fu2::detail::unreachable_debug()
  113. #else
  114. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  115. #define FU2_DETAIL_UNREACHABLE() FU2_DETAIL_UNREACHABLE_INTRINSIC()
  116. #endif
  117. namespace fu2 {
  118. inline namespace abi_400 {
  119. namespace detail {
  120. template <typename Config, typename Property>
  121. class function;
  122. template <typename...>
  123. struct identity {};
  124. // Equivalent to C++17's std::void_t which targets a bug in GCC,
  125. // that prevents correct SFINAE behavior.
  126. // See http://stackoverflow.com/questions/35753920 for details.
  127. template <typename...>
  128. struct deduce_to_void : std::common_type<void> {};
  129. template <typename... T>
  130. using void_t = typename deduce_to_void<T...>::type;
  131. template <typename T>
  132. using unrefcv_t = std::remove_cv_t<std::remove_reference_t<T>>;
  133. // Copy enabler helper class
  134. template <bool /*Copyable*/>
  135. struct copyable {};
  136. template <>
  137. struct copyable<false> {
  138. copyable() = default;
  139. ~copyable() = default;
  140. copyable(copyable const&) = delete;
  141. copyable(copyable&&) = default;
  142. copyable& operator=(copyable const&) = delete;
  143. copyable& operator=(copyable&&) = default;
  144. };
  145. /// Configuration trait to configure the function_base class.
  146. template <bool Owning, bool Copyable, typename Capacity>
  147. struct config {
  148. // Is true if the function is owning.
  149. static constexpr auto const is_owning = Owning;
  150. // Is true if the function is copyable.
  151. static constexpr auto const is_copyable = Copyable;
  152. // The internal capacity of the function
  153. // used in small functor optimization.
  154. // The object shall expose the real capacity through Capacity::capacity
  155. // and the intended alignment through Capacity::alignment.
  156. using capacity = Capacity;
  157. };
  158. /// A config which isn't compatible to other configs
  159. template <bool Throws, bool HasStrongExceptGuarantee, typename... Args>
  160. struct property {
  161. // Is true when the function throws an exception on empty invocation.
  162. static constexpr auto const is_throwing = Throws;
  163. // Is true when the function throws an exception on empty invocation.
  164. static constexpr auto const is_strong_exception_guaranteed =
  165. HasStrongExceptGuarantee;
  166. };
  167. #ifndef NDEBUG
  168. [[noreturn]] inline void unreachable_debug() {
  169. FU2_DETAIL_TRAP();
  170. std::abort();
  171. }
  172. #endif
  173. /// Provides utilities for invocing callable objects
  174. namespace invocation {
  175. /// Invokes the given callable object with the given arguments
  176. template <typename Callable, typename... Args>
  177. constexpr auto invoke(Callable&& callable, Args&&... args) noexcept(
  178. noexcept(std::forward<Callable>(callable)(std::forward<Args>(args)...)))
  179. -> decltype(std::forward<Callable>(callable)(std::forward<Args>(args)...)) {
  180. return std::forward<Callable>(callable)(std::forward<Args>(args)...);
  181. }
  182. /// Invokes the given member function pointer by reference
  183. template <typename T, typename Type, typename Self, typename... Args>
  184. constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
  185. noexcept((std::forward<Self>(self).*member)(std::forward<Args>(args)...)))
  186. -> decltype((std::forward<Self>(self).*
  187. member)(std::forward<Args>(args)...)) {
  188. return (std::forward<Self>(self).*member)(std::forward<Args>(args)...);
  189. }
  190. /// Invokes the given member function pointer by pointer
  191. template <typename T, typename Type, typename Self, typename... Args>
  192. constexpr auto invoke(Type T::*member, Self&& self, Args&&... args) noexcept(
  193. noexcept((std::forward<Self>(self)->*member)(std::forward<Args>(args)...)))
  194. -> decltype(
  195. (std::forward<Self>(self)->*member)(std::forward<Args>(args)...)) {
  196. return (std::forward<Self>(self)->*member)(std::forward<Args>(args)...);
  197. }
  198. /// Invokes the given pointer to a scalar member by reference
  199. template <typename T, typename Type, typename Self>
  200. constexpr auto
  201. invoke(Type T::*member,
  202. Self&& self) noexcept(noexcept(std::forward<Self>(self).*member))
  203. -> decltype(std::forward<Self>(self).*member) {
  204. return (std::forward<Self>(self).*member);
  205. }
  206. /// Invokes the given pointer to a scalar member by pointer
  207. template <typename T, typename Type, typename Self>
  208. constexpr auto
  209. invoke(Type T::*member,
  210. Self&& self) noexcept(noexcept(std::forward<Self>(self)->*member))
  211. -> decltype(std::forward<Self>(self)->*member) {
  212. return std::forward<Self>(self)->*member;
  213. }
  214. /// Deduces to a true type if the callable object can be invoked with
  215. /// the given arguments.
  216. /// We don't use invoke here because MSVC can't evaluate the nested expression
  217. /// SFINAE here.
  218. template <typename T, typename Args, typename = void>
  219. struct can_invoke : std::false_type {};
  220. template <typename T, typename... Args>
  221. struct can_invoke<T, identity<Args...>,
  222. decltype((void)std::declval<T>()(std::declval<Args>()...))>
  223. : std::true_type {};
  224. template <typename Pointer, typename T, typename... Args>
  225. struct can_invoke<Pointer, identity<T&, Args...>,
  226. decltype((void)((std::declval<T&>().*std::declval<Pointer>())(
  227. std::declval<Args>()...)))> : std::true_type {};
  228. template <typename Pointer, typename T, typename... Args>
  229. struct can_invoke<Pointer, identity<T&&, Args...>,
  230. decltype(
  231. (void)((std::declval<T&&>().*std::declval<Pointer>())(
  232. std::declval<Args>()...)))> : std::true_type {};
  233. template <typename Pointer, typename T, typename... Args>
  234. struct can_invoke<Pointer, identity<T*, Args...>,
  235. decltype(
  236. (void)((std::declval<T*>()->*std::declval<Pointer>())(
  237. std::declval<Args>()...)))> : std::true_type {};
  238. template <typename Pointer, typename T>
  239. struct can_invoke<Pointer, identity<T&>,
  240. decltype((void)(std::declval<T&>().*std::declval<Pointer>()))>
  241. : std::true_type {};
  242. template <typename Pointer, typename T>
  243. struct can_invoke<Pointer, identity<T&&>,
  244. decltype(
  245. (void)(std::declval<T&&>().*std::declval<Pointer>()))>
  246. : std::true_type {};
  247. template <typename Pointer, typename T>
  248. struct can_invoke<Pointer, identity<T*>,
  249. decltype(
  250. (void)(std::declval<T*>()->*std::declval<Pointer>()))>
  251. : std::true_type {};
  252. template <bool RequiresNoexcept, typename T, typename Args>
  253. struct is_noexcept_correct : std::true_type {};
  254. template <typename T, typename... Args>
  255. struct is_noexcept_correct<true, T, identity<Args...>>
  256. : std::integral_constant<bool,
  257. noexcept(::fu2::detail::invocation::invoke(
  258. std::declval<T>(), std::declval<Args>()...))> {
  259. };
  260. } // end namespace invocation
  261. namespace overloading {
  262. template <typename... Args>
  263. struct overload_impl;
  264. template <typename Current, typename Next, typename... Rest>
  265. struct overload_impl<Current, Next, Rest...> : Current,
  266. overload_impl<Next, Rest...> {
  267. explicit overload_impl(Current current, Next next, Rest... rest)
  268. : Current(std::move(current)), overload_impl<Next, Rest...>(
  269. std::move(next), std::move(rest)...) {
  270. }
  271. using Current::operator();
  272. using overload_impl<Next, Rest...>::operator();
  273. };
  274. template <typename Current>
  275. struct overload_impl<Current> : Current {
  276. explicit overload_impl(Current current) : Current(std::move(current)) {
  277. }
  278. using Current::operator();
  279. };
  280. template <typename... T>
  281. constexpr auto overload(T&&... callables) {
  282. return overload_impl<std::decay_t<T>...>{std::forward<T>(callables)...};
  283. }
  284. } // namespace overloading
  285. /// Declares the namespace which provides the functionality to work with a
  286. /// type-erased object.
  287. namespace type_erasure {
  288. /// Specialization to work with addresses of callable objects
  289. template <typename T, typename = void>
  290. struct address_taker {
  291. template <typename O>
  292. static void* take(O&& obj) {
  293. return std::addressof(obj);
  294. }
  295. static T& restore(void* ptr) {
  296. return *static_cast<T*>(ptr);
  297. }
  298. static T const& restore(void const* ptr) {
  299. return *static_cast<T const*>(ptr);
  300. }
  301. static T volatile& restore(void volatile* ptr) {
  302. return *static_cast<T volatile*>(ptr);
  303. }
  304. static T const volatile& restore(void const volatile* ptr) {
  305. return *static_cast<T const volatile*>(ptr);
  306. }
  307. };
  308. /// Specialization to work with addresses of raw function pointers
  309. template <typename T>
  310. struct address_taker<T, std::enable_if_t<std::is_pointer<T>::value>> {
  311. template <typename O>
  312. static void* take(O&& obj) {
  313. return reinterpret_cast<void*>(obj);
  314. }
  315. template <typename O>
  316. static T restore(O ptr) {
  317. return reinterpret_cast<T>(const_cast<void*>(ptr));
  318. }
  319. };
  320. template <typename Box>
  321. struct box_factory;
  322. /// Store the allocator inside the box
  323. template <bool IsCopyable, typename T, typename Allocator>
  324. struct box : private Allocator {
  325. friend box_factory<box>;
  326. T value_;
  327. explicit box(T value, Allocator allocator)
  328. : Allocator(std::move(allocator)), value_(std::move(value)) {
  329. }
  330. box(box&&) = default;
  331. box(box const&) = default;
  332. box& operator=(box&&) = default;
  333. box& operator=(box const&) = default;
  334. ~box() = default;
  335. };
  336. template <typename T, typename Allocator>
  337. struct box<false, T, Allocator> : private Allocator {
  338. friend box_factory<box>;
  339. T value_;
  340. explicit box(T value, Allocator allocator)
  341. : Allocator(std::move(allocator)), value_(std::move(value)) {
  342. }
  343. box(box&&) = default;
  344. box(box const&) = delete;
  345. box& operator=(box&&) = default;
  346. box& operator=(box const&) = delete;
  347. ~box() = default;
  348. };
  349. template <bool IsCopyable, typename T, typename Allocator>
  350. struct box_factory<box<IsCopyable, T, Allocator>> {
  351. using real_allocator =
  352. typename std::allocator_traits<std::decay_t<Allocator>>::
  353. template rebind_alloc<box<IsCopyable, T, Allocator>>;
  354. /// Allocates space through the boxed allocator
  355. static box<IsCopyable, T, Allocator>*
  356. box_allocate(box<IsCopyable, T, Allocator> const* me) {
  357. real_allocator allocator(*static_cast<Allocator const*>(me));
  358. return static_cast<box<IsCopyable, T, Allocator>*>(
  359. std::allocator_traits<real_allocator>::allocate(allocator, 1U));
  360. }
  361. /// Destroys the box through the given allocator
  362. static void box_deallocate(box<IsCopyable, T, Allocator>* me) {
  363. real_allocator allocator(*static_cast<Allocator const*>(me));
  364. me->~box();
  365. std::allocator_traits<real_allocator>::deallocate(allocator, me, 1U);
  366. }
  367. };
  368. /// Creates a box containing the given value and allocator
  369. template <bool IsCopyable, typename T, typename Allocator>
  370. auto make_box(std::integral_constant<bool, IsCopyable>, T&& value,
  371. Allocator&& allocator) {
  372. return box<IsCopyable, std::decay_t<T>, std::decay_t<Allocator>>(
  373. std::forward<T>(value), std::forward<Allocator>(allocator));
  374. }
  375. template <typename T>
  376. struct is_box : std::false_type {};
  377. template <bool IsCopyable, typename T, typename Allocator>
  378. struct is_box<box<IsCopyable, T, Allocator>> : std::true_type {};
  379. /// Provides access to the pointer to a heal allocated erased object
  380. /// as well to the inplace storage.
  381. union data_accessor {
  382. data_accessor() = default;
  383. explicit constexpr data_accessor(std::nullptr_t) noexcept : ptr_(nullptr) {
  384. }
  385. explicit constexpr data_accessor(void* ptr) noexcept : ptr_(ptr) {
  386. }
  387. /// The pointer we use if the object is on the heap
  388. void* ptr_;
  389. /// The first field of the inplace storage
  390. std::size_t inplace_storage_;
  391. };
  392. /// See opcode::op_fetch_empty
  393. static FU2_DETAIL_CXX14_CONSTEXPR void write_empty(data_accessor* accessor,
  394. bool empty) noexcept {
  395. accessor->inplace_storage_ = std::size_t(empty);
  396. }
  397. template <typename From, typename To>
  398. using transfer_const_t =
  399. std::conditional_t<std::is_const<std::remove_pointer_t<From>>::value,
  400. std::add_const_t<To>, To>;
  401. template <typename From, typename To>
  402. using transfer_volatile_t =
  403. std::conditional_t<std::is_volatile<std::remove_pointer_t<From>>::value,
  404. std::add_volatile_t<To>, To>;
  405. /// The retriever when the object is allocated inplace
  406. template <typename T, typename Accessor>
  407. FU2_DETAIL_CXX14_CONSTEXPR auto retrieve(std::true_type /*is_inplace*/,
  408. Accessor from,
  409. std::size_t from_capacity) {
  410. using type = transfer_const_t<Accessor, transfer_volatile_t<Accessor, void>>*;
  411. /// Process the command by using the data inside the internal capacity
  412. auto storage = &(from->inplace_storage_);
  413. auto inplace = const_cast<void*>(static_cast<type>(storage));
  414. return type(std::align(alignof(T), sizeof(T), inplace, from_capacity));
  415. }
  416. /// The retriever which is used when the object is allocated
  417. /// through the allocator
  418. template <typename T, typename Accessor>
  419. constexpr auto retrieve(std::false_type /*is_inplace*/, Accessor from,
  420. std::size_t /*from_capacity*/) {
  421. return from->ptr_;
  422. }
  423. namespace invocation_table {
  424. #if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
  425. #if defined(FU2_HAS_NO_FUNCTIONAL_HEADER)
  426. struct bad_function_call : std::exception {
  427. bad_function_call() noexcept {
  428. }
  429. char const* what() const noexcept override {
  430. return "bad function call";
  431. }
  432. };
  433. #else
  434. using std::bad_function_call;
  435. #endif
  436. #endif
  437. #ifdef FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  438. #define FU2_DETAIL_EXPAND_QUALIFIERS_NOEXCEPT(F) \
  439. F(, , noexcept, , &) \
  440. F(const, , noexcept, , &) \
  441. F(, volatile, noexcept, , &) \
  442. F(const, volatile, noexcept, , &) \
  443. F(, , noexcept, &, &) \
  444. F(const, , noexcept, &, &) \
  445. F(, volatile, noexcept, &, &) \
  446. F(const, volatile, noexcept, &, &) \
  447. F(, , noexcept, &&, &&) \
  448. F(const, , noexcept, &&, &&) \
  449. F(, volatile, noexcept, &&, &&) \
  450. F(const, volatile, noexcept, &&, &&)
  451. #define FU2_DETAIL_EXPAND_CV_NOEXCEPT(F) \
  452. F(, , noexcept) \
  453. F(const, , noexcept) \
  454. F(, volatile, noexcept) \
  455. F(const, volatile, noexcept)
  456. #else // FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  457. #define FU2_DETAIL_EXPAND_QUALIFIERS_NOEXCEPT(F)
  458. #define FU2_DETAIL_EXPAND_CV_NOEXCEPT(F)
  459. #endif // FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE
  460. #define FU2_DETAIL_EXPAND_QUALIFIERS(F) \
  461. F(, , , , &) \
  462. F(const, , , , &) \
  463. F(, volatile, , , &) \
  464. F(const, volatile, , , &) \
  465. F(, , , &, &) \
  466. F(const, , , &, &) \
  467. F(, volatile, , &, &) \
  468. F(const, volatile, , &, &) \
  469. F(, , , &&, &&) \
  470. F(const, , , &&, &&) \
  471. F(, volatile, , &&, &&) \
  472. F(const, volatile, , &&, &&) \
  473. FU2_DETAIL_EXPAND_QUALIFIERS_NOEXCEPT(F)
  474. #define FU2_DETAIL_EXPAND_CV(F) \
  475. F(, , ) \
  476. F(const, , ) \
  477. F(, volatile, ) \
  478. F(const, volatile, ) \
  479. FU2_DETAIL_EXPAND_CV_NOEXCEPT(F)
  480. /// If the function is qualified as noexcept, the call will never throw
  481. template <bool IsNoexcept>
  482. [[noreturn]] void throw_or_abortnoexcept(
  483. std::integral_constant<bool, IsNoexcept> /*is_throwing*/) noexcept {
  484. std::abort();
  485. }
  486. /// Calls std::abort on empty function calls
  487. [[noreturn]] inline void
  488. throw_or_abort(std::false_type /*is_throwing*/) noexcept {
  489. std::abort();
  490. }
  491. /// Throws bad_function_call on empty funciton calls
  492. [[noreturn]] inline void throw_or_abort(std::true_type /*is_throwing*/) {
  493. #ifdef FU2_HAS_DISABLED_EXCEPTIONS
  494. throw_or_abort(std::false_type{});
  495. #else
  496. throw bad_function_call{};
  497. #endif
  498. }
  499. template <typename T>
  500. struct function_trait;
  501. using is_noexcept_ = std::false_type;
  502. using is_noexcept_noexcept = std::true_type;
  503. #define FU2_DEFINE_FUNCTION_TRAIT(CONST, VOLATILE, NOEXCEPT, OVL_REF, REF) \
  504. template <typename Ret, typename... Args> \
  505. struct function_trait<Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT> { \
  506. using pointer_type = Ret (*)(data_accessor CONST VOLATILE*, \
  507. std::size_t capacity, Args...); \
  508. template <typename T, bool IsInplace> \
  509. struct internal_invoker { \
  510. static Ret invoke(data_accessor CONST VOLATILE* data, \
  511. std::size_t capacity, Args... args) NOEXCEPT { \
  512. auto obj = retrieve<T>(std::integral_constant<bool, IsInplace>{}, \
  513. data, capacity); \
  514. auto box = static_cast<T CONST VOLATILE*>(obj); \
  515. return invocation::invoke( \
  516. static_cast<std::decay_t<decltype(box->value_)> CONST VOLATILE \
  517. REF>(box->value_), \
  518. std::forward<Args>(args)...); \
  519. } \
  520. }; \
  521. \
  522. template <typename T> \
  523. struct view_invoker { \
  524. static Ret invoke(data_accessor CONST VOLATILE* data, std::size_t, \
  525. Args... args) NOEXCEPT { \
  526. \
  527. auto ptr = static_cast<void CONST VOLATILE*>(data->ptr_); \
  528. return invocation::invoke(address_taker<T>::restore(ptr), \
  529. std::forward<Args>(args)...); \
  530. } \
  531. }; \
  532. \
  533. template <typename T> \
  534. using callable = T CONST VOLATILE REF; \
  535. \
  536. using arguments = identity<Args...>; \
  537. \
  538. using is_noexcept = is_noexcept_##NOEXCEPT; \
  539. \
  540. template <bool Throws> \
  541. struct empty_invoker { \
  542. static Ret invoke(data_accessor CONST VOLATILE* /*data*/, \
  543. std::size_t /*capacity*/, Args... /*args*/) NOEXCEPT { \
  544. throw_or_abort##NOEXCEPT(std::integral_constant<bool, Throws>{}); \
  545. } \
  546. }; \
  547. };
  548. FU2_DETAIL_EXPAND_QUALIFIERS(FU2_DEFINE_FUNCTION_TRAIT)
  549. #undef FU2_DEFINE_FUNCTION_TRAIT
  550. /// Deduces to the function pointer to the given signature
  551. template <typename Signature>
  552. using function_pointer_of = typename function_trait<Signature>::pointer_type;
  553. template <typename... Args>
  554. struct invoke_table;
  555. /// We optimize the vtable_t in case there is a single function overload
  556. template <typename First>
  557. struct invoke_table<First> {
  558. using type = function_pointer_of<First>;
  559. /// Return the function pointer itself
  560. template <std::size_t Index>
  561. static constexpr auto fetch(type pointer) noexcept {
  562. static_assert(Index == 0U, "The index should be 0 here!");
  563. return pointer;
  564. }
  565. /// Returns the thunk of an single overloaded callable
  566. template <typename T, bool IsInplace>
  567. static constexpr type get_invocation_table_of() noexcept {
  568. return &function_trait<First>::template internal_invoker<T,
  569. IsInplace>::invoke;
  570. }
  571. /// Returns the thunk of an single overloaded callable
  572. template <typename T>
  573. static constexpr type get_invocation_view_table_of() noexcept {
  574. return &function_trait<First>::template view_invoker<T>::invoke;
  575. }
  576. /// Returns the thunk of an empty single overloaded callable
  577. template <bool IsThrowing>
  578. static constexpr type get_empty_invocation_table() noexcept {
  579. return &function_trait<First>::template empty_invoker<IsThrowing>::invoke;
  580. }
  581. };
  582. /// We generate a table in case of multiple function overloads
  583. template <typename First, typename Second, typename... Args>
  584. struct invoke_table<First, Second, Args...> {
  585. using type =
  586. std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
  587. function_pointer_of<Args>...> const*;
  588. /// Return the function pointer at the particular index
  589. template <std::size_t Index>
  590. static constexpr auto fetch(type table) noexcept {
  591. return std::get<Index>(*table);
  592. }
  593. /// The invocation vtable for a present object
  594. template <typename T, bool IsInplace>
  595. struct invocation_vtable : public std::tuple<function_pointer_of<First>,
  596. function_pointer_of<Second>,
  597. function_pointer_of<Args>...> {
  598. constexpr invocation_vtable() noexcept
  599. : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
  600. function_pointer_of<Args>...>(std::make_tuple(
  601. &function_trait<First>::template internal_invoker<
  602. T, IsInplace>::invoke,
  603. &function_trait<Second>::template internal_invoker<
  604. T, IsInplace>::invoke,
  605. &function_trait<Args>::template internal_invoker<
  606. T, IsInplace>::invoke...)) {
  607. }
  608. };
  609. /// Returns the thunk of an multi overloaded callable
  610. template <typename T, bool IsInplace>
  611. static type get_invocation_table_of() noexcept {
  612. static invocation_vtable<T, IsInplace> const table;
  613. return &table;
  614. }
  615. /// The invocation vtable for a present object
  616. template <typename T>
  617. struct invocation_view_vtable
  618. : public std::tuple<function_pointer_of<First>,
  619. function_pointer_of<Second>,
  620. function_pointer_of<Args>...> {
  621. constexpr invocation_view_vtable() noexcept
  622. : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
  623. function_pointer_of<Args>...>(std::make_tuple(
  624. &function_trait<First>::template view_invoker<T>::invoke,
  625. &function_trait<Second>::template view_invoker<T>::invoke,
  626. &function_trait<Args>::template view_invoker<T>::invoke...)) {
  627. }
  628. };
  629. /// Returns the thunk of an multi overloaded callable
  630. template <typename T>
  631. static type get_invocation_view_table_of() noexcept {
  632. static invocation_view_vtable<T> const table;
  633. return &table;
  634. }
  635. /// The invocation table for an empty wrapper
  636. template <bool IsThrowing>
  637. struct empty_vtable : public std::tuple<function_pointer_of<First>,
  638. function_pointer_of<Second>,
  639. function_pointer_of<Args>...> {
  640. constexpr empty_vtable() noexcept
  641. : std::tuple<function_pointer_of<First>, function_pointer_of<Second>,
  642. function_pointer_of<Args>...>(
  643. std::make_tuple(&function_trait<First>::template empty_invoker<
  644. IsThrowing>::invoke,
  645. &function_trait<Second>::template empty_invoker<
  646. IsThrowing>::invoke,
  647. &function_trait<Args>::template empty_invoker<
  648. IsThrowing>::invoke...)) {
  649. }
  650. };
  651. /// Returns the thunk of an multi single overloaded callable
  652. template <bool IsThrowing>
  653. static type get_empty_invocation_table() noexcept {
  654. static empty_vtable<IsThrowing> const table;
  655. return &table;
  656. }
  657. };
  658. template <std::size_t Index, typename Function, typename... Signatures>
  659. class operator_impl;
  660. #define FU2_DEFINE_FUNCTION_TRAIT(CONST, VOLATILE, NOEXCEPT, OVL_REF, REF) \
  661. template <std::size_t Index, typename Function, typename Ret, \
  662. typename... Args, typename Next, typename... Signatures> \
  663. class operator_impl<Index, Function, \
  664. Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT, Next, \
  665. Signatures...> \
  666. : operator_impl<Index + 1, Function, Next, Signatures...> { \
  667. \
  668. template <std::size_t, typename, typename...> \
  669. friend class operator_impl; \
  670. \
  671. protected: \
  672. operator_impl() = default; \
  673. ~operator_impl() = default; \
  674. operator_impl(operator_impl const&) = default; \
  675. operator_impl(operator_impl&&) = default; \
  676. operator_impl& operator=(operator_impl const&) = default; \
  677. operator_impl& operator=(operator_impl&&) = default; \
  678. \
  679. using operator_impl<Index + 1, Function, Next, Signatures...>::operator(); \
  680. \
  681. Ret operator()(Args... args) CONST VOLATILE OVL_REF NOEXCEPT { \
  682. auto parent = static_cast<Function CONST VOLATILE*>(this); \
  683. using erasure_t = std::decay_t<decltype(parent->erasure_)>; \
  684. \
  685. /* `std::decay_t<decltype(parent->erasure_)>` is a workaround for a */ \
  686. /* compiler regression of MSVC 16.3.1, see #29 for details. */ \
  687. return std::decay_t<decltype(parent->erasure_)>::template invoke<Index>( \
  688. static_cast<erasure_t CONST VOLATILE REF>(parent->erasure_), \
  689. std::forward<Args>(args)...); \
  690. } \
  691. }; \
  692. template <std::size_t Index, typename Config, typename Property, \
  693. typename Ret, typename... Args> \
  694. class operator_impl<Index, function<Config, Property>, \
  695. Ret(Args...) CONST VOLATILE OVL_REF NOEXCEPT> \
  696. : copyable<!Config::is_owning || Config::is_copyable> { \
  697. \
  698. template <std::size_t, typename, typename...> \
  699. friend class operator_impl; \
  700. \
  701. protected: \
  702. operator_impl() = default; \
  703. ~operator_impl() = default; \
  704. operator_impl(operator_impl const&) = default; \
  705. operator_impl(operator_impl&&) = default; \
  706. operator_impl& operator=(operator_impl const&) = default; \
  707. operator_impl& operator=(operator_impl&&) = default; \
  708. \
  709. Ret operator()(Args... args) CONST VOLATILE OVL_REF NOEXCEPT { \
  710. auto parent = \
  711. static_cast<function<Config, Property> CONST VOLATILE*>(this); \
  712. using erasure_t = std::decay_t<decltype(parent->erasure_)>; \
  713. \
  714. /* `std::decay_t<decltype(parent->erasure_)>` is a workaround for a */ \
  715. /* compiler regression of MSVC 16.3.1, see #29 for details. */ \
  716. return std::decay_t<decltype(parent->erasure_)>::template invoke<Index>( \
  717. static_cast<erasure_t CONST VOLATILE REF>(parent->erasure_), \
  718. std::forward<Args>(args)...); \
  719. } \
  720. };
  721. FU2_DETAIL_EXPAND_QUALIFIERS(FU2_DEFINE_FUNCTION_TRAIT)
  722. #undef FU2_DEFINE_FUNCTION_TRAIT
  723. } // namespace invocation_table
  724. namespace tables {
  725. /// Identifies the action which is dispatched on the erased object
  726. enum class opcode {
  727. op_move, ///< Move the object and set the vtable
  728. op_copy, ///< Copy the object and set the vtable
  729. op_destroy, ///< Destroy the object and reset the vtable
  730. op_weak_destroy, ///< Destroy the object without resetting the vtable
  731. op_fetch_empty, ///< Stores true or false into the to storage
  732. ///< to indicate emptiness
  733. };
  734. /// Abstraction for a vtable together with a command table
  735. /// TODO Add optimization for a single formal argument
  736. /// TODO Add optimization to merge both tables if the function is size
  737. /// optimized
  738. template <typename Property>
  739. class vtable;
  740. template <bool IsThrowing, bool HasStrongExceptGuarantee,
  741. typename... FormalArgs>
  742. class vtable<property<IsThrowing, HasStrongExceptGuarantee, FormalArgs...>> {
  743. using command_function_t = void (*)(vtable* /*this*/, opcode /*op*/,
  744. data_accessor* /*from*/,
  745. std::size_t /*from_capacity*/,
  746. data_accessor* /*to*/,
  747. std::size_t /*to_capacity*/);
  748. using invoke_table_t = invocation_table::invoke_table<FormalArgs...>;
  749. command_function_t cmd_;
  750. typename invoke_table_t::type vtable_;
  751. template <typename T>
  752. struct trait {
  753. static_assert(is_box<T>::value,
  754. "The trait must be specialized with a box!");
  755. /// The command table
  756. template <bool IsInplace>
  757. static void process_cmd(vtable* to_table, opcode op, data_accessor* from,
  758. std::size_t from_capacity, data_accessor* to,
  759. std::size_t to_capacity) {
  760. switch (op) {
  761. case opcode::op_move: {
  762. /// Retrieve the pointer to the object
  763. auto box = static_cast<T*>(retrieve<T>(
  764. std::integral_constant<bool, IsInplace>{}, from, from_capacity));
  765. assert(box && "The object must not be over aligned or null!");
  766. if (!IsInplace) {
  767. // Just swap both pointers if we allocated on the heap
  768. to->ptr_ = from->ptr_;
  769. #ifndef NDEBUG
  770. // We don't need to null the pointer since we know that
  771. // we don't own the data anymore through the vtable
  772. // which is set to empty.
  773. from->ptr_ = nullptr;
  774. #endif
  775. to_table->template set_allocated<T>();
  776. }
  777. // The object is allocated inplace
  778. else {
  779. construct(std::true_type{}, std::move(*box), to_table, to,
  780. to_capacity);
  781. box->~T();
  782. }
  783. return;
  784. }
  785. case opcode::op_copy: {
  786. auto box = static_cast<T const*>(retrieve<T>(
  787. std::integral_constant<bool, IsInplace>{}, from, from_capacity));
  788. assert(box && "The object must not be over aligned or null!");
  789. assert(std::is_copy_constructible<T>::value &&
  790. "The box is required to be copyable here!");
  791. // Try to allocate the object inplace
  792. construct(std::is_copy_constructible<T>{}, *box, to_table, to,
  793. to_capacity);
  794. return;
  795. }
  796. case opcode::op_destroy:
  797. case opcode::op_weak_destroy: {
  798. assert(!to && !to_capacity && "Arg overflow!");
  799. auto box = static_cast<T*>(retrieve<T>(
  800. std::integral_constant<bool, IsInplace>{}, from, from_capacity));
  801. if (IsInplace) {
  802. box->~T();
  803. } else {
  804. box_factory<T>::box_deallocate(box);
  805. }
  806. if (op == opcode::op_destroy) {
  807. to_table->set_empty();
  808. }
  809. return;
  810. }
  811. case opcode::op_fetch_empty: {
  812. write_empty(to, false);
  813. return;
  814. }
  815. }
  816. FU2_DETAIL_UNREACHABLE();
  817. }
  818. template <typename Box>
  819. static void
  820. construct(std::true_type /*apply*/, Box&& box, vtable* to_table,
  821. data_accessor* to,
  822. std::size_t to_capacity) noexcept(HasStrongExceptGuarantee) {
  823. // Try to allocate the object inplace
  824. void* storage = retrieve<T>(std::true_type{}, to, to_capacity);
  825. if (storage) {
  826. to_table->template set_inplace<T>();
  827. } else {
  828. // Allocate the object through the allocator
  829. to->ptr_ = storage =
  830. box_factory<std::decay_t<Box>>::box_allocate(std::addressof(box));
  831. to_table->template set_allocated<T>();
  832. }
  833. new (storage) T(std::forward<Box>(box));
  834. }
  835. template <typename Box>
  836. static void
  837. construct(std::false_type /*apply*/, Box&& /*box*/, vtable* /*to_table*/,
  838. data_accessor* /*to*/,
  839. std::size_t /*to_capacity*/) noexcept(HasStrongExceptGuarantee) {
  840. }
  841. };
  842. /// The command table
  843. static void empty_cmd(vtable* to_table, opcode op, data_accessor* /*from*/,
  844. std::size_t /*from_capacity*/, data_accessor* to,
  845. std::size_t /*to_capacity*/) {
  846. switch (op) {
  847. case opcode::op_move:
  848. case opcode::op_copy: {
  849. to_table->set_empty();
  850. break;
  851. }
  852. case opcode::op_destroy:
  853. case opcode::op_weak_destroy: {
  854. // Do nothing
  855. break;
  856. }
  857. case opcode::op_fetch_empty: {
  858. write_empty(to, true);
  859. break;
  860. }
  861. default: {
  862. FU2_DETAIL_UNREACHABLE();
  863. }
  864. }
  865. }
  866. public:
  867. vtable() noexcept = default;
  868. /// Initialize an object at the given position
  869. template <typename T>
  870. static void init(vtable& table, T&& object, data_accessor* to,
  871. std::size_t to_capacity) {
  872. trait<std::decay_t<T>>::construct(std::true_type{}, std::forward<T>(object),
  873. &table, to, to_capacity);
  874. }
  875. /// Moves the object at the given position
  876. void move(vtable& to_table, data_accessor* from, std::size_t from_capacity,
  877. data_accessor* to,
  878. std::size_t to_capacity) noexcept(HasStrongExceptGuarantee) {
  879. cmd_(&to_table, opcode::op_move, from, from_capacity, to, to_capacity);
  880. set_empty();
  881. }
  882. /// Destroys the object at the given position
  883. void copy(vtable& to_table, data_accessor const* from,
  884. std::size_t from_capacity, data_accessor* to,
  885. std::size_t to_capacity) const {
  886. cmd_(&to_table, opcode::op_copy, const_cast<data_accessor*>(from),
  887. from_capacity, to, to_capacity);
  888. }
  889. /// Destroys the object at the given position
  890. void destroy(data_accessor* from,
  891. std::size_t from_capacity) noexcept(HasStrongExceptGuarantee) {
  892. cmd_(this, opcode::op_destroy, from, from_capacity, nullptr, 0U);
  893. }
  894. /// Destroys the object at the given position without invalidating the
  895. /// vtable
  896. void
  897. weak_destroy(data_accessor* from,
  898. std::size_t from_capacity) noexcept(HasStrongExceptGuarantee) {
  899. cmd_(this, opcode::op_weak_destroy, from, from_capacity, nullptr, 0U);
  900. }
  901. /// Returns true when the vtable doesn't hold any erased object
  902. bool empty() const noexcept {
  903. data_accessor data;
  904. cmd_(nullptr, opcode::op_fetch_empty, nullptr, 0U, &data, 0U);
  905. return bool(data.inplace_storage_);
  906. }
  907. /// Invoke the function at the given index
  908. template <std::size_t Index, typename... Args>
  909. constexpr decltype(auto) invoke(Args&&... args) const {
  910. auto thunk = invoke_table_t::template fetch<Index>(vtable_);
  911. return thunk(std::forward<Args>(args)...);
  912. }
  913. /// Invoke the function at the given index
  914. template <std::size_t Index, typename... Args>
  915. constexpr decltype(auto) invoke(Args&&... args) const volatile {
  916. auto thunk = invoke_table_t::template fetch<Index>(vtable_);
  917. return thunk(std::forward<Args>(args)...);
  918. }
  919. template <typename T>
  920. void set_inplace() noexcept {
  921. using type = std::decay_t<T>;
  922. vtable_ = invoke_table_t::template get_invocation_table_of<type, true>();
  923. cmd_ = &trait<type>::template process_cmd<true>;
  924. }
  925. template <typename T>
  926. void set_allocated() noexcept {
  927. using type = std::decay_t<T>;
  928. vtable_ = invoke_table_t::template get_invocation_table_of<type, false>();
  929. cmd_ = &trait<type>::template process_cmd<false>;
  930. }
  931. void set_empty() noexcept {
  932. vtable_ = invoke_table_t::template get_empty_invocation_table<IsThrowing>();
  933. cmd_ = &empty_cmd;
  934. }
  935. };
  936. } // namespace tables
  937. /// A union which makes the pointer to the heap object share the
  938. /// same space with the internal capacity.
  939. /// The storage type is distinguished by multiple versions of the
  940. /// control and vtable.
  941. template <typename Capacity, typename = void>
  942. struct internal_capacity {
  943. /// We extend the union through a technique similar to the tail object hack
  944. typedef union {
  945. /// Tag to access the structure in a type-safe way
  946. data_accessor accessor_;
  947. /// The internal capacity we use to allocate in-place
  948. std::aligned_storage_t<Capacity::capacity, Capacity::alignment> capacity_;
  949. } type;
  950. };
  951. template <typename Capacity>
  952. struct internal_capacity<
  953. Capacity, std::enable_if_t<(Capacity::capacity < sizeof(void*))>> {
  954. typedef struct {
  955. /// Tag to access the structure in a type-safe way
  956. data_accessor accessor_;
  957. } type;
  958. };
  959. template <typename Capacity>
  960. class internal_capacity_holder {
  961. // Tag to access the structure in a type-safe way
  962. typename internal_capacity<Capacity>::type storage_;
  963. public:
  964. constexpr internal_capacity_holder() = default;
  965. FU2_DETAIL_CXX14_CONSTEXPR data_accessor* opaque_ptr() noexcept {
  966. return &storage_.accessor_;
  967. }
  968. constexpr data_accessor const* opaque_ptr() const noexcept {
  969. return &storage_.accessor_;
  970. }
  971. FU2_DETAIL_CXX14_CONSTEXPR data_accessor volatile*
  972. opaque_ptr() volatile noexcept {
  973. return &storage_.accessor_;
  974. }
  975. constexpr data_accessor const volatile* opaque_ptr() const volatile noexcept {
  976. return &storage_.accessor_;
  977. }
  978. static constexpr std::size_t capacity() noexcept {
  979. return sizeof(storage_);
  980. }
  981. };
  982. /// An owning erasure
  983. template <bool IsOwning /* = true*/, typename Config, typename Property>
  984. class erasure : internal_capacity_holder<typename Config::capacity> {
  985. template <bool, typename, typename>
  986. friend class erasure;
  987. template <std::size_t, typename, typename...>
  988. friend class operator_impl;
  989. using vtable_t = tables::vtable<Property>;
  990. vtable_t vtable_;
  991. public:
  992. /// Returns the capacity of this erasure
  993. static constexpr std::size_t capacity() noexcept {
  994. return internal_capacity_holder<typename Config::capacity>::capacity();
  995. }
  996. FU2_DETAIL_CXX14_CONSTEXPR erasure() noexcept {
  997. vtable_.set_empty();
  998. }
  999. FU2_DETAIL_CXX14_CONSTEXPR erasure(std::nullptr_t) noexcept {
  1000. vtable_.set_empty();
  1001. }
  1002. FU2_DETAIL_CXX14_CONSTEXPR
  1003. erasure(erasure&& right) noexcept(Property::is_strong_exception_guaranteed) {
  1004. right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
  1005. this->opaque_ptr(), capacity());
  1006. }
  1007. FU2_DETAIL_CXX14_CONSTEXPR erasure(erasure const& right) {
  1008. right.vtable_.copy(vtable_, right.opaque_ptr(), right.capacity(),
  1009. this->opaque_ptr(), capacity());
  1010. }
  1011. template <typename OtherConfig>
  1012. FU2_DETAIL_CXX14_CONSTEXPR
  1013. erasure(erasure<true, OtherConfig, Property> right) noexcept(
  1014. Property::is_strong_exception_guaranteed) {
  1015. right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
  1016. this->opaque_ptr(), capacity());
  1017. }
  1018. template <typename T, typename Allocator = std::allocator<std::decay_t<T>>>
  1019. FU2_DETAIL_CXX14_CONSTEXPR erasure(std::false_type /*use_bool_op*/,
  1020. T&& callable,
  1021. Allocator&& allocator = Allocator{}) {
  1022. vtable_t::init(vtable_,
  1023. type_erasure::make_box(
  1024. std::integral_constant<bool, Config::is_copyable>{},
  1025. std::forward<T>(callable),
  1026. std::forward<Allocator>(allocator)),
  1027. this->opaque_ptr(), capacity());
  1028. }
  1029. template <typename T, typename Allocator = std::allocator<std::decay_t<T>>>
  1030. FU2_DETAIL_CXX14_CONSTEXPR erasure(std::true_type /*use_bool_op*/,
  1031. T&& callable,
  1032. Allocator&& allocator = Allocator{}) {
  1033. if (bool(callable)) {
  1034. vtable_t::init(vtable_,
  1035. type_erasure::make_box(
  1036. std::integral_constant<bool, Config::is_copyable>{},
  1037. std::forward<T>(callable),
  1038. std::forward<Allocator>(allocator)),
  1039. this->opaque_ptr(), capacity());
  1040. } else {
  1041. vtable_.set_empty();
  1042. }
  1043. }
  1044. ~erasure() {
  1045. vtable_.weak_destroy(this->opaque_ptr(), capacity());
  1046. }
  1047. FU2_DETAIL_CXX14_CONSTEXPR erasure&
  1048. operator=(std::nullptr_t) noexcept(Property::is_strong_exception_guaranteed) {
  1049. vtable_.destroy(this->opaque_ptr(), capacity());
  1050. return *this;
  1051. }
  1052. FU2_DETAIL_CXX14_CONSTEXPR erasure& operator=(erasure&& right) noexcept(
  1053. Property::is_strong_exception_guaranteed) {
  1054. vtable_.weak_destroy(this->opaque_ptr(), capacity());
  1055. right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
  1056. this->opaque_ptr(), capacity());
  1057. return *this;
  1058. }
  1059. FU2_DETAIL_CXX14_CONSTEXPR erasure& operator=(erasure const& right) {
  1060. vtable_.weak_destroy(this->opaque_ptr(), capacity());
  1061. right.vtable_.copy(vtable_, right.opaque_ptr(), right.capacity(),
  1062. this->opaque_ptr(), capacity());
  1063. return *this;
  1064. }
  1065. template <typename OtherConfig>
  1066. FU2_DETAIL_CXX14_CONSTEXPR erasure&
  1067. operator=(erasure<true, OtherConfig, Property> right) noexcept(
  1068. Property::is_strong_exception_guaranteed) {
  1069. vtable_.weak_destroy(this->opaque_ptr(), capacity());
  1070. right.vtable_.move(vtable_, right.opaque_ptr(), right.capacity(),
  1071. this->opaque_ptr(), capacity());
  1072. return *this;
  1073. }
  1074. template <typename T, typename Allocator = std::allocator<std::decay_t<T>>>
  1075. void assign(std::false_type /*use_bool_op*/, T&& callable,
  1076. Allocator&& allocator = {}) {
  1077. vtable_.weak_destroy(this->opaque_ptr(), capacity());
  1078. vtable_t::init(vtable_,
  1079. type_erasure::make_box(
  1080. std::integral_constant<bool, Config::is_copyable>{},
  1081. std::forward<T>(callable),
  1082. std::forward<Allocator>(allocator)),
  1083. this->opaque_ptr(), capacity());
  1084. }
  1085. template <typename T, typename Allocator = std::allocator<std::decay_t<T>>>
  1086. void assign(std::true_type /*use_bool_op*/, T&& callable,
  1087. Allocator&& allocator = {}) {
  1088. if (bool(callable)) {
  1089. assign(std::false_type{}, std::forward<T>(callable),
  1090. std::forward<Allocator>(allocator));
  1091. } else {
  1092. operator=(nullptr);
  1093. }
  1094. }
  1095. /// Returns true when the erasure doesn't hold any erased object
  1096. constexpr bool empty() const noexcept {
  1097. return vtable_.empty();
  1098. }
  1099. /// Invoke the function of the erasure at the given index
  1100. ///
  1101. /// We define this out of class to be able to forward the qualified
  1102. /// erasure correctly.
  1103. template <std::size_t Index, typename Erasure, typename... Args>
  1104. static constexpr decltype(auto) invoke(Erasure&& erasure, Args&&... args) {
  1105. auto const capacity = erasure.capacity();
  1106. return erasure.vtable_.template invoke<Index>(
  1107. std::forward<Erasure>(erasure).opaque_ptr(), capacity,
  1108. std::forward<Args>(args)...);
  1109. }
  1110. };
  1111. // A non owning erasure
  1112. template </*bool IsOwning = false, */ typename Config, bool IsThrowing,
  1113. bool HasStrongExceptGuarantee, typename... Args>
  1114. class erasure<false, Config,
  1115. property<IsThrowing, HasStrongExceptGuarantee, Args...>> {
  1116. template <bool, typename, typename>
  1117. friend class erasure;
  1118. template <std::size_t, typename, typename...>
  1119. friend class operator_impl;
  1120. using property_t = property<IsThrowing, HasStrongExceptGuarantee, Args...>;
  1121. using invoke_table_t = invocation_table::invoke_table<Args...>;
  1122. typename invoke_table_t::type invoke_table_;
  1123. /// The internal pointer to the non owned object
  1124. data_accessor view_;
  1125. public:
  1126. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1127. constexpr erasure() noexcept
  1128. : invoke_table_(
  1129. invoke_table_t::template get_empty_invocation_table<IsThrowing>()),
  1130. view_(nullptr) {
  1131. }
  1132. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1133. constexpr erasure(std::nullptr_t) noexcept
  1134. : invoke_table_(
  1135. invoke_table_t::template get_empty_invocation_table<IsThrowing>()),
  1136. view_(nullptr) {
  1137. }
  1138. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1139. constexpr erasure(erasure&& right) noexcept
  1140. : invoke_table_(right.invoke_table_), view_(right.view_) {
  1141. }
  1142. constexpr erasure(erasure const& /*right*/) = default;
  1143. template <typename OtherConfig>
  1144. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1145. constexpr erasure(erasure<false, OtherConfig, property_t> right) noexcept
  1146. : invoke_table_(right.invoke_table_), view_(right.view_) {
  1147. }
  1148. template <typename T>
  1149. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1150. constexpr erasure(std::false_type /*use_bool_op*/, T&& object)
  1151. : invoke_table_(invoke_table_t::template get_invocation_view_table_of<
  1152. std::decay_t<T>>()),
  1153. view_(address_taker<std::decay_t<T>>::take(std::forward<T>(object))) {
  1154. }
  1155. template <typename T>
  1156. // NOLINTNEXTLINE(cppcoreguidlines-pro-type-member-init)
  1157. FU2_DETAIL_CXX14_CONSTEXPR erasure(std::true_type use_bool_op, T&& object) {
  1158. this->assign(use_bool_op, std::forward<T>(object));
  1159. }
  1160. ~erasure() = default;
  1161. constexpr erasure&
  1162. operator=(std::nullptr_t) noexcept(HasStrongExceptGuarantee) {
  1163. invoke_table_ =
  1164. invoke_table_t::template get_empty_invocation_table<IsThrowing>();
  1165. view_.ptr_ = nullptr;
  1166. return *this;
  1167. }
  1168. constexpr erasure& operator=(erasure&& right) noexcept {
  1169. invoke_table_ = right.invoke_table_;
  1170. view_ = right.view_;
  1171. right = nullptr;
  1172. return *this;
  1173. }
  1174. constexpr erasure& operator=(erasure const& /*right*/) = default;
  1175. template <typename OtherConfig>
  1176. constexpr erasure&
  1177. operator=(erasure<true, OtherConfig, property_t> right) noexcept {
  1178. invoke_table_ = right.invoke_table_;
  1179. view_ = right.view_;
  1180. return *this;
  1181. }
  1182. template <typename T>
  1183. constexpr void assign(std::false_type /*use_bool_op*/, T&& callable) {
  1184. invoke_table_ = invoke_table_t::template get_invocation_view_table_of<
  1185. std::decay_t<T>>();
  1186. view_.ptr_ =
  1187. address_taker<std::decay_t<T>>::take(std::forward<T>(callable));
  1188. }
  1189. template <typename T>
  1190. constexpr void assign(std::true_type /*use_bool_op*/, T&& callable) {
  1191. if (bool(callable)) {
  1192. assign(std::false_type{}, std::forward<T>(callable));
  1193. } else {
  1194. operator=(nullptr);
  1195. }
  1196. }
  1197. /// Returns true when the erasure doesn't hold any erased object
  1198. constexpr bool empty() const noexcept {
  1199. return view_.ptr_ == nullptr;
  1200. }
  1201. template <std::size_t Index, typename Erasure, typename... T>
  1202. static constexpr decltype(auto) invoke(Erasure&& erasure, T&&... args) {
  1203. auto thunk = invoke_table_t::template fetch<Index>(erasure.invoke_table_);
  1204. return thunk(&(erasure.view_), 0UL, std::forward<T>(args)...);
  1205. }
  1206. };
  1207. } // namespace type_erasure
  1208. /// Deduces to a true_type if the type T provides the given signature and the
  1209. /// signature is noexcept correct callable.
  1210. template <typename T, typename Signature,
  1211. typename Trait =
  1212. type_erasure::invocation_table::function_trait<Signature>>
  1213. struct accepts_one
  1214. : std::integral_constant<
  1215. bool, invocation::can_invoke<typename Trait::template callable<T>,
  1216. typename Trait::arguments>::value &&
  1217. invocation::is_noexcept_correct<
  1218. Trait::is_noexcept::value,
  1219. typename Trait::template callable<T>,
  1220. typename Trait::arguments>::value> {};
  1221. /// Deduces to a true_type if the type T provides all signatures
  1222. template <typename T, typename Signatures, typename = void>
  1223. struct accepts_all : std::false_type {};
  1224. template <typename T, typename... Signatures>
  1225. struct accepts_all<
  1226. T, identity<Signatures...>,
  1227. void_t<std::enable_if_t<accepts_one<T, Signatures>::value>...>>
  1228. : std::true_type {};
  1229. /// Deduces to a true_type if the type T is implementing operator bool()
  1230. /// or if the type is convertible to bool directly, this also implements an
  1231. /// optimizations for function references `void(&)()` which are can never
  1232. /// be null and for such a conversion to bool would never return false.
  1233. #if defined(FU2_HAS_NO_EMPTY_PROPAGATION)
  1234. template <typename T>
  1235. struct use_bool_op : std::false_type {};
  1236. #else
  1237. template <typename T, typename = void>
  1238. struct has_bool_op : std::false_type {};
  1239. template <typename T>
  1240. struct has_bool_op<T, void_t<decltype(bool(std::declval<T>()))>>
  1241. : std::true_type {
  1242. #ifndef NDEBUG
  1243. static_assert(!std::is_pointer<T>::value,
  1244. "Missing deduction for function pointer!");
  1245. #endif
  1246. };
  1247. template <typename T>
  1248. struct use_bool_op : has_bool_op<T> {};
  1249. #define FU2_DEFINE_USE_OP_TRAIT(CONST, VOLATILE, NOEXCEPT) \
  1250. template <typename Ret, typename... Args> \
  1251. struct use_bool_op<Ret (*CONST VOLATILE)(Args...) NOEXCEPT> \
  1252. : std::true_type {};
  1253. FU2_DETAIL_EXPAND_CV(FU2_DEFINE_USE_OP_TRAIT)
  1254. #undef FU2_DEFINE_USE_OP_TRAIT
  1255. template <typename Ret, typename... Args>
  1256. struct use_bool_op<Ret(Args...)> : std::false_type {};
  1257. #if defined(FU2_HAS_CXX17_NOEXCEPT_FUNCTION_TYPE)
  1258. template <typename Ret, typename... Args>
  1259. struct use_bool_op<Ret(Args...) noexcept> : std::false_type {};
  1260. #endif
  1261. #endif // FU2_HAS_NO_EMPTY_PROPAGATION
  1262. template <typename Config, typename T>
  1263. struct assert_wrong_copy_assign {
  1264. static_assert(!Config::is_owning || !Config::is_copyable ||
  1265. std::is_copy_constructible<std::decay_t<T>>::value,
  1266. "Can't wrap a non copyable object into a unique function!");
  1267. using type = void;
  1268. };
  1269. template <bool IsStrongExceptGuaranteed, typename T>
  1270. struct assert_no_strong_except_guarantee {
  1271. static_assert(
  1272. !IsStrongExceptGuaranteed ||
  1273. (std::is_nothrow_move_constructible<T>::value &&
  1274. std::is_nothrow_destructible<T>::value),
  1275. "Can't wrap a object an object that has no strong exception guarantees "
  1276. "if this is required by the wrapper!");
  1277. using type = void;
  1278. };
  1279. /// SFINAES out if the given callable is not copyable correct to the left one.
  1280. template <typename LeftConfig, typename RightConfig>
  1281. using enable_if_copyable_correct_t =
  1282. std::enable_if_t<(!LeftConfig::is_copyable || RightConfig::is_copyable)>;
  1283. template <typename LeftConfig, typename RightConfig>
  1284. using is_owning_correct =
  1285. std::integral_constant<bool,
  1286. (LeftConfig::is_owning == RightConfig::is_owning)>;
  1287. /// SFINAES out if the given function2 is not owning correct to this one
  1288. template <typename LeftConfig, typename RightConfig>
  1289. using enable_if_owning_correct_t =
  1290. std::enable_if_t<is_owning_correct<LeftConfig, RightConfig>::value>;
  1291. template <typename Config, bool IsThrowing, bool HasStrongExceptGuarantee,
  1292. typename... Args>
  1293. class function<Config, property<IsThrowing, HasStrongExceptGuarantee, Args...>>
  1294. : type_erasure::invocation_table::operator_impl<
  1295. 0U,
  1296. function<Config,
  1297. property<IsThrowing, HasStrongExceptGuarantee, Args...>>,
  1298. Args...> {
  1299. template <typename, typename>
  1300. friend class function;
  1301. template <std::size_t, typename, typename...>
  1302. friend class type_erasure::invocation_table::operator_impl;
  1303. using property_t = property<IsThrowing, HasStrongExceptGuarantee, Args...>;
  1304. using erasure_t =
  1305. type_erasure::erasure<Config::is_owning, Config, property_t>;
  1306. template <typename T>
  1307. using enable_if_can_accept_all_t =
  1308. std::enable_if_t<accepts_all<std::decay_t<T>, identity<Args...>>::value>;
  1309. template <typename Function, typename = void>
  1310. struct is_convertible_to_this : std::false_type {};
  1311. template <typename RightConfig>
  1312. struct is_convertible_to_this<
  1313. function<RightConfig, property_t>,
  1314. void_t<enable_if_copyable_correct_t<Config, RightConfig>,
  1315. enable_if_owning_correct_t<Config, RightConfig>>>
  1316. : std::true_type {};
  1317. template <typename T>
  1318. using enable_if_not_convertible_to_this =
  1319. std::enable_if_t<!is_convertible_to_this<std::decay_t<T>>::value>;
  1320. template <typename T>
  1321. using enable_if_owning_t =
  1322. std::enable_if_t<std::is_same<T, T>::value && Config::is_owning>;
  1323. template <typename T>
  1324. using assert_wrong_copy_assign_t =
  1325. typename assert_wrong_copy_assign<Config, std::decay_t<T>>::type;
  1326. template <typename T>
  1327. using assert_no_strong_except_guarantee_t =
  1328. typename assert_no_strong_except_guarantee<HasStrongExceptGuarantee,
  1329. std::decay_t<T>>::type;
  1330. erasure_t erasure_;
  1331. public:
  1332. /// Default constructor which empty constructs the function
  1333. function() = default;
  1334. ~function() = default;
  1335. explicit FU2_DETAIL_CXX14_CONSTEXPR
  1336. function(function const& /*right*/) = default;
  1337. explicit FU2_DETAIL_CXX14_CONSTEXPR function(function&& /*right*/) = default;
  1338. /// Copy construction from another copyable function
  1339. template <typename RightConfig,
  1340. std::enable_if_t<RightConfig::is_copyable>* = nullptr,
  1341. enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
  1342. enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
  1343. FU2_DETAIL_CXX14_CONSTEXPR
  1344. function(function<RightConfig, property_t> const& right)
  1345. : erasure_(right.erasure_) {
  1346. }
  1347. /// Move construction from another function
  1348. template <typename RightConfig,
  1349. enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
  1350. enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
  1351. FU2_DETAIL_CXX14_CONSTEXPR function(function<RightConfig, property_t>&& right)
  1352. : erasure_(std::move(right.erasure_)) {
  1353. }
  1354. /// Construction from a callable object which overloads the `()` operator
  1355. template <typename T, //
  1356. enable_if_not_convertible_to_this<T>* = nullptr,
  1357. enable_if_can_accept_all_t<T>* = nullptr,
  1358. assert_wrong_copy_assign_t<T>* = nullptr,
  1359. assert_no_strong_except_guarantee_t<T>* = nullptr>
  1360. FU2_DETAIL_CXX14_CONSTEXPR function(T&& callable)
  1361. : erasure_(use_bool_op<unrefcv_t<T>>{}, std::forward<T>(callable)) {
  1362. }
  1363. template <typename T, typename Allocator, //
  1364. enable_if_not_convertible_to_this<T>* = nullptr,
  1365. enable_if_can_accept_all_t<T>* = nullptr,
  1366. enable_if_owning_t<T>* = nullptr,
  1367. assert_wrong_copy_assign_t<T>* = nullptr,
  1368. assert_no_strong_except_guarantee_t<T>* = nullptr>
  1369. FU2_DETAIL_CXX14_CONSTEXPR function(T&& callable, Allocator&& allocator)
  1370. : erasure_(use_bool_op<unrefcv_t<T>>{}, std::forward<T>(callable),
  1371. std::forward<Allocator>(allocator)) {
  1372. }
  1373. /// Empty constructs the function
  1374. FU2_DETAIL_CXX14_CONSTEXPR function(std::nullptr_t np) : erasure_(np) {
  1375. }
  1376. function& operator=(function const& /*right*/) = default;
  1377. function& operator=(function&& /*right*/) = default;
  1378. /// Copy assigning from another copyable function
  1379. template <typename RightConfig,
  1380. std::enable_if_t<RightConfig::is_copyable>* = nullptr,
  1381. enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
  1382. enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
  1383. function& operator=(function<RightConfig, property_t> const& right) {
  1384. erasure_ = right.erasure_;
  1385. return *this;
  1386. }
  1387. /// Move assigning from another function
  1388. template <typename RightConfig,
  1389. enable_if_copyable_correct_t<Config, RightConfig>* = nullptr,
  1390. enable_if_owning_correct_t<Config, RightConfig>* = nullptr>
  1391. function& operator=(function<RightConfig, property_t>&& right) {
  1392. erasure_ = std::move(right.erasure_);
  1393. return *this;
  1394. }
  1395. /// Move assigning from a callable object
  1396. template <typename T, // ...
  1397. enable_if_not_convertible_to_this<T>* = nullptr,
  1398. enable_if_can_accept_all_t<T>* = nullptr,
  1399. assert_wrong_copy_assign_t<T>* = nullptr,
  1400. assert_no_strong_except_guarantee_t<T>* = nullptr>
  1401. function& operator=(T&& callable) {
  1402. erasure_.assign(use_bool_op<unrefcv_t<T>>{}, std::forward<T>(callable));
  1403. return *this;
  1404. }
  1405. /// Clears the function
  1406. function& operator=(std::nullptr_t np) {
  1407. erasure_ = np;
  1408. return *this;
  1409. }
  1410. /// Returns true when the function is empty
  1411. bool empty() const noexcept {
  1412. return erasure_.empty();
  1413. }
  1414. /// Returns true when the function isn't empty
  1415. explicit operator bool() const noexcept {
  1416. return !empty();
  1417. }
  1418. /// Assigns a new target with an optional allocator
  1419. template <typename T, typename Allocator = std::allocator<std::decay_t<T>>,
  1420. enable_if_not_convertible_to_this<T>* = nullptr,
  1421. enable_if_can_accept_all_t<T>* = nullptr,
  1422. assert_wrong_copy_assign_t<T>* = nullptr,
  1423. assert_no_strong_except_guarantee_t<T>* = nullptr>
  1424. void assign(T&& callable, Allocator&& allocator = Allocator{}) {
  1425. erasure_.assign(use_bool_op<unrefcv_t<T>>{}, std::forward<T>(callable),
  1426. std::forward<Allocator>(allocator));
  1427. }
  1428. /// Swaps this function with the given function
  1429. void swap(function& other) noexcept(HasStrongExceptGuarantee) {
  1430. if (&other == this) {
  1431. return;
  1432. }
  1433. function cache = std::move(other);
  1434. other = std::move(*this);
  1435. *this = std::move(cache);
  1436. }
  1437. /// Swaps the left function with the right one
  1438. friend void swap(function& left,
  1439. function& right) noexcept(HasStrongExceptGuarantee) {
  1440. left.swap(right);
  1441. }
  1442. /// Calls the wrapped callable object
  1443. using type_erasure::invocation_table::operator_impl<
  1444. 0U, function<Config, property_t>, Args...>::operator();
  1445. };
  1446. template <typename Config, typename Property>
  1447. bool operator==(function<Config, Property> const& f, std::nullptr_t) {
  1448. return !bool(f);
  1449. }
  1450. template <typename Config, typename Property>
  1451. bool operator!=(function<Config, Property> const& f, std::nullptr_t) {
  1452. return bool(f);
  1453. }
  1454. template <typename Config, typename Property>
  1455. bool operator==(std::nullptr_t, function<Config, Property> const& f) {
  1456. return !bool(f);
  1457. }
  1458. template <typename Config, typename Property>
  1459. bool operator!=(std::nullptr_t, function<Config, Property> const& f) {
  1460. return bool(f);
  1461. }
  1462. // Default intended object size of the function
  1463. using object_size = std::integral_constant<std::size_t, 32U>;
  1464. } // namespace detail
  1465. } // namespace abi_400
  1466. /// Can be passed to function_base as template argument which causes
  1467. /// the internal small buffer to be sized according to the given size,
  1468. /// and aligned with the given alignment.
  1469. template <std::size_t Capacity,
  1470. std::size_t Alignment = alignof(std::max_align_t)>
  1471. struct capacity_fixed {
  1472. static constexpr std::size_t capacity = Capacity;
  1473. static constexpr std::size_t alignment = Alignment;
  1474. };
  1475. /// Default capacity for small functor optimization
  1476. struct capacity_default
  1477. : capacity_fixed<detail::object_size::value - (2 * sizeof(void*))> {};
  1478. /// Can be passed to function_base as template argument which causes
  1479. /// the internal small buffer to be removed from the callable wrapper.
  1480. /// The owning function_base will then allocate memory for every object
  1481. /// it applies a type erasure on.
  1482. struct capacity_none : capacity_fixed<0UL> {};
  1483. /// Can be passed to function_base as template argument which causes
  1484. /// the internal small buffer to be sized such that it can hold
  1485. /// the given object without allocating memory for an applied type erasure.
  1486. template <typename T>
  1487. struct capacity_can_hold {
  1488. static constexpr std::size_t capacity = sizeof(T);
  1489. static constexpr std::size_t alignment = alignof(T);
  1490. };
  1491. /// An adaptable function wrapper base for arbitrary functional types.
  1492. ///
  1493. /// \tparam IsOwning Is true when the type erasure shall be owning the object.
  1494. ///
  1495. /// \tparam IsCopyable Defines whether the function is copyable or not
  1496. ///
  1497. /// \tparam Capacity Defines the internal capacity of the function
  1498. /// for small functor optimization.
  1499. /// The size of the whole function object will be the capacity
  1500. /// plus the size of two pointers. If the capacity is zero,
  1501. /// the size will increase through one additional pointer
  1502. /// so the whole object has the size of 3 * sizeof(void*).
  1503. /// The type which is passed to the Capacity template parameter
  1504. /// shall provide a capacity and alignment member which
  1505. /// looks like the following example:
  1506. /// ```cpp
  1507. /// struct my_capacity {
  1508. /// static constexpr std::size_t capacity = sizeof(my_type);
  1509. /// static constexpr std::size_t alignment = alignof(my_type);
  1510. /// };
  1511. /// ```
  1512. ///
  1513. /// \tparam IsThrowing Defines whether the function throws an exception on
  1514. /// empty function call, `std::abort` is called otherwise.
  1515. ///
  1516. /// \tparam HasStrongExceptGuarantee Defines whether all objects satisfy the
  1517. /// strong exception guarantees,
  1518. /// which means the function type will satisfy
  1519. /// the strong exception guarantees too.
  1520. ///
  1521. /// \tparam Signatures Defines the signature of the callable wrapper
  1522. ///
  1523. template <bool IsOwning, bool IsCopyable, typename Capacity, bool IsThrowing,
  1524. bool HasStrongExceptGuarantee, typename... Signatures>
  1525. using function_base = detail::function<
  1526. detail::config<IsOwning, IsCopyable, Capacity>,
  1527. detail::property<IsThrowing, HasStrongExceptGuarantee, Signatures...>>;
  1528. /// An owning copyable function wrapper for arbitrary callable types.
  1529. template <typename... Signatures>
  1530. using function = function_base<true, true, capacity_default, //
  1531. true, false, Signatures...>;
  1532. /// An owning non copyable function wrapper for arbitrary callable types.
  1533. template <typename... Signatures>
  1534. using unique_function = function_base<true, false, capacity_default, //
  1535. true, false, Signatures...>;
  1536. /// A non owning copyable function wrapper for arbitrary callable types.
  1537. template <typename... Signatures>
  1538. using function_view = function_base<false, true, capacity_default, //
  1539. true, false, Signatures...>;
  1540. #if !defined(FU2_HAS_DISABLED_EXCEPTIONS)
  1541. /// Exception type that is thrown when invoking empty function objects
  1542. /// and exception support isn't disabled.
  1543. ///
  1544. /// Exception support is enabled if
  1545. /// the template parameter 'Throwing' is set to true (default).
  1546. ///
  1547. /// This type will default to std::bad_function_call if the
  1548. /// functional header is used, otherwise the library provides its own type.
  1549. ///
  1550. /// You may disable the inclusion of the functional header
  1551. /// through defining `FU2_WITH_NO_FUNCTIONAL_HEADER`.
  1552. ///
  1553. using detail::type_erasure::invocation_table::bad_function_call;
  1554. #endif
  1555. /// Returns a callable object, which unifies all callable objects
  1556. /// that were passed to this function.
  1557. ///
  1558. /// ```cpp
  1559. /// auto overloaded = fu2::overload([](std::true_type) { return true; },
  1560. /// [](std::false_type) { return false; });
  1561. /// ```
  1562. ///
  1563. /// \param callables A pack of callable objects with arbitrary signatures.
  1564. ///
  1565. /// \returns A callable object which exposes the
  1566. ///
  1567. template <typename... T>
  1568. constexpr auto overload(T&&... callables) {
  1569. return detail::overloading::overload(std::forward<T>(callables)...);
  1570. }
  1571. } // namespace fu2
  1572. #undef FU2_DETAIL_EXPAND_QUALIFIERS
  1573. #undef FU2_DETAIL_EXPAND_QUALIFIERS_NOEXCEPT
  1574. #undef FU2_DETAIL_EXPAND_CV
  1575. #undef FU2_DETAIL_EXPAND_CV_NOEXCEPT
  1576. #undef FU2_DETAIL_UNREACHABLE_INTRINSIC
  1577. #undef FU2_DETAIL_TRAP
  1578. #undef FU2_DETAIL_CXX14_CONSTEXPR
  1579. #endif // FU2_INCLUDED_FUNCTION2_HPP_