1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_FIT_FUNCTION_INTERNAL_H_ 6 #define LIB_FIT_FUNCTION_INTERNAL_H_ 7 8 #include <stddef.h> 9 #include <stdlib.h> 10 11 #include <new> 12 #include <type_traits> 13 #include <utility> 14 15 namespace fit { 16 namespace internal { 17 18 template <typename Result, typename... Args> 19 struct target_ops final { 20 void* (*get)(void* bits); 21 Result (*invoke)(void* bits, Args... args); 22 void (*move)(void* from_bits, void* to_bits); 23 void (*destroy)(void* bits); 24 }; 25 26 template <typename Callable, bool is_inline, typename Result, typename... Args> 27 struct target; 28 29 template <typename Result, typename... Args> 30 struct target<decltype(nullptr), true, Result, Args...> final { 31 static Result invoke(void* bits, Args... args) { 32 abort(); 33 } 34 35 static const target_ops<Result, Args...> ops; 36 }; 37 38 inline void* null_target_get(void* bits) { 39 return nullptr; 40 } 41 inline void null_target_move(void* from_bits, void* to_bits) {} 42 inline void null_target_destroy(void* bits) {} 43 44 template <typename Result, typename... Args> 45 constexpr target_ops<Result, Args...> target<decltype(nullptr), true, Result, Args...>::ops = { 46 &null_target_get, 47 &target::invoke, 48 &null_target_move, 49 &null_target_destroy}; 50 51 template <typename Callable, typename Result, typename... Args> 52 struct target<Callable, true, Result, Args...> final { 53 static void initialize(void* bits, Callable&& target) { 54 new (bits) Callable(std::move(target)); 55 } 56 static Result invoke(void* bits, Args... args) { 57 auto& target = *static_cast<Callable*>(bits); 58 return target(std::forward<Args>(args)...); 59 } 60 static void move(void* from_bits, void* to_bits) { 61 auto& from_target = *static_cast<Callable*>(from_bits); 62 new (to_bits) Callable(std::move(from_target)); 63 from_target.~Callable(); 64 } 65 static void destroy(void* bits) { 66 auto& target = *static_cast<Callable*>(bits); 67 target.~Callable(); 68 } 69 70 static const target_ops<Result, Args...> ops; 71 }; 72 73 inline void* inline_target_get(void* bits) { 74 return bits; 75 } 76 77 template <typename Callable, typename Result, typename... Args> 78 constexpr target_ops<Result, Args...> target<Callable, true, Result, Args...>::ops = { 79 &inline_target_get, 80 &target::invoke, 81 &target::move, 82 &target::destroy}; 83 84 template <typename Callable, typename Result, typename... Args> 85 struct target<Callable, false, Result, Args...> final { 86 static void initialize(void* bits, Callable&& target) { 87 auto ptr = static_cast<Callable**>(bits); 88 *ptr = new Callable(std::move(target)); 89 } 90 static Result invoke(void* bits, Args... args) { 91 auto& target = **static_cast<Callable**>(bits); 92 return target(std::forward<Args>(args)...); 93 } 94 static void move(void* from_bits, void* to_bits) { 95 auto from_ptr = static_cast<Callable**>(from_bits); 96 auto to_ptr = static_cast<Callable**>(to_bits); 97 *to_ptr = *from_ptr; 98 } 99 static void destroy(void* bits) { 100 auto ptr = static_cast<Callable**>(bits); 101 delete *ptr; 102 } 103 104 static const target_ops<Result, Args...> ops; 105 }; 106 107 inline void* heap_target_get(void* bits) { 108 return *static_cast<void**>(bits); 109 } 110 111 template <typename Callable, typename Result, typename... Args> 112 constexpr target_ops<Result, Args...> target<Callable, false, Result, Args...>::ops = { 113 &heap_target_get, 114 &target::invoke, 115 &target::move, 116 &target::destroy}; 117 118 } // namespace internal 119 } // namespace fit 120 121 #endif // LIB_FIT_FUNCTION_INTERNAL_H_ 122