forked from OctaForge/libostd
octa::Function allocator support
parent
e9ab01b894
commit
2652fe9242
|
@ -358,85 +358,107 @@ namespace detail {
|
||||||
&& octa::IsMoveConstructible<T>::value;
|
&& octa::IsMoveConstructible<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename E = void>
|
|
||||||
struct FunctorDataManager {
|
|
||||||
template<typename R, typename ...A>
|
|
||||||
static R call(const FunctorData &s, A ...args) {
|
|
||||||
return ((T &)s)(octa::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void store_f(FunctorData &s, T v) {
|
|
||||||
new (&get_ref(s)) T(octa::forward<T>(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void move_f(FunctorData &lhs, FunctorData &&rhs) {
|
|
||||||
new (&get_ref(lhs)) T(octa::move(get_ref(rhs)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy_f(FunctorData &s) {
|
|
||||||
get_ref(s).~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
static T &get_ref(const FunctorData &s) {
|
|
||||||
return (T &)s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct FunctorDataManager<T,
|
|
||||||
EnableIf<!FunctorInPlace<T>::value>
|
|
||||||
> {
|
|
||||||
template<typename R, typename ...A>
|
|
||||||
static R call(const FunctorData &s, A ...args) {
|
|
||||||
return (*(T *&)s)(octa::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void store_f(FunctorData &s, T v) {
|
|
||||||
new (&get_ptr_ref(s)) T *(new T(octa::forward<T>(v)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void move_f(FunctorData &lhs, FunctorData &&rhs) {
|
|
||||||
new (&get_ptr_ref(lhs)) T *(get_ptr_ref(rhs));
|
|
||||||
get_ptr_ref(rhs) = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy_f(FunctorData &s) {
|
|
||||||
T *&ptr = get_ptr_ref(s);
|
|
||||||
if (!ptr) return;
|
|
||||||
delete ptr;
|
|
||||||
ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static T &get_ref(const FunctorData &s) {
|
|
||||||
return *get_ptr_ref(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static T *&get_ptr_ref(FunctorData &s) {
|
|
||||||
return (T *&)s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static T *&get_ptr_ref(const FunctorData &s) {
|
|
||||||
return (T *&)s;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FunctionManager;
|
struct FunctionManager;
|
||||||
|
|
||||||
struct FmStorage {
|
struct FmStorage {
|
||||||
FunctorData data;
|
FunctorData data;
|
||||||
const FunctionManager *manager;
|
const FunctionManager *manager;
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
A &get_alloc() {
|
||||||
|
return (A &)manager;
|
||||||
|
}
|
||||||
|
template<typename A>
|
||||||
|
const A &get_alloc() const {
|
||||||
|
return (const A &)manager;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A, typename E = void>
|
||||||
|
struct FunctorDataManager {
|
||||||
|
template<typename R, typename ...Args>
|
||||||
|
static R call(const FunctorData &s, Args ...args) {
|
||||||
|
return ((T &)s)(octa::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void store_f(FmStorage &s, T v) {
|
||||||
|
new (&get_ref(s)) T(octa::forward<T>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
|
||||||
|
new (&get_ref(lhs)) T(octa::move(get_ref(rhs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_f(A &, FmStorage &s) {
|
||||||
|
get_ref(s).~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
static T &get_ref(const FmStorage &s) {
|
||||||
|
return (T &)(s.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename A>
|
||||||
|
struct FunctorDataManager<T, A,
|
||||||
|
EnableIf<!FunctorInPlace<T>::value>
|
||||||
|
> {
|
||||||
|
template<typename R, typename ...Args>
|
||||||
|
static R call(const FunctorData &s, Args ...args) {
|
||||||
|
return (*(octa::AllocatorPointer<A> &)s)
|
||||||
|
(octa::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void store_f(FmStorage &s, T v) {
|
||||||
|
A &a = s.get_alloc<A>();
|
||||||
|
AllocatorPointer<A> *ptr = new (&get_ptr_ref(s))
|
||||||
|
AllocatorPointer<A>(allocator_allocate(a, 1));
|
||||||
|
allocator_construct(a, *ptr, octa::forward<T>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
|
||||||
|
new (&get_ptr_ref(lhs)) AllocatorPointer<A>(octa::move(
|
||||||
|
get_ptr_ref(rhs)));
|
||||||
|
get_ptr_ref(rhs) = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_f(A &a, FmStorage &s) {
|
||||||
|
AllocatorPointer<A> &ptr = get_ptr_ref(s);
|
||||||
|
if (!ptr) return;
|
||||||
|
allocator_destroy(a, ptr);
|
||||||
|
allocator_deallocate(a, ptr, 1);
|
||||||
|
ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static T &get_ref(const FmStorage &s) {
|
||||||
|
return *get_ptr_ref(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AllocatorPointer<A> &get_ptr_ref(FmStorage &s) {
|
||||||
|
return (AllocatorPointer<A> &)(s.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AllocatorPointer<A> &get_ptr_ref(const FmStorage &s) {
|
||||||
|
return (AllocatorPointer<A> &)(s.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename A>
|
||||||
static const FunctionManager &get_default_fm();
|
static const FunctionManager &get_default_fm();
|
||||||
|
|
||||||
|
template<typename T, typename A>
|
||||||
|
static void create_fm(FmStorage &s, A &&a) {
|
||||||
|
new (&s.get_alloc<A>()) A(octa::move(a));
|
||||||
|
s.manager = &get_default_fm<T, A>();
|
||||||
|
}
|
||||||
|
|
||||||
struct FunctionManager {
|
struct FunctionManager {
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
inline static const FunctionManager create_default_manager() {
|
inline static constexpr FunctionManager create_default_manager() {
|
||||||
return FunctionManager {
|
return FunctionManager {
|
||||||
&call_move_and_destroy<T>,
|
&call_move_and_destroy<T, A>,
|
||||||
&call_copy<T>,
|
&call_copy<T, A>,
|
||||||
&call_destroy<T>
|
&call_copy_fo<T, A>,
|
||||||
|
&call_destroy<T, A>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,36 +466,47 @@ namespace detail {
|
||||||
FmStorage &&rhs);
|
FmStorage &&rhs);
|
||||||
void (* const call_copyf)(FmStorage &lhs,
|
void (* const call_copyf)(FmStorage &lhs,
|
||||||
const FmStorage &rhs);
|
const FmStorage &rhs);
|
||||||
|
void (* const call_copyf_fo)(FmStorage &lhs,
|
||||||
|
const FmStorage &rhs);
|
||||||
void (* const call_destroyf)(FmStorage &s);
|
void (* const call_destroyf)(FmStorage &s);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
static void call_move_and_destroy(FmStorage &lhs,
|
static void call_move_and_destroy(FmStorage &lhs,
|
||||||
FmStorage &&rhs) {
|
FmStorage &&rhs) {
|
||||||
typedef FunctorDataManager<T> _spec;
|
typedef FunctorDataManager<T, A> _spec;
|
||||||
_spec::move_f(lhs.data, octa::move(rhs.data));
|
_spec::move_f(lhs, octa::move(rhs));
|
||||||
_spec::destroy_f(rhs.data);
|
_spec::destroy_f(rhs.get_alloc<A>(), rhs);
|
||||||
lhs.manager = &get_default_fm<T>();
|
create_fm<T, A>(lhs, octa::move(rhs.get_alloc<A>()));
|
||||||
|
rhs.get_alloc<A>().~A();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
static void call_copy(FmStorage &lhs,
|
static void call_copy(FmStorage &lhs,
|
||||||
const FmStorage &rhs) {
|
const FmStorage &rhs) {
|
||||||
typedef FunctorDataManager<T> _spec;
|
typedef FunctorDataManager<T, A> _spec;
|
||||||
lhs.manager = &get_default_fm<T>();
|
create_fm<T, A>(lhs, A(rhs.get_alloc<A>()));
|
||||||
_spec::store_f(lhs.data, _spec::get_ref(rhs.data));
|
_spec::store_f(lhs, _spec::get_ref(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
|
static void call_copy_fo(FmStorage &lhs,
|
||||||
|
const FmStorage &rhs) {
|
||||||
|
typedef FunctorDataManager<T, A> _spec;
|
||||||
|
_spec::store_f(lhs, _spec::get_ref(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename A>
|
||||||
static void call_destroy(FmStorage &s) {
|
static void call_destroy(FmStorage &s) {
|
||||||
typedef FunctorDataManager<T> _spec;
|
typedef FunctorDataManager<T, A> _spec;
|
||||||
_spec::destroy_f(s.data);
|
_spec::destroy_f(s.get_alloc<A>(), s);
|
||||||
|
s.get_alloc<A>().~A();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
inline static const FunctionManager &get_default_fm() {
|
inline static const FunctionManager &get_default_fm() {
|
||||||
static const FunctionManager def_manager
|
static const FunctionManager def_manager
|
||||||
= FunctionManager::create_default_manager<T>();
|
= FunctionManager::create_default_manager<T, A>();
|
||||||
return def_manager;
|
return def_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,10 +569,13 @@ namespace detail {
|
||||||
decltype(test<T>(nullptr)), R
|
decltype(test<T>(nullptr)), R
|
||||||
>::value;
|
>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using FunctorType = decltype(func_to_functor(octa::declval<T>()));
|
||||||
} /* namespace detail */
|
} /* namespace detail */
|
||||||
|
|
||||||
template<typename R, typename ...A>
|
template<typename R, typename ...Args>
|
||||||
struct Function<R(A...)>: octa::detail::FunctionBase<R, A...> {
|
struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
|
||||||
Function( ) { init_empty(); }
|
Function( ) { init_empty(); }
|
||||||
Function(nullptr_t) { init_empty(); }
|
Function(nullptr_t) { init_empty(); }
|
||||||
|
|
||||||
|
@ -554,13 +590,60 @@ struct Function<R(A...)>: octa::detail::FunctionBase<R, A...> {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Function(T f, EnableIf<
|
Function(T f, EnableIf<
|
||||||
octa::detail::IsValidFunctor<T, R(A...)>::value, bool
|
octa::detail::IsValidFunctor<T, R(Args...)>::value, bool
|
||||||
> = true) {
|
> = true) {
|
||||||
if (func_is_null(f)) {
|
if (func_is_null(f)) {
|
||||||
init_empty();
|
init_empty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initialize(octa::detail::func_to_functor(octa::forward<T>(f)));
|
initialize(octa::detail::func_to_functor(octa::forward<T>(f)),
|
||||||
|
octa::Allocator<octa::detail::FunctorType<T>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
Function(octa::AllocatorArg, const A &) { init_empty(); }
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
Function(octa::AllocatorArg, const A &, nullptr_t) { init_empty(); }
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
Function(octa::AllocatorArg, const A &, Function &&f) {
|
||||||
|
init_empty();
|
||||||
|
swap(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A>
|
||||||
|
Function(octa::AllocatorArg, const A &a, const Function &f):
|
||||||
|
p_call(f.p_call) {
|
||||||
|
const octa::detail::FunctionManager *mfa
|
||||||
|
= &octa::detail::get_default_fm<octa::AllocatorValue<A>, A>();
|
||||||
|
if (f.p_stor.manager == mfa) {
|
||||||
|
octa::detail::create_fm<octa::AllocatorValue<A>, A>(p_stor, A(a));
|
||||||
|
mfa->call_copyf_fo(p_stor, f.p_stor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef AllocatorRebind<A, Function> AA;
|
||||||
|
const octa::detail::FunctionManager *mff
|
||||||
|
= &octa::detail::get_default_fm<Function, AA>();
|
||||||
|
if (f.p_stor.manager == mff) {
|
||||||
|
octa::detail::create_fm<Function, AA>(p_stor, AA(a));
|
||||||
|
mff->call_copyf_fo(p_stor, f.P_stor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(f, AA(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename A, typename T>
|
||||||
|
Function(octa::AllocatorArg, const A &a, T f, EnableIf<
|
||||||
|
octa::detail::IsValidFunctor<T, R(Args...)>::value, bool
|
||||||
|
> = true) {
|
||||||
|
if (func_is_null(f)) {
|
||||||
|
init_empty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialize(octa::detail::func_to_functor(octa::forward<T>(f)), A(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
~Function() {
|
~Function() {
|
||||||
|
@ -575,16 +658,17 @@ struct Function<R(A...)>: octa::detail::FunctionBase<R, A...> {
|
||||||
|
|
||||||
Function &operator=(const Function &f) {
|
Function &operator=(const Function &f) {
|
||||||
p_stor.manager->call_destroyf(p_stor);
|
p_stor.manager->call_destroyf(p_stor);
|
||||||
f.p_stor.manager->call_copyf(p_stor, f.p_stor);
|
swap(Function(f));
|
||||||
return *this;
|
return *this;
|
||||||
};
|
};
|
||||||
|
|
||||||
R operator()(A ...args) const {
|
R operator()(Args ...args) const {
|
||||||
return p_call(p_stor.data, octa::forward<A>(args)...);
|
return p_call(p_stor.data, octa::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _F> void assign(_F &&f) {
|
template<typename F, typename A>
|
||||||
Function(octa::forward<_F>(f)).swap(*this);
|
void assign(F &&f, const A &a) {
|
||||||
|
Function(octa::allocator_arg, a, octa::forward<F>(f)).swap(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(Function &f) {
|
void swap(Function &f) {
|
||||||
|
@ -602,37 +686,39 @@ struct Function<R(A...)>: octa::detail::FunctionBase<R, A...> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
octa::detail::FmStorage p_stor;
|
octa::detail::FmStorage p_stor;
|
||||||
R (*p_call)(const octa::detail::FunctorData &, A...);
|
R (*p_call)(const octa::detail::FunctorData &, Args...);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename A>
|
||||||
void initialize(T f) {
|
void initialize(T &&f, A &&a) {
|
||||||
p_call = &octa::detail::FunctorDataManager<T>::template call<R, A...>;
|
p_call = &octa::detail::FunctorDataManager<T, A>::template call<R, Args...>;
|
||||||
p_stor.manager = &octa::detail::get_default_fm<T>();
|
octa::detail::create_fm<T, A>(p_stor, octa::forward<A>(a));
|
||||||
octa::detail::FunctorDataManager<T>::store_f(p_stor.data,
|
octa::detail::FunctorDataManager<T, A>::store_f(p_stor,
|
||||||
octa::forward<T>(f));
|
octa::forward<T>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_empty() {
|
void init_empty() {
|
||||||
typedef R(*emptyf)(A...);
|
typedef R(*emptyf)(Args...);
|
||||||
|
typedef octa::Allocator<emptyf> emptya;
|
||||||
p_call = nullptr;
|
p_call = nullptr;
|
||||||
p_stor.manager = &octa::detail::get_default_fm<emptyf>();
|
octa::detail::create_fm<emptyf, emptya>(p_stor, emptya());
|
||||||
octa::detail::FunctorDataManager<emptyf>::store_f(p_stor.data, nullptr);
|
octa::detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor,
|
||||||
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool func_is_null(const T &) { return false; }
|
static bool func_is_null(const T &) { return false; }
|
||||||
|
|
||||||
static bool func_is_null(R (* const &fptr)(A...)) {
|
static bool func_is_null(R (* const &fptr)(Args...)) {
|
||||||
return fptr == nullptr;
|
return fptr == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RR, typename T, typename ...AA>
|
template<typename RR, typename T, typename ...AArgs>
|
||||||
static bool func_is_null(RR (T::* const &fptr)(AA...)) {
|
static bool func_is_null(RR (T::* const &fptr)(AArgs...)) {
|
||||||
return fptr == nullptr;
|
return fptr == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RR, typename T, typename ...AA>
|
template<typename RR, typename T, typename ...AArgs>
|
||||||
static bool func_is_null(RR (T::* const &fptr)(AA...) const) {
|
static bool func_is_null(RR (T::* const &fptr)(AArgs...) const) {
|
||||||
return fptr == nullptr;
|
return fptr == nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1112,6 +1112,11 @@ inline AllocatorType<A> allocator_container_copy(const A &a) {
|
||||||
const A
|
const A
|
||||||
>(), a);
|
>(), a);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
struct AllocatorArg {};
|
||||||
|
|
||||||
|
constexpr AllocatorArg allocator_arg = AllocatorArg();
|
||||||
|
|
||||||
|
} /* namespace octa */
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue