22 template<
typename Prototype,
unsigned int reserved_space = 4*sizeof(
void *)>
24 template<
typename Prototype,
bool nx,
unsigned int reserved_space = 4*sizeof(
void *)>
28 template<
typename T,
typename RetVal,
bool nx,
typename ... Args>
29 concept IsFunctionConstructible = (nx?std::is_nothrow_invocable_r_v<RetVal,T, Args...>:std::is_invocable_r_v<RetVal, T, Args...>);
32 template<
typename T,
typename ToObj>
33 concept hasnt_cast_operator = !requires(T t) {
40 template<
typename RetVal,
bool nx,
typename ... Args,
unsigned int reserved_space>
41 class function_impl<RetVal(Args...), nx, reserved_space> {
58 virtual ~Abstract() =
default;
60 virtual RetVal call(Args && ... args) = 0;
67 virtual void move(
void *address) = 0;
73 virtual bool valid()
const = 0;
78 class WrapFnSmall:
public Abstract {
80 template<std::convertible_to<Fn> Fun>
81 WrapFnSmall(Fun &&fn):_fn(std::forward<Fun>(fn)) {}
83 virtual RetVal call(Args && ... args)
override {
84 return _fn(std::forward<Args>(args)...);
86 virtual void move(
void *address)
override {
88 new(address) WrapFnSmall(std::move(*
this));
90 virtual bool valid()
const override {
return true;}
99 class WrapFnLarge:
public Abstract {
101 template<std::convertible_to<Fn> Fun>
102 WrapFnLarge(Fun &&fn):_fn(std::make_unique<Fn>(std::forward<Fun>(fn))) {}
104 virtual RetVal call(Args && ... args)
override {
105 return (*_fn)(std::forward<Args>(args)...);
107 virtual void move(
void *address)
override {
109 new(address) WrapFnLarge(std::move(*
this));
111 virtual bool valid()
const override {
return true;}
115 std::unique_ptr<Fn> _fn;
118 template<
typename Fn>
119 class WrapFnPlacement:
public Abstract {
122 void operator()(Fn *fn){std::destroy_at(fn);};
125 template<std::convertible_to<Fn> Fun>
126 WrapFnPlacement(Fun &&fn,
void *ptr):_fn(new(ptr) Fn(std::forward<Fun>(fn))) {}
128 virtual RetVal call(Args && ... args)
override {
129 return (*_fn)(std::forward<Args>(args)...);
131 virtual void move(
void *address)
override {
133 new(address) WrapFnPlacement(std::move(*
this));
135 virtual bool valid()
const override {
return true;}
139 std::unique_ptr<Fn, Deleter> _fn;
144 class InvalidFn:
public Abstract {
146 virtual RetVal call(Args &&... )
override {
147 throw std::bad_function_call();
149 virtual void move(
void *address)
override {
150 new(address) InvalidFn(std::move(*
this));
152 virtual bool valid()
const override {
return false;}
156 struct TestCallable {
157 RetVal operator()(Args ...) noexcept(nx);
162 static_assert(IsFunctionConstructible<TestCallable, RetVal, nx, Args ...>);
164 static_assert(
sizeof(WrapFnLarge<TestCallable>) <= reserved_space,
"Reserved space is too small");
169 new(_reserved) InvalidFn();
175 template<IsFunctionConstructible<RetVal, nx, Args...> Fn>
176 function_impl(Fn &&fn) {
177 using Small = WrapFnSmall<std::decay_t<Fn> >;
178 using Large = WrapFnLarge<std::decay_t<Fn> >;
179 if constexpr(
sizeof(Small) <= reserved_space) {
181 new(_reserved) Small(std::forward<Fn>(fn));
184 new(_reserved) Large(std::forward<Fn>(fn));
196 template<IsFunctionConstructible<RetVal, nx, Args...> Fn>
197 function_impl(
void *ptr, Fn &&fn) {
198 new(_reserved) WrapFnPlacement<std::decay_t<Fn> >(std::forward<Fn>(fn), ptr);
209 function_impl(function_impl &&other) {
211 other.ref().move(_reserved);
227 function_impl &operator=(function_impl &&other) {
228 if (
this != &other) {
231 other.ref().move(_reserved);
241 function_impl &operator=(std::nullptr_t) {
244 new(_reserved) InvalidFn();
250 RetVal operator()(Args ... args) noexcept(nx) {
251 return ref().call(std::forward<Args>(args)...);
259 explicit operator bool()
const {
260 return ref().valid();
263 static constexpr
bool is_noexcept = nx;
264 using value_type = RetVal;
269 char _reserved[reserved_space];
272 Abstract &ref() {
return *
reinterpret_cast<Abstract *
>(_reserved);}
274 const Abstract &ref()
const {
return *
reinterpret_cast<const Abstract *
>(_reserved);}
284 template<
typename RetVal,
typename ... Args,
unsigned int reserved_space>
285 class function<RetVal(Args...) noexcept(false), reserved_space>:
public function_impl<RetVal(Args...), false, reserved_space> {
287 using function_impl<RetVal(Args...),
false, reserved_space>::function_impl;
290 template<
typename RetVal,
typename ... Args,
unsigned int reserved_space>
291 class function<RetVal(Args...) noexcept(true), reserved_space>:
public function_impl<RetVal(Args...), true, reserved_space> {
293 using function_impl<RetVal(Args...),
true, reserved_space>::function_impl;
305 template<
unsigned int reserved_space = 4*sizeof(
void *)>
324 template<hasnt_cast_operator<any> Arg>
325 any(Arg &&arg):_storage([v = Arg(std::forward<Arg>(arg))]()mutable ->
content{
336 return {typeid(nullptr),nullptr,0};
367 auto ctx = get_info();
368 if (ctx.type !=
typeid(T))
return nullptr;
369 return reinterpret_cast<const T *
>(ctx.ptr);
381 auto ctx = get_info();
382 if (ctx.type !=
typeid(T))
return nullptr;
383 return reinterpret_cast<T *
>(ctx.ptr);
395 auto ptr = get_ptr<T>();
396 if (ptr ==
nullptr)
throw std::bad_cast();
408 auto ptr = get_ptr<T>();
409 if (ptr ==
nullptr)
throw std::bad_cast();
420 return get_info().ptr ==
nullptr;
428 operator bool() const noexcept {
429 return get_info().ptr !=
nullptr;
440 return get_info().type ==
typeid(T);
444 mutable function<content()> _storage;
bool contains() const noexcept
Tests whether object contains given type.
content get_info()
Retrieve information about the content.
const content get_info() const
Retrieve information about the content.
any(Arg &&arg)
Construct any instance.
const T * get_ptr() const noexcept
Get as pointer.
const T & get() const
Get as reference.
T & get()
Get as reference.
T * get_ptr() noexcept
Get as pointer.
bool empty() const noexcept
Determines whether object is empty.
Movable any replacement with small object optimization - uses coro::function.
Move only function wrapper with small object optimization.
std::size_t size
size in bytes
void * ptr
pointer to memory, where content is located.
const std::type_info & type
reference to type information
Contains information about stored content.