tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
inplace_function.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2
3#ifndef TETL_FUNCTIONAL_INPLACE_FUNCTION_HPP
4#define TETL_FUNCTIONAL_INPLACE_FUNCTION_HPP
5
11#include <etl/_new/operator.hpp>
18#include <etl/_utility/swap.hpp>
19
20namespace etl {
21
23 constexpr bad_function_call() = default;
24
25 constexpr explicit bad_function_call(char const* what)
27 {
28 }
29};
30
31namespace detail {
32
33template <typename T>
34struct wrapper {
35 using type = T;
36};
37
38template <typename R, typename... Args>
39struct inplace_func_vtable {
40 using storage_ptr_t = void*;
41
42 using invoke_ptr_t = R (*)(storage_ptr_t, Args&&...);
43 using process_ptr_t = void (*)(storage_ptr_t, storage_ptr_t);
44 using destructor_ptr_t = void (*)(storage_ptr_t);
45
46 invoke_ptr_t const invoke_ptr;
47 process_ptr_t const copy_ptr;
48 process_ptr_t const relocate_ptr;
49 destructor_ptr_t const destructor_ptr;
50
51 explicit constexpr inplace_func_vtable()
52 : invoke_ptr{[](storage_ptr_t /*p*/, Args&&... /*args*/) -> R {
53 etl::raise<etl::bad_function_call>("empty inplace_func_vtable");
54 }}
55 , copy_ptr{[](storage_ptr_t /*p*/, storage_ptr_t /*p*/) -> void {}}
56 , relocate_ptr{[](storage_ptr_t /*p*/, storage_ptr_t /*p*/) -> void {}}
57 , destructor_ptr{[](storage_ptr_t /*p*/) -> void {}}
58 {
59 }
60
61 template <typename C>
62 explicit constexpr inplace_func_vtable(wrapper<C> /*ignore*/)
63 : invoke_ptr{[](storage_ptr_t storagePtr, Args&&... args) -> R {
64 return (*static_cast<C*>(storagePtr))(static_cast<Args&&>(args)...);
65 }}
66 , copy_ptr{[](storage_ptr_t dstPtr, storage_ptr_t srcPtr) -> void {
67 ::new (dstPtr) C{(*static_cast<C*>(srcPtr))};
68 }}
69 , relocate_ptr{[](storage_ptr_t dstPtr, storage_ptr_t srcPtr) -> void {
70 ::new (dstPtr) C{etl::move(*static_cast<C*>(srcPtr))};
71 static_cast<C*>(srcPtr)->~C();
72 }}
73 , destructor_ptr{[](storage_ptr_t srcPtr) -> void { static_cast<C*>(srcPtr)->~C(); }}
74 {
75 }
76
77 inplace_func_vtable(inplace_func_vtable const&) = delete;
78 inplace_func_vtable(inplace_func_vtable&&) = delete;
79
80 auto operator=(inplace_func_vtable const&) -> inplace_func_vtable& = delete;
81 auto operator=(inplace_func_vtable&&) -> inplace_func_vtable& = delete;
82
83 ~inplace_func_vtable() = default;
84};
85
86template <typename R, typename... Args>
87inline constexpr auto empty_vtable = inplace_func_vtable<R, Args...>{};
88
89template <size_t DstCap, size_t DstAlign, size_t SrcCap, size_t SrcAlign>
90struct is_valid_inplace_destination : etl::true_type {
91 static_assert(DstCap >= SrcCap);
92 static_assert(DstAlign % SrcAlign == 0);
93};
94
95} // namespace detail
96
97template <typename Signature, size_t Capacity = sizeof(void*), size_t Alignment = alignof(aligned_storage_t<Capacity>)>
99
100namespace detail {
101template <typename>
102struct is_inplace_function : false_type { };
103
104template <typename Sig, size_t Cap, size_t Align>
105struct is_inplace_function<inplace_function<Sig, Cap, Align>> : etl::true_type { };
106} // namespace detail
107
108template <typename R, typename... Args, size_t Capacity, size_t Alignment>
109struct inplace_function<R(Args...), Capacity, Alignment> {
110private:
112 using vtable_t = detail::inplace_func_vtable<R, Args...>;
113 using vtable_ptr_t = vtable_t const*;
114
115 template <typename, size_t, size_t>
116 friend struct inplace_function;
117
118public:
121
124 : _vtable{etl::addressof(detail::empty_vtable<R, Args...>)}
125 {
126 }
127
128 template <typename T, typename C = decay_t<T>>
129 requires(!detail::is_inplace_function<C>::value && is_invocable_r_v<R, C&, Args...>)
130 inplace_function(T&& closure)
131 {
132 static_assert(is_copy_constructible_v<C>, "inplace_function cannot be constructed from non-copyable type");
133 static_assert(
134 sizeof(C) <= Capacity,
135 "inplace_function cannot be constructed from object with this (large) size"
136 );
137 static_assert(
138 Alignment % alignof(C) == 0,
139 "inplace_function cannot be constructed from object with this (large) alignment"
140 );
141
142 static constexpr vtable_t const vt{detail::wrapper<C>{}};
143 _vtable = etl::addressof(vt);
144
145 ::new (etl::addressof(_storage)) C{etl::forward<T>(closure)};
146 }
147
148 template <size_t Cap, size_t Align>
149 inplace_function(inplace_function<R(Args...), Cap, Align> const& other)
150 : inplace_function{other._vtable, other._vtable->copy_ptr, etl::addressof(other._storage)}
151 {
152 static_assert(
154 "conversion not allowed"
155 );
156 }
157
158 template <size_t Cap, size_t Align>
159 inplace_function(inplace_function<R(Args...), Cap, Align>&& other) noexcept
160 : inplace_function{other._vtable, other._vtable->relocate_ptr, etl::addressof(other._storage)}
161 {
162 static_assert(
164 "conversion not allowed"
165 );
166 other._vtable = etl::addressof(detail::empty_vtable<R, Args...>);
167 }
168
170 inplace_function(nullptr_t /*ignore*/) noexcept
171 : _vtable{etl::addressof(detail::empty_vtable<R, Args...>)}
172 {
173 }
174
176 : _vtable{other._vtable}
177 {
178 _vtable->copy_ptr(etl::addressof(_storage), etl::addressof(other._storage));
179 }
180
182 : _vtable{exchange(other._vtable, etl::addressof(detail::empty_vtable<R, Args...>))}
183 {
184 _vtable->relocate_ptr(etl::addressof(_storage), etl::addressof(other._storage));
185 }
186
190 {
191 _vtable->destructor_ptr(etl::addressof(_storage));
192 _vtable = etl::addressof(detail::empty_vtable<R, Args...>);
193 return *this;
194 }
195
197 {
198 _vtable->destructor_ptr(etl::addressof(_storage));
199 _vtable = exchange(other._vtable, etl::addressof(detail::empty_vtable<R, Args...>));
200 _vtable->relocate_ptr(etl::addressof(_storage), etl::addressof(other._storage));
201 return *this;
202 }
203
206 ~inplace_function() { _vtable->destructor_ptr(etl::addressof(_storage)); }
207
209 auto operator()(Args... args) const -> R
210 {
211 return _vtable->invoke_ptr(etl::addressof(_storage), etl::forward<Args>(args)...);
212 }
213
215 [[nodiscard]] explicit constexpr operator bool() const noexcept
216 {
217 return _vtable != etl::addressof(detail::empty_vtable<R, Args...>);
218 }
219
221 auto swap(inplace_function& other) noexcept -> void
222 {
223 auto tmp = storage_t{};
224 _vtable->relocate_ptr(etl::addressof(tmp), etl::addressof(_storage));
225 other._vtable->relocate_ptr(etl::addressof(_storage), etl::addressof(other._storage));
226 _vtable->relocate_ptr(etl::addressof(other._storage), etl::addressof(tmp));
227 etl::swap(_vtable, other._vtable);
228 }
229
230private:
232 vtable_ptr_t vtable,
233 typename vtable_t::process_ptr_t process,
234 typename vtable_t::storage_ptr_t storage
235 )
236 : _vtable{vtable}
237 {
238 process(etl::addressof(_storage), storage);
239 }
240
241 vtable_ptr_t _vtable;
242 storage_t mutable _storage;
243};
244
248template <typename R, typename... Args, size_t Capacity, size_t Alignment>
249auto swap(
250 inplace_function<R(Args...), Capacity, Alignment>& lhs,
251 inplace_function<R(Args...), Capacity, Alignment>& rhs
252) noexcept -> void
253{
254 lhs.swap(rhs);
255}
256
260template <typename R, typename... Args, size_t Capacity, size_t Alignment>
261[[nodiscard]] constexpr auto
262operator==(inplace_function<R(Args...), Capacity, Alignment> const& f, nullptr_t /*ignore*/) noexcept -> bool
263{
264 return !static_cast<bool>(f);
265}
266
270template <typename R, typename... Args, size_t Capacity, size_t Alignment>
271[[nodiscard]] constexpr auto
272operator!=(inplace_function<R(Args...), Capacity, Alignment> const& f, nullptr_t /*ignore*/) noexcept -> bool
273{
274 return static_cast<bool>(f);
275}
276
280template <typename R, typename... Args, size_t Capacity, size_t Alignment>
281[[nodiscard]] constexpr auto
282operator==(nullptr_t /*ignore*/, inplace_function<R(Args...), Capacity, Alignment> const& f) noexcept -> bool
283{
284 return !static_cast<bool>(f);
285}
286
290template <typename R, typename... Args, size_t Capacity, size_t Alignment>
291[[nodiscard]] constexpr auto
292operator!=(nullptr_t /*ignore*/, inplace_function<R(Args...), Capacity, Alignment> const& f) noexcept -> bool
293{
294 return static_cast<bool>(f);
295}
296
297} // namespace etl
298
299#endif // TETL_FUNCTIONAL_INPLACE_FUNCTION_HPP
constexpr auto move(InputIt first, InputIt last, OutputIt destination) -> OutputIt
Moves the elements in the range [first, last), to another range beginning at destination,...
Definition move.hpp:26
Definition adjacent_find.hpp:8
constexpr bool is_copy_constructible_v
Definition is_copy_constructible.hpp:30
constexpr auto operator==(inplace_function< R(Args...), Capacity, Alignment > const &f, nullptr_t) noexcept -> bool
Compares a etl::inplace_function with a null pointer. Empty functions (that is, functions without a c...
Definition inplace_function.hpp:262
constexpr auto addressof(T &arg) noexcept -> T *
Obtains the actual address of the object or function arg, even in presence of overloaded operator&.
Definition addressof.hpp:15
constexpr auto operator!=(inplace_function< R(Args...), Capacity, Alignment > const &f, nullptr_t) noexcept -> bool
Compares a etl::inplace_function with a null pointer. Empty functions (that is, functions without a c...
Definition inplace_function.hpp:272
TETL_NO_INLINE TETL_COLD auto raise(char const *msg, etl::source_location const loc=etl::source_location::current()) -> void
Definition raise.hpp:17
constexpr auto exchange(T &obj, U &&newValue) noexcept(etl::is_nothrow_move_constructible_v< T > and etl::is_nothrow_assignable_v< T &, U >) -> T
Replaces the value of obj with new_value and returns the old value of obj.
Definition exchange.hpp:16
bool_constant< true > true_type
Definition bool_constant.hpp:13
auto swap(inplace_function< R(Args...), Capacity, Alignment > &lhs, inplace_function< R(Args...), Capacity, Alignment > &rhs) noexcept -> void
Overloads the etl::swap algorithm for etl::inplace_function. Exchanges the state of lhs with that of ...
Definition inplace_function.hpp:249
bool_constant< false > false_type
Definition bool_constant.hpp:14
typename aligned_storage< Len, Align >::type aligned_storage_t
Definition aligned_storage.hpp:57
constexpr auto forward(remove_reference_t< T > &param) noexcept -> T &&
Forwards lvalues as either lvalues or as rvalues, depending on T. When t is a forwarding reference (a...
Definition forward.hpp:18
decltype(nullptr) nullptr_t
etl::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not it...
Definition nullptr_t.hpp:13
constexpr bad_function_call(char const *what)
Definition inplace_function.hpp:25
constexpr bad_function_call()=default
constexpr exception()=default
constexpr auto what() const noexcept -> char const *
Definition exception.hpp:16
auto operator()(Args... args) const -> R
Invokes the stored callable function target with the parameters args.
Definition inplace_function.hpp:209
inplace_function(inplace_function< R(Args...), Cap, Align > const &other)
Definition inplace_function.hpp:149
inplace_function(inplace_function &&other) noexcept
Definition inplace_function.hpp:181
inplace_function(inplace_function const &other)
Definition inplace_function.hpp:175
inplace_function(inplace_function< R(Args...), Cap, Align > &&other) noexcept
Definition inplace_function.hpp:159
integral_constant< size_t, Capacity > capacity
Definition inplace_function.hpp:119
inplace_function() noexcept
Creates an empty function.
Definition inplace_function.hpp:123
auto operator=(inplace_function other) noexcept -> inplace_function &
Definition inplace_function.hpp:196
inplace_function(nullptr_t) noexcept
Creates an empty function.
Definition inplace_function.hpp:170
~inplace_function()
Destroys the etl::inplace_function instance. If the etl::inplace_function is not empty,...
Definition inplace_function.hpp:206
inplace_function(T &&closure)
Definition inplace_function.hpp:130
auto swap(inplace_function &other) noexcept -> void
Exchanges the stored callable objects of *this and other.
Definition inplace_function.hpp:221
friend struct inplace_function
Definition inplace_function.hpp:116
auto operator=(nullptr_t) noexcept -> inplace_function &
Assigns a new target to etl::inplace_function. Drops the current target. *this is empty after the cal...
Definition inplace_function.hpp:189
integral_constant< size_t, Alignment > alignment
Definition inplace_function.hpp:120
Definition inplace_function.hpp:98
Definition integral_constant.hpp:9
static constexpr bool value
Definition integral_constant.hpp:10