mirror of
https://github.com/BlackMATov/meta.hpp.git
synced 2025-12-14 19:41:29 +07:00
fixed_function instead std::function
This commit is contained in:
@@ -35,6 +35,7 @@
|
|||||||
#include "meta_base/cvref_traits.hpp"
|
#include "meta_base/cvref_traits.hpp"
|
||||||
#include "meta_base/enum_bitflags.hpp"
|
#include "meta_base/enum_bitflags.hpp"
|
||||||
#include "meta_base/enum.hpp"
|
#include "meta_base/enum.hpp"
|
||||||
|
#include "meta_base/fixed_function.hpp"
|
||||||
#include "meta_base/noncopyable.hpp"
|
#include "meta_base/noncopyable.hpp"
|
||||||
#include "meta_base/overloaded.hpp"
|
#include "meta_base/overloaded.hpp"
|
||||||
#include "meta_base/select_overload.hpp"
|
#include "meta_base/select_overload.hpp"
|
||||||
|
|||||||
203
headers/meta.hpp/meta_base/fixed_function.hpp
Normal file
203
headers/meta.hpp/meta_base/fixed_function.hpp
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||||
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||||
|
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
|
template < typename Function, std::size_t MaxFunctorSize = sizeof(void*) * 3 >
|
||||||
|
class fixed_function;
|
||||||
|
|
||||||
|
template < typename R, typename... Args, std::size_t MaxFunctorSize >
|
||||||
|
class fixed_function<R(Args...), MaxFunctorSize> final {
|
||||||
|
public:
|
||||||
|
fixed_function() = default;
|
||||||
|
~fixed_function() { reset(); }
|
||||||
|
|
||||||
|
fixed_function(const fixed_function& other) = delete;
|
||||||
|
fixed_function& operator=(const fixed_function& other) = delete;
|
||||||
|
|
||||||
|
fixed_function(fixed_function&& other) noexcept {
|
||||||
|
if ( other.vtable_ ) {
|
||||||
|
other.vtable_->move(other, *this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed_function& operator=(fixed_function&& other) noexcept {
|
||||||
|
if ( this != &other ) {
|
||||||
|
fixed_function{std::move(other)}.swap(*this);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Functor >
|
||||||
|
fixed_function(Functor&& functor) {
|
||||||
|
vtable_t::construct(*this, std::forward<Functor>(functor));
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Functor >
|
||||||
|
fixed_function& operator=(Functor&& functor) {
|
||||||
|
fixed_function{std::forward<Functor>(functor)}.swap(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_valid() const noexcept {
|
||||||
|
return !!vtable_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] explicit operator bool() const noexcept {
|
||||||
|
return is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
R operator()(Args... args) const {
|
||||||
|
return vtable_
|
||||||
|
? vtable_->call(*this, std::forward<Args>(args)...)
|
||||||
|
: throw std::bad_function_call();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() noexcept {
|
||||||
|
if ( vtable_ ) {
|
||||||
|
vtable_->destroy(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(fixed_function& other) noexcept {
|
||||||
|
vtable_t::swap(*this, other);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
struct vtable_t;
|
||||||
|
vtable_t* vtable_{};
|
||||||
|
private:
|
||||||
|
using storage_t = std::aligned_storage_t<MaxFunctorSize, alignof(void*)>;
|
||||||
|
storage_t storage_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename Function, std::size_t MaxFunctorSize >
|
||||||
|
inline void swap(fixed_function<Function, MaxFunctorSize>& l, fixed_function<Function, MaxFunctorSize>& r) noexcept {
|
||||||
|
l.swap(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
|
template < typename R, typename... Args, std::size_t MaxFunctorSize >
|
||||||
|
struct fixed_function<R(Args...), MaxFunctorSize>::vtable_t final {
|
||||||
|
R (*const call)(const fixed_function& self, Args... args);
|
||||||
|
void (*const move)(fixed_function& from, fixed_function& to) noexcept;
|
||||||
|
void (*const destroy)(fixed_function& self);
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
static T* storage_cast(storage_t& storage) noexcept {
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
return reinterpret_cast<T*>(&storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
static const T* storage_cast(const storage_t& storage) noexcept {
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
|
return reinterpret_cast<const T*>(&storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename FunctionType >
|
||||||
|
static vtable_t* get() {
|
||||||
|
static vtable_t table{
|
||||||
|
.call = +[](const fixed_function& self, Args... args) -> R {
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
const FunctionType& src = *storage_cast<FunctionType>(self.storage_);
|
||||||
|
return std::invoke(src, std::forward<Args>(args)...);
|
||||||
|
},
|
||||||
|
.move = +[](fixed_function& from, fixed_function& to) noexcept {
|
||||||
|
assert(from && !to);
|
||||||
|
|
||||||
|
FunctionType& src = *storage_cast<FunctionType>(from.storage_);
|
||||||
|
::new (&to.storage_) FunctionType(std::move(src));
|
||||||
|
|
||||||
|
to.vtable_ = from.vtable_;
|
||||||
|
from.vtable_->destroy(from);
|
||||||
|
},
|
||||||
|
.destroy = +[](fixed_function& self){
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
FunctionType& src = *storage_cast<FunctionType>(self.storage_);
|
||||||
|
src.~FunctionType();
|
||||||
|
|
||||||
|
self.vtable_ = nullptr;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return &table;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Functor >
|
||||||
|
static void construct(fixed_function& dst, Functor&& functor) {
|
||||||
|
using Fp = std::decay_t<Functor>;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
sizeof(Fp) <= MaxFunctorSize &&
|
||||||
|
alignof(Fp) <= alignof(storage_t) &&
|
||||||
|
std::is_invocable_r_v<R, Fp, Args...> &&
|
||||||
|
std::is_nothrow_move_constructible_v<Fp>);
|
||||||
|
|
||||||
|
::new (&dst.storage_) Fp(std::forward<Functor>(functor));
|
||||||
|
dst.vtable_ = vtable_t::get<Fp>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swap(fixed_function& l, fixed_function& r) noexcept {
|
||||||
|
if ( (&l == &r) || (!l && !r) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( l && r ) {
|
||||||
|
fixed_function temp;
|
||||||
|
r.vtable_->move(r, temp);
|
||||||
|
l.vtable_->move(l, r);
|
||||||
|
temp.vtable_->move(temp, l);
|
||||||
|
} else {
|
||||||
|
if ( l ) {
|
||||||
|
l.vtable_->move(l, r);
|
||||||
|
} else {
|
||||||
|
r.vtable_->move(r, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace meta_hpp::detail
|
||||||
|
{
|
||||||
|
namespace impl
|
||||||
|
{
|
||||||
|
template < typename F >
|
||||||
|
struct strip_signature_impl;
|
||||||
|
|
||||||
|
template < typename R, typename C, bool NoExcept, typename... Args >
|
||||||
|
struct strip_signature_impl<R(C::*)(Args...) noexcept(NoExcept)> { using type = R(Args...); };
|
||||||
|
|
||||||
|
template < typename R, typename C, bool NoExcept, typename... Args >
|
||||||
|
struct strip_signature_impl<R(C::*)(Args...) const noexcept(NoExcept)> { using type = R(Args...); };
|
||||||
|
|
||||||
|
template < typename R, typename C, bool NoExcept, typename... Args >
|
||||||
|
struct strip_signature_impl<R(C::*)(Args...) & noexcept(NoExcept)> { using type = R(Args...); };
|
||||||
|
|
||||||
|
template < typename R, typename C, bool NoExcept, typename... Args >
|
||||||
|
struct strip_signature_impl<R(C::*)(Args...) const & noexcept(NoExcept)> { using type = R(Args...); };
|
||||||
|
|
||||||
|
template < typename F >
|
||||||
|
using strip_signature_impl_t = typename strip_signature_impl<F>::type;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename R, typename... Args >
|
||||||
|
fixed_function(R(*)(Args...)) -> fixed_function<R(Args...)>;
|
||||||
|
|
||||||
|
template < typename Functor
|
||||||
|
, typename Signature = impl::strip_signature_impl_t<decltype(&Functor::operator())> >
|
||||||
|
fixed_function(Functor) -> fixed_function<Signature>;
|
||||||
|
}
|
||||||
@@ -367,81 +367,81 @@ namespace meta_hpp
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
struct ctor_state final {
|
struct ctor_state final {
|
||||||
using invoke_impl = std::function<value(std::span<const arg>)>;
|
using invoke_impl = fixed_function<value(std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
|
using is_invocable_with_impl = fixed_function<bool(std::span<const arg_base>)>;
|
||||||
|
|
||||||
const ctor_index index;
|
ctor_index index;
|
||||||
const invoke_impl invoke;
|
invoke_impl invoke;
|
||||||
const is_invocable_with_impl is_invocable_with;
|
is_invocable_with_impl is_invocable_with;
|
||||||
|
|
||||||
template < ctor_policy_kind Policy, class_kind Class, typename... Args >
|
template < ctor_policy_kind Policy, class_kind Class, typename... Args >
|
||||||
[[nodiscard]] static ctor_state_ptr make();
|
[[nodiscard]] static ctor_state_ptr make();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dtor_state final {
|
struct dtor_state final {
|
||||||
using invoke_impl = std::function<void(const arg&)>;
|
using invoke_impl = fixed_function<void(const arg&)>;
|
||||||
using is_invocable_with_impl = std::function<bool(const arg_base&)>;
|
using is_invocable_with_impl = fixed_function<bool(const arg_base&)>;
|
||||||
|
|
||||||
const dtor_index index;
|
dtor_index index;
|
||||||
const invoke_impl invoke;
|
invoke_impl invoke;
|
||||||
const is_invocable_with_impl is_invocable_with;
|
is_invocable_with_impl is_invocable_with;
|
||||||
|
|
||||||
template < class_kind Class >
|
template < class_kind Class >
|
||||||
[[nodiscard]] static dtor_state_ptr make();
|
[[nodiscard]] static dtor_state_ptr make();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct evalue_state final {
|
struct evalue_state final {
|
||||||
const evalue_index index;
|
evalue_index index;
|
||||||
const value enum_value;
|
value enum_value;
|
||||||
const value underlying_value;
|
value underlying_value;
|
||||||
|
|
||||||
template < enum_kind Enum >
|
template < enum_kind Enum >
|
||||||
[[nodiscard]] static evalue_state_ptr make(std::string name, Enum evalue);
|
[[nodiscard]] static evalue_state_ptr make(std::string name, Enum evalue);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct function_state final {
|
struct function_state final {
|
||||||
using invoke_impl = std::function<value(std::span<const arg>)>;
|
using invoke_impl = fixed_function<value(std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(std::span<const arg_base>)>;
|
using is_invocable_with_impl = fixed_function<bool(std::span<const arg_base>)>;
|
||||||
|
|
||||||
const function_index index;
|
function_index index;
|
||||||
const invoke_impl invoke;
|
invoke_impl invoke;
|
||||||
const is_invocable_with_impl is_invocable_with;
|
is_invocable_with_impl is_invocable_with;
|
||||||
|
|
||||||
template < function_policy_kind Policy, function_kind Function >
|
template < function_policy_kind Policy, function_kind Function >
|
||||||
[[nodiscard]] static function_state_ptr make(std::string name, Function function);
|
[[nodiscard]] static function_state_ptr make(std::string name, Function function);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct member_state final {
|
struct member_state final {
|
||||||
using getter_impl = std::function<value(const inst&)>;
|
using getter_impl = fixed_function<value(const inst&)>;
|
||||||
using setter_impl = std::function<void(const inst&, const arg&)>;
|
using setter_impl = fixed_function<void(const inst&, const arg&)>;
|
||||||
|
|
||||||
using is_gettable_with_impl = std::function<bool(const inst_base&)>;
|
using is_gettable_with_impl = fixed_function<bool(const inst_base&)>;
|
||||||
using is_settable_with_impl = std::function<bool(const inst_base&, const arg_base&)>;
|
using is_settable_with_impl = fixed_function<bool(const inst_base&, const arg_base&)>;
|
||||||
|
|
||||||
const member_index index;
|
member_index index;
|
||||||
const getter_impl getter;
|
getter_impl getter;
|
||||||
const setter_impl setter;
|
setter_impl setter;
|
||||||
const is_gettable_with_impl is_gettable_with;
|
is_gettable_with_impl is_gettable_with;
|
||||||
const is_settable_with_impl is_settable_with;
|
is_settable_with_impl is_settable_with;
|
||||||
|
|
||||||
template < member_policy_kind Policy, member_kind Member >
|
template < member_policy_kind Policy, member_kind Member >
|
||||||
[[nodiscard]] static member_state_ptr make(std::string name, Member member);
|
[[nodiscard]] static member_state_ptr make(std::string name, Member member);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct method_state final {
|
struct method_state final {
|
||||||
using invoke_impl = std::function<value(const inst&, std::span<const arg>)>;
|
using invoke_impl = fixed_function<value(const inst&, std::span<const arg>)>;
|
||||||
using is_invocable_with_impl = std::function<bool(const inst_base&, std::span<const arg_base>)>;
|
using is_invocable_with_impl = fixed_function<bool(const inst_base&, std::span<const arg_base>)>;
|
||||||
|
|
||||||
const method_index index;
|
method_index index;
|
||||||
const invoke_impl invoke;
|
invoke_impl invoke;
|
||||||
const is_invocable_with_impl is_invocable_with;
|
is_invocable_with_impl is_invocable_with;
|
||||||
|
|
||||||
template < method_policy_kind Policy, method_kind Method >
|
template < method_policy_kind Policy, method_kind Method >
|
||||||
[[nodiscard]] static method_state_ptr make(std::string name, Method method);
|
[[nodiscard]] static method_state_ptr make(std::string name, Method method);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct scope_state final {
|
struct scope_state final {
|
||||||
const scope_index index;
|
scope_index index;
|
||||||
|
|
||||||
class_map classes{};
|
class_map classes{};
|
||||||
enum_map enums{};
|
enum_map enums{};
|
||||||
@@ -452,14 +452,14 @@ namespace meta_hpp::detail
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct variable_state final {
|
struct variable_state final {
|
||||||
using getter_impl = std::function<value()>;
|
using getter_impl = fixed_function<value()>;
|
||||||
using setter_impl = std::function<void(const arg&)>;
|
using setter_impl = fixed_function<void(const arg&)>;
|
||||||
using is_settable_with_impl = std::function<bool(const arg_base&)>;
|
using is_settable_with_impl = fixed_function<bool(const arg_base&)>;
|
||||||
|
|
||||||
const variable_index index;
|
variable_index index;
|
||||||
const getter_impl getter;
|
getter_impl getter;
|
||||||
const setter_impl setter;
|
setter_impl setter;
|
||||||
const is_settable_with_impl is_settable_with;
|
is_settable_with_impl is_settable_with;
|
||||||
|
|
||||||
template < variable_policy_kind Policy, pointer_kind Pointer >
|
template < variable_policy_kind Policy, pointer_kind Pointer >
|
||||||
[[nodiscard]] static variable_state_ptr make(std::string name, Pointer pointer);
|
[[nodiscard]] static variable_state_ptr make(std::string name, Pointer pointer);
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
namespace meta_hpp::detail
|
namespace meta_hpp::detail
|
||||||
{
|
{
|
||||||
template < typename T >
|
template < typename T >
|
||||||
concept value_kind = stdex::same_as<T, value>;
|
inline constexpr bool is_value_kind_v = std::is_same_v<T, value>;
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
concept value_kind = is_value_kind_v<T>;
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
concept decay_value_kind = value_kind<std::decay_t<T>>;
|
concept decay_value_kind = value_kind<std::decay_t<T>>;
|
||||||
@@ -26,7 +29,7 @@ namespace meta_hpp
|
|||||||
class value final {
|
class value final {
|
||||||
public:
|
public:
|
||||||
value() = default;
|
value() = default;
|
||||||
~value() noexcept;
|
~value();
|
||||||
|
|
||||||
value(value&& other) noexcept;
|
value(value&& other) noexcept;
|
||||||
value(const value& other);
|
value(const value& other);
|
||||||
@@ -45,7 +48,7 @@ namespace meta_hpp
|
|||||||
[[nodiscard]] bool is_valid() const noexcept;
|
[[nodiscard]] bool is_valid() const noexcept;
|
||||||
[[nodiscard]] explicit operator bool() const noexcept;
|
[[nodiscard]] explicit operator bool() const noexcept;
|
||||||
|
|
||||||
void reset() noexcept;
|
void reset();
|
||||||
void swap(value& other) noexcept;
|
void swap(value& other) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] const any_type& get_type() const noexcept;
|
[[nodiscard]] const any_type& get_type() const noexcept;
|
||||||
|
|||||||
@@ -40,13 +40,13 @@ namespace meta_hpp
|
|||||||
std::ostream& (*const ostream)(std::ostream&, const value&);
|
std::ostream& (*const ostream)(std::ostream&, const value&);
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
static T* storage_cast(buffer_t& buffer) noexcept {
|
static T* buffer_cast(buffer_t& buffer) noexcept {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
return reinterpret_cast<T*>(&buffer);
|
return reinterpret_cast<T*>(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
static const T* storage_cast(const buffer_t& buffer) noexcept {
|
static const T* buffer_cast(const buffer_t& buffer) noexcept {
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
return reinterpret_cast<const T*>(&buffer);
|
return reinterpret_cast<const T*>(&buffer);
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ namespace meta_hpp
|
|||||||
static T* storage_cast(storage_u& storage) noexcept {
|
static T* storage_cast(storage_u& storage) noexcept {
|
||||||
return std::visit(detail::overloaded {
|
return std::visit(detail::overloaded {
|
||||||
[](void* ptr) { return static_cast<T*>(ptr); },
|
[](void* ptr) { return static_cast<T*>(ptr); },
|
||||||
[](buffer_t& buffer) { return storage_cast<T>(buffer); },
|
[](buffer_t& buffer) { return buffer_cast<T>(buffer); },
|
||||||
[](...) -> T* { return nullptr; },
|
[](...) -> T* { return nullptr; },
|
||||||
}, storage);
|
}, storage);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ namespace meta_hpp
|
|||||||
static const T* storage_cast(const storage_u& storage) noexcept {
|
static const T* storage_cast(const storage_u& storage) noexcept {
|
||||||
return std::visit(detail::overloaded {
|
return std::visit(detail::overloaded {
|
||||||
[](const void* ptr) { return static_cast<const T*>(ptr); },
|
[](const void* ptr) { return static_cast<const T*>(ptr); },
|
||||||
[](const buffer_t& buffer) { return storage_cast<T>(buffer); },
|
[](const buffer_t& buffer) { return buffer_cast<T>(buffer); },
|
||||||
[](...) -> const T* { return nullptr; },
|
[](...) -> const T* { return nullptr; },
|
||||||
}, storage);
|
}, storage);
|
||||||
}
|
}
|
||||||
@@ -115,6 +115,7 @@ namespace meta_hpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template < typename Tp >
|
template < typename Tp >
|
||||||
|
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||||
static vtable_t* get() {
|
static vtable_t* get() {
|
||||||
static vtable_t table{
|
static vtable_t table{
|
||||||
.type = detail::resolve_type<Tp>(),
|
.type = detail::resolve_type<Tp>(),
|
||||||
@@ -128,15 +129,17 @@ namespace meta_hpp
|
|||||||
},
|
},
|
||||||
|
|
||||||
.move = [](value& from, value& to) noexcept {
|
.move = [](value& from, value& to) noexcept {
|
||||||
|
assert(from && !to);
|
||||||
|
|
||||||
std::visit(detail::overloaded {
|
std::visit(detail::overloaded {
|
||||||
[&to](void* ptr) {
|
[&to](void* ptr) {
|
||||||
Tp* src = static_cast<Tp*>(ptr);
|
Tp* src = static_cast<Tp*>(ptr);
|
||||||
to.storage_.emplace<void*>(src);
|
to.storage_.emplace<void*>(src);
|
||||||
},
|
},
|
||||||
[&to](buffer_t& buffer) {
|
[&to](buffer_t& buffer) {
|
||||||
Tp* src = storage_cast<Tp>(buffer);
|
Tp& src = *buffer_cast<Tp>(buffer);
|
||||||
::new (&to.storage_.emplace<buffer_t>()) Tp(std::move(*src));
|
::new (&to.storage_.emplace<buffer_t>()) Tp(std::move(src));
|
||||||
src->~Tp();
|
src.~Tp();
|
||||||
},
|
},
|
||||||
[](...){}
|
[](...){}
|
||||||
}, from.storage_);
|
}, from.storage_);
|
||||||
@@ -146,14 +149,16 @@ namespace meta_hpp
|
|||||||
},
|
},
|
||||||
|
|
||||||
.copy = [](const value& from, value& to){
|
.copy = [](const value& from, value& to){
|
||||||
|
assert(from && !to);
|
||||||
|
|
||||||
std::visit(detail::overloaded {
|
std::visit(detail::overloaded {
|
||||||
[&to](void* ptr) {
|
[&to](void* ptr) {
|
||||||
const Tp* src = static_cast<const Tp*>(ptr);
|
const Tp& src = *static_cast<const Tp*>(ptr);
|
||||||
to.storage_.emplace<void*>(new Tp{*src});
|
to.storage_.emplace<void*>(new Tp(src));
|
||||||
},
|
},
|
||||||
[&to](const buffer_t& buffer) {
|
[&to](const buffer_t& buffer) {
|
||||||
const Tp* src = storage_cast<Tp>(buffer);
|
const Tp& src = *buffer_cast<Tp>(buffer);
|
||||||
::new (&to.storage_.emplace<buffer_t>()) Tp(*src);
|
::new (&to.storage_.emplace<buffer_t>()) Tp(src);
|
||||||
},
|
},
|
||||||
[](...){}
|
[](...){}
|
||||||
}, from.storage_);
|
}, from.storage_);
|
||||||
@@ -162,13 +167,16 @@ namespace meta_hpp
|
|||||||
},
|
},
|
||||||
|
|
||||||
.destroy = [](value& self) noexcept {
|
.destroy = [](value& self) noexcept {
|
||||||
|
assert(self);
|
||||||
|
|
||||||
std::visit(detail::overloaded {
|
std::visit(detail::overloaded {
|
||||||
[](void* ptr) {
|
[](void* ptr) {
|
||||||
Tp* src = static_cast<Tp*>(ptr);
|
Tp* src = static_cast<Tp*>(ptr);
|
||||||
std::unique_ptr<Tp>{src}.reset();
|
std::unique_ptr<Tp>{src}.reset();
|
||||||
},
|
},
|
||||||
[](buffer_t& buffer) {
|
[](buffer_t& buffer) {
|
||||||
storage_cast<Tp>(buffer)->~Tp();
|
Tp& src = *buffer_cast<Tp>(buffer);
|
||||||
|
src.~Tp();
|
||||||
},
|
},
|
||||||
[](...){}
|
[](...){}
|
||||||
}, self.storage_);
|
}, self.storage_);
|
||||||
@@ -232,7 +240,7 @@ namespace meta_hpp
|
|||||||
|
|
||||||
namespace meta_hpp
|
namespace meta_hpp
|
||||||
{
|
{
|
||||||
inline value::~value() noexcept {
|
inline value::~value() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,10 +291,9 @@ namespace meta_hpp
|
|||||||
return is_valid();
|
return is_valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void value::reset() noexcept {
|
inline void value::reset() {
|
||||||
if ( vtable_ != nullptr ) {
|
if ( vtable_ != nullptr ) {
|
||||||
vtable_->destroy(*this);
|
vtable_->destroy(*this);
|
||||||
vtable_ = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
122
untests/meta_base/fixed_function_tests.cpp
Normal file
122
untests/meta_base/fixed_function_tests.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* This file is part of the "https://github.com/blackmatov/meta.hpp"
|
||||||
|
* For conditions of distribution and use, see copyright notice in LICENSE.md
|
||||||
|
* Copyright (C) 2021, by Matvey Cherevko (blackmatov@gmail.com)
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "../meta_untests.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("meta/meta_base/fixed_function") {
|
||||||
|
namespace meta = meta_hpp;
|
||||||
|
using meta::detail::fixed_function;
|
||||||
|
|
||||||
|
SUBCASE("is_valid") {
|
||||||
|
{
|
||||||
|
fixed_function<void()> ff;
|
||||||
|
CHECK_FALSE(ff);
|
||||||
|
CHECK_FALSE(ff.is_valid());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
fixed_function<void()> ff = []{};
|
||||||
|
CHECK(ff);
|
||||||
|
CHECK(ff.is_valid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("ctor") {
|
||||||
|
{
|
||||||
|
auto f1 = []{return 1;};
|
||||||
|
fixed_function<int()> ff{std::move(f1)};
|
||||||
|
CHECK(ff() == 1);
|
||||||
|
|
||||||
|
auto f2 = fixed_function{[]{return 2;}};
|
||||||
|
ff = std::move(f2);
|
||||||
|
CHECK(ff() == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("reset") {
|
||||||
|
fixed_function ff = []{return 0;};
|
||||||
|
|
||||||
|
ff.reset();
|
||||||
|
CHECK_FALSE(ff);
|
||||||
|
CHECK_FALSE(ff.is_valid());
|
||||||
|
|
||||||
|
ff = []{return 1;};
|
||||||
|
CHECK(ff);
|
||||||
|
CHECK(ff.is_valid());
|
||||||
|
|
||||||
|
CHECK(ff() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("move") {
|
||||||
|
fixed_function ff = []{return 1;};
|
||||||
|
fixed_function ff2 = std::move(ff);
|
||||||
|
CHECK(ff2() == 1);
|
||||||
|
CHECK_FALSE(ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("operator=") {
|
||||||
|
{
|
||||||
|
fixed_function<int()> ff;
|
||||||
|
ff = []{return 0;};
|
||||||
|
CHECK(ff() == 0);
|
||||||
|
ff = []{return 1;};
|
||||||
|
CHECK(ff() == 1);
|
||||||
|
|
||||||
|
fixed_function<int()> ff2 = []{return 2;};
|
||||||
|
ff = std::move(ff2);
|
||||||
|
CHECK(ff() == 2);
|
||||||
|
CHECK_FALSE(ff2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("swap") {
|
||||||
|
{
|
||||||
|
fixed_function<void()> ff1;
|
||||||
|
fixed_function<void()> ff2;
|
||||||
|
ff1.swap(ff2);
|
||||||
|
CHECK_FALSE(ff1);
|
||||||
|
CHECK_FALSE(ff2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
fixed_function ff1 = []{return 1;};
|
||||||
|
fixed_function ff2 = []{return 2;};
|
||||||
|
ff1.swap(ff2);
|
||||||
|
CHECK(ff1() == 2);
|
||||||
|
CHECK(ff2() == 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
fixed_function<int()> ff1;
|
||||||
|
fixed_function ff2 = []{return 2;};
|
||||||
|
|
||||||
|
ff1.swap(ff2);
|
||||||
|
CHECK(ff1() == 2);
|
||||||
|
CHECK_FALSE(ff2);
|
||||||
|
|
||||||
|
ff1.swap(ff2);
|
||||||
|
CHECK_FALSE(ff1);
|
||||||
|
CHECK(ff2() == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("-> int") {
|
||||||
|
auto f = [
|
||||||
|
s = std::make_unique<int>(10)
|
||||||
|
](){ return 0; };
|
||||||
|
fixed_function ff = std::move(f);
|
||||||
|
CHECK(ff() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUBCASE("-> void") {
|
||||||
|
auto f = [
|
||||||
|
s = std::make_unique<int>(10)
|
||||||
|
](){};
|
||||||
|
fixed_function ff = std::move(f);
|
||||||
|
CHECK_NOTHROW(ff());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user