4#ifndef TETL_FUNCTIONAL_INPLACE_FUNCTION_HPP
5#define TETL_FUNCTIONAL_INPLACE_FUNCTION_HPP
7#include <etl/_cstddef/nullptr_t.hpp>
8#include <etl/_cstddef/size_t.hpp>
9#include <etl/_exception/exception.hpp>
10#include <etl/_exception/raise.hpp>
11#include <etl/_memory/addressof.hpp>
12#include <etl/_new/operator
.hpp>
13#include <etl/_type_traits/aligned_storage.hpp>
14#include <etl/_type_traits/bool_constant.hpp>
15#include <etl/_type_traits/is_copy_constructible.hpp>
16#include <etl/_type_traits/is_invocable_r.hpp>
17#include <etl/_utility/exchange.hpp>
18#include <etl/_utility/forward.hpp>
19#include <etl/_utility/swap.hpp>
39template <
typename R,
typename... Args>
40struct inplace_func_vtable {
41 using storage_ptr_t =
void*;
43 using invoke_ptr_t = R (*)(storage_ptr_t, Args&&...);
44 using process_ptr_t =
void (*)(storage_ptr_t, storage_ptr_t);
45 using destructor_ptr_t =
void (*)(storage_ptr_t);
47 invoke_ptr_t
const invoke_ptr;
48 process_ptr_t
const copy_ptr;
49 process_ptr_t
const relocate_ptr;
50 destructor_ptr_t
const destructor_ptr;
52 explicit constexpr inplace_func_vtable()
53 : invoke_ptr{[](storage_ptr_t , Args&&... ) -> R {
56 , copy_ptr{[](storage_ptr_t , storage_ptr_t ) ->
void {}}
57 , relocate_ptr{[](storage_ptr_t , storage_ptr_t ) ->
void {}}
58 , destructor_ptr{[](storage_ptr_t ) ->
void {}}
63 explicit constexpr inplace_func_vtable(wrapper<C> )
64 : invoke_ptr{[](storage_ptr_t storagePtr, Args&&... args) -> R {
65 return (*
static_cast<C*>(storagePtr))(
static_cast<Args&&>(args)...);
67 , copy_ptr{[](storage_ptr_t dstPtr, storage_ptr_t srcPtr) ->
void {
68 ::
new (dstPtr) C{(*
static_cast<C*>(srcPtr))};
70 , relocate_ptr{[](storage_ptr_t dstPtr, storage_ptr_t srcPtr) ->
void {
71 ::
new (dstPtr) C{
etl::move(*
static_cast<C*>(srcPtr))};
72 static_cast<C*>(srcPtr)->~C();
74 , destructor_ptr{[](storage_ptr_t srcPtr) ->
void {
static_cast<C*>(srcPtr)->~C(); }}
78 inplace_func_vtable(inplace_func_vtable
const&) =
delete;
79 inplace_func_vtable(inplace_func_vtable&&) =
delete;
81 auto operator=(inplace_func_vtable
const&) -> inplace_func_vtable& =
delete;
82 auto operator=(inplace_func_vtable&&) -> inplace_func_vtable& =
delete;
84 ~inplace_func_vtable() =
default;
87template <
typename R,
typename... Args>
88inline constexpr auto empty_vtable = inplace_func_vtable<R, Args...>{};
90template <size_t DstCap, size_t DstAlign, size_t SrcCap, size_t SrcAlign>
91struct is_valid_inplace_destination :
etl::true_type {
92 static_assert(DstCap >= SrcCap);
93 static_assert(DstAlign % SrcAlign == 0);
98template <
typename Signature, size_t Capacity =
sizeof(
void*), size_t Alignment =
alignof(aligned_storage_t<Capacity>)>
103struct is_inplace_function : false_type { };
105template <
typename Sig, size_t Cap, size_t Align>
109template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
112 using storage_t = aligned_storage_t<Capacity, Alignment>;
113 using vtable_t = detail::inplace_func_vtable<R, Args...>;
114 using vtable_ptr_t = vtable_t
const*;
116 template <
typename, size_t, size_t>
125 : _vtable{
etl::addressof(detail::empty_vtable<R, Args...>)}
129 template <
typename T,
typename C = decay_t<T>>
130 requires(!detail::is_inplace_function<C>::value && is_invocable_r_v<R, C&, Args...>)
133 static_assert(is_copy_constructible_v<C>,
"inplace_function cannot be constructed from non-copyable type");
135 sizeof(C) <= Capacity,
136 "inplace_function cannot be constructed from object with this (large) size"
139 Alignment %
alignof(C) == 0,
140 "inplace_function cannot be constructed from object with this (large) alignment"
143 static constexpr vtable_t
const vt{detail::wrapper<C>{}};
144 _vtable =
etl::addressof(vt);
146 ::
new (
etl::addressof(_storage)) C{
etl::forward<T>(closure)};
149 template <size_t Cap, size_t Align>
154 detail::is_valid_inplace_destination<Capacity, Alignment, Cap, Align>::value,
155 "conversion not allowed"
159 template <size_t Cap, size_t Align>
161 :
inplace_function{other._vtable, other._vtable->relocate_ptr,
etl::addressof(other._storage)}
164 detail::is_valid_inplace_destination<Capacity, Alignment, Cap, Align>::value,
165 "conversion not allowed"
167 other._vtable =
etl::addressof(detail::empty_vtable<R, Args...>);
172 : _vtable{
etl::addressof(detail::empty_vtable<R, Args...>)}
177 : _vtable{other._vtable}
179 _vtable->copy_ptr(
etl::addressof(_storage),
etl::addressof(other._storage));
183 : _vtable{exchange(other._vtable,
etl::addressof(detail::empty_vtable<R, Args...>))}
185 _vtable->relocate_ptr(
etl::addressof(_storage),
etl::addressof(other._storage));
192 _vtable->destructor_ptr(
etl::addressof(_storage));
193 _vtable =
etl::addressof(detail::empty_vtable<R, Args...>);
199 _vtable->destructor_ptr(
etl::addressof(_storage));
200 _vtable = exchange(other._vtable,
etl::addressof(detail::empty_vtable<R, Args...>));
201 _vtable->relocate_ptr(
etl::addressof(_storage),
etl::addressof(other._storage));
209 _vtable->destructor_ptr(
etl::addressof(_storage));
215 return _vtable->invoke_ptr(
etl::addressof(_storage),
etl::forward<Args>(args)...);
221 return _vtable !=
etl::addressof(detail::empty_vtable<R, Args...>);
227 auto tmp = storage_t{};
228 _vtable->relocate_ptr(
etl::addressof(tmp),
etl::addressof(_storage));
229 other._vtable->relocate_ptr(
etl::addressof(_storage),
etl::addressof(other._storage));
230 _vtable->relocate_ptr(
etl::addressof(other._storage),
etl::addressof(tmp));
231 etl::swap(_vtable, other._vtable);
237 typename vtable_t::process_ptr_t process,
238 typename vtable_t::storage_ptr_t storage
242 process(
etl::addressof(_storage), storage);
245 vtable_ptr_t _vtable;
246 storage_t
mutable _storage;
252template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
264template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
265[[nodiscard]]
constexpr auto
268 return !
static_cast<
bool>(f);
274template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
275[[nodiscard]]
constexpr auto
278 return static_cast<
bool>(f);
284template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
285[[nodiscard]]
constexpr auto
288 return !
static_cast<
bool>(f);
294template <
typename R,
typename... Args, size_t Capacity, size_t Alignment>
295[[nodiscard]]
constexpr auto
298 return static_cast<
bool>(f);
Definition adjacent_find.hpp:9
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:266
constexpr auto operator==(nullptr_t, inplace_function< R(Args...), Capacity, Alignment > const &f) noexcept -> bool
Compares a etl::inplace_function with a null pointer. Empty functions (that is, functions without a c...
Definition inplace_function.hpp:286
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:276
TETL_NO_INLINE TETL_COLD auto raise(char const *msg, etl::source_location const loc=etl::source_location::current()) -> void
Definition raise.hpp:17
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:253
constexpr auto operator!=(nullptr_t, inplace_function< R(Args...), Capacity, Alignment > const &f) noexcept -> bool
Compares a etl::inplace_function with a null pointer. Empty functions (that is, functions without a c...
Definition inplace_function.hpp:296
Definition inplace_function.hpp:23
constexpr bad_function_call(char const *what)
Definition inplace_function.hpp:26
constexpr bad_function_call()=default
Definition exception.hpp:9
constexpr exception(char const *what)
Definition exception.hpp:12
auto operator()(Args... args) const -> R
Invokes the stored callable function target with the parameters args.
Definition inplace_function.hpp:213
inplace_function(inplace_function< R(Args...), Cap, Align > const &other)
Definition inplace_function.hpp:150
inplace_function(inplace_function &&other) noexcept
Definition inplace_function.hpp:182
inplace_function(inplace_function const &other)
Definition inplace_function.hpp:176
inplace_function(inplace_function< R(Args...), Cap, Align > &&other) noexcept
Definition inplace_function.hpp:160
inplace_function() noexcept
Creates an empty function.
Definition inplace_function.hpp:124
auto operator=(inplace_function other) noexcept -> inplace_function &
Definition inplace_function.hpp:197
constexpr operator bool() const noexcept
Checks whether *this stores a callable function target, i.e. is not empty.
Definition inplace_function.hpp:219
inplace_function(nullptr_t) noexcept
Creates an empty function.
Definition inplace_function.hpp:171
~inplace_function()
Destroys the etl::inplace_function instance. If the etl::inplace_function is not empty,...
Definition inplace_function.hpp:207
inplace_function(T &&closure)
Definition inplace_function.hpp:131
auto swap(inplace_function &other) noexcept -> void
Exchanges the stored callable objects of *this and other.
Definition inplace_function.hpp:225
friend struct inplace_function
Definition inplace_function.hpp:117
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:190
Definition integral_constant.hpp:10