5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_FUNCTION_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_FUNCTION_HPP_
11#include "arene/base/array/array.hpp"
12#include "arene/base/byte/byte.hpp"
13#include "arene/base/constraints/constraints.hpp"
14#include "arene/base/contracts/contract.hpp"
15#include "arene/base/memory/construct_at.hpp"
16#include "arene/base/stdlib_choice/cstddef.hpp"
17#include "arene/base/stdlib_choice/decay.hpp"
18#include "arene/base/stdlib_choice/enable_if.hpp"
19#include "arene/base/stdlib_choice/forward.hpp"
20#include "arene/base/stdlib_choice/is_base_of.hpp"
21#include "arene/base/stdlib_choice/is_move_constructible.hpp"
22#include "arene/base/stdlib_choice/is_same.hpp"
23#include "arene/base/stdlib_choice/move.hpp"
24#include "arene/base/type_traits/conditional.hpp"
25#include "arene/base/type_traits/is_invocable.hpp"
48template <
typename Signature, std::size_t BufferSize = default_inline_function_size,
bool IsNoexcept =
false>
58template <
typename Signature, std::size_t BufferSize = default_inline_function_size>
59using noexcept_inline_function = inline_function<Signature, BufferSize,
true>;
61namespace inline_function_detail {
70template <std::size_t BufferSize,
bool IsConst,
bool IsNoexcept,
typename ReturnType,
typename... Args>
71class inline_function_base {
73 using invoke_self_type = conditional_t<IsConst, inline_function_base
const&, inline_function_base&>;
76 using invoke_func_type = ReturnType(invoke_self_type self, Args&&... args);
81 struct operation_functions {
84 void (*
const destroy)(inline_function_base& self)
noexcept;
88 void (*
const move)(inline_function_base& target, inline_function_base& source)
noexcept;
92 invoke_func_type*
const invoke;
99 static void do_destroy(inline_function_base& self)
noexcept {
101 T& wrapped_invocable{*self.
template get_ptr<T>()};
103 wrapped_invocable.~T();
104 self.operations_ =
nullptr;
112 template <
typename T>
113 static void do_move(inline_function_base& target, inline_function_base& source)
noexcept {
114 target.construct_from(std::move(*source.
template get_ptr<T>()));
115 target.operations_ = source.operations_;
116 do_destroy<T>(source);
125 template <
typename T>
126 static auto do_invoke(invoke_self_type self, Args&&... args) -> ReturnType {
127 auto& wrapped_invocable = *self.
template get_ptr<T>();
129 return static_cast<ReturnType>(wrapped_invocable(std::forward<Args>(args)...));
135 template <
typename T>
136 static constexpr operation_functions call_table{&do_destroy<T>, &do_move<T>, &do_invoke<T>};
143 template <
typename T>
144 static constexpr bool
145 is_invocable_n_r_v{IsNoexcept ? ::arene::base::is_nothrow_invocable_r_v<ReturnType, T, Args...> : ::arene::base::is_invocable_r_v<ReturnType, T, Args...>};
149 inline_function_base()
noexcept
151 operations_{
nullptr} {}
154 inline_function_base(inline_function_base
const&) =
delete;
156 auto operator=(inline_function_base
const&) -> inline_function_base& =
delete;
168 std::enable_if_t<(
sizeof(std::decay_t<T>) <= BufferSize)>,
169 std::enable_if_t<std::is_nothrow_move_constructible<std::decay_t<T>>::value>,
170 std::enable_if_t<is_invocable_n_r_v<conditional_t<IsConst, std::decay_t<T>
const, std::decay_t<T>>>>> =
173 inline_function_base(T&& invocable)
noexcept
175 operations_(&call_table<std::decay_t<T>>) {
176 construct_from(std::forward<T>(invocable));
185 typename InvocableTooBigForBuffer,
187 std::enable_if_t<(
sizeof(std::decay_t<InvocableTooBigForBuffer>) > BufferSize)>,
188 std::enable_if_t<!std::is_base_of<inline_function_base, std::decay_t<InvocableTooBigForBuffer>>::value>> =
191 inline_function_base(InvocableTooBigForBuffer&& buffer_too_small) =
delete;
203 std::enable_if_t<(
sizeof(std::decay_t<T>) <= BufferSize)>,
204 std::enable_if_t<std::is_nothrow_move_constructible<std::decay_t<T>>::value>,
205 std::enable_if_t<is_invocable_n_r_v<conditional_t<IsConst, std::decay_t<T>
const, std::decay_t<T>>>>> =
207 void assign_from(T&& invocable)
noexcept {
209 operations_ = &call_table<std::decay_t<T>>;
210 construct_from(std::forward<T>(invocable));
223 std::enable_if_t<(
sizeof(std::decay_t<T>) <= BufferSize)>,
224 std::enable_if_t<std::is_nothrow_move_constructible<std::decay_t<T>>::value>,
225 std::enable_if_t<is_invocable_n_r_v<conditional_t<IsConst, std::decay_t<T>
const, std::decay_t<T>>>>> =
227 void construct_from(T&& invocable)
noexcept {
228 construct_at(get_ptr<std::decay_t<T>>(), std::forward<T>(invocable));
232 ~inline_function_base() { destroy(); }
236 auto is_initialized()
const noexcept ->
bool {
return operations_ !=
nullptr; }
240 auto get_invoke()
const noexcept -> invoke_func_type* {
241 ARENE_PRECONDITION(is_initialized());
242 return operations_->invoke;
248 explicit operator
bool()
const noexcept {
return is_initialized(); }
257 inline_function_base(inline_function_base&& other)
noexcept
258 : inline_function_base{} {
272 auto operator=(inline_function_base&& other)
noexcept -> inline_function_base& {
273 if (&other !=
this) {
285 void destroy()
noexcept {
286 if (is_initialized()) {
287 operations_->destroy(*
this);
293 void move_from(inline_function_base& other) {
294 if (other.is_initialized()) {
295 other.operations_->move(*
this, other);
303 template <
typename T>
304 auto get_ptr()
noexcept -> T* {
305 return static_cast<T*>(
static_cast<
void*>(buffer_.data()));
311 template <
typename T>
312 auto get_ptr()
const noexcept -> T
const* {
313 return static_cast<T
const*>(
static_cast<
void const*>(buffer_.data()));
317 alignas(std::max_align_t) array<byte, BufferSize> buffer_;
320 operation_functions
const* operations_;
329template <std::size_t BufferSize,
bool IsConst,
bool IsNoexcept,
typename ReturnType,
typename... Args>
331constexpr typename inline_function_base<BufferSize, IsConst, IsNoexcept, ReturnType, Args...>::operation_functions
332 inline_function_base<BufferSize, IsConst, IsNoexcept, ReturnType, Args...>::call_table;
344template <
typename ReturnType,
typename... Args, std::size_t BufferSize,
bool IsNoexcept>
345class inline_function<ReturnType(Args...), BufferSize, IsNoexcept>
346 : inline_function_detail::inline_function_base<BufferSize,
false, IsNoexcept, ReturnType, Args...> {
348 using base_class = inline_function_detail::inline_function_base<BufferSize,
false, IsNoexcept, ReturnType, Args...>;
352 using base_class::base_class;
366 auto operator=(inline_function&& other)
noexcept -> inline_function& =
default;
379 std::enable_if_t<(
sizeof(std::decay_t<T>) <= BufferSize)>,
380 std::enable_if_t<std::is_nothrow_move_constructible<std::decay_t<T>>::value>,
381 std::enable_if_t<base_class::
template is_invocable_n_r_v<std::decay_t<T>>>> =
nullptr>
382 auto operator=(T&& invocable)
noexcept -> inline_function& {
383 this->assign_from(std::forward<T>(invocable));
393 typename InvocableTooBigForBuffer,
395 std::enable_if_t<(
sizeof(std::decay_t<InvocableTooBigForBuffer>) > BufferSize)>,
396 std::enable_if_t<!std::is_same<inline_function, std::decay_t<InvocableTooBigForBuffer>>::value>> =
nullptr>
397 auto operator=(InvocableTooBigForBuffer&& buffer_too_small) -> inline_function& =
delete;
402 auto operator=(inline_function
const&) -> inline_function& =
delete;
408 using base_class::operator
bool;
415 ARENE_PRECONDITION(
this->is_initialized());
417 return this->get_invoke()(*
this, std::forward<Args>(args)...);
430template <
typename ReturnType,
typename... Args, std::size_t BufferSize,
bool IsNoexcept>
431class inline_function<ReturnType(Args...)
const, BufferSize, IsNoexcept>
432 : inline_function_detail::inline_function_base<BufferSize,
true, IsNoexcept, ReturnType, Args...> {
434 using base_class = inline_function_detail::inline_function_base<BufferSize,
true, IsNoexcept, ReturnType, Args...>;
438 using base_class::base_class;
452 auto operator=(inline_function&& other)
noexcept -> inline_function& =
default;
465 std::enable_if_t<(
sizeof(std::decay_t<T>) <= BufferSize)>,
466 std::enable_if_t<std::is_nothrow_move_constructible<std::decay_t<T>>::value>,
467 std::enable_if_t<base_class::
template is_invocable_n_r_v<std::decay_t<T>
const>>> =
nullptr>
468 auto operator=(T&& invocable)
noexcept -> inline_function& {
469 this->assign_from(std::forward<T>(invocable));
479 typename InvocableTooBigForBuffer,
481 std::enable_if_t<(
sizeof(std::decay_t<InvocableTooBigForBuffer>) > BufferSize)>,
482 std::enable_if_t<!std::is_same<inline_function, std::decay_t<InvocableTooBigForBuffer>>::value>> =
nullptr>
483 auto operator=(InvocableTooBigForBuffer&& buffer_too_small) -> inline_function& =
delete;
488 auto operator=(inline_function
const&) -> inline_function& =
delete;
494 using base_class::operator
bool;
501 ARENE_PRECONDITION(
this->is_initialized());
502 return this->get_invoke()(*
this, std::forward<Args>(args)...);
~inline_function()=default
Destroy the wrapped invocable.
auto operator=(inline_function const &) -> inline_function &=delete
Not copyable.
inline_function() noexcept=default
Default construct with no stored invocable.
auto operator=(inline_function &&other) noexcept -> inline_function &=default
Transfer ownership of an invocable from another object. Leaves the source without an invocable.
auto operator()(Args... args) noexcept(IsNoexcept) -> ReturnType
Invoke the wrapped invocable as a non-const object, with the supplied arguments.
Definition function.hpp:414
inline_function(inline_function const &)=delete
Not copyable.
inline_function(inline_function &&other) noexcept=default
Transfer ownership of an invocable from another object. Leaves the source without an invocable.
auto operator()(Args... args) const noexcept(IsNoexcept) -> ReturnType
Invoke the wrapped invocable as a const object, with the supplied arguments.
Definition function.hpp:500
Definition array_exceptions_disabled.cpp:11
static constexpr std::size_t default_inline_function_size
The default size of the buffer used for inline_function .
Definition function.hpp:37
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10