diff --git a/octa/functional.h b/octa/functional.h index 74960bc..ad251bf 100644 --- a/octa/functional.h +++ b/octa/functional.h @@ -358,85 +358,107 @@ namespace detail { && octa::IsMoveConstructible::value; }; - template - struct FunctorDataManager { - template - static R call(const FunctorData &s, A ...args) { - return ((T &)s)(octa::forward(args)...); - } - - static void store_f(FunctorData &s, T v) { - new (&get_ref(s)) T(octa::forward(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 - struct FunctorDataManager::value> - > { - template - static R call(const FunctorData &s, A ...args) { - return (*(T *&)s)(octa::forward(args)...); - } - - static void store_f(FunctorData &s, T v) { - new (&get_ptr_ref(s)) T *(new T(octa::forward(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 FmStorage { FunctorData data; const FunctionManager *manager; + + template + A &get_alloc() { + return (A &)manager; + } + template + const A &get_alloc() const { + return (const A &)manager; + } }; - template + template + struct FunctorDataManager { + template + static R call(const FunctorData &s, Args ...args) { + return ((T &)s)(octa::forward(args)...); + } + + static void store_f(FmStorage &s, T v) { + new (&get_ref(s)) T(octa::forward(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 + struct FunctorDataManager::value> + > { + template + static R call(const FunctorData &s, Args ...args) { + return (*(octa::AllocatorPointer &)s) + (octa::forward(args)...); + } + + static void store_f(FmStorage &s, T v) { + A &a = s.get_alloc(); + AllocatorPointer *ptr = new (&get_ptr_ref(s)) + AllocatorPointer(allocator_allocate(a, 1)); + allocator_construct(a, *ptr, octa::forward(v)); + } + + static void move_f(FmStorage &lhs, FmStorage &&rhs) { + new (&get_ptr_ref(lhs)) AllocatorPointer(octa::move( + get_ptr_ref(rhs))); + get_ptr_ref(rhs) = nullptr; + } + + static void destroy_f(A &a, FmStorage &s) { + AllocatorPointer &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 &get_ptr_ref(FmStorage &s) { + return (AllocatorPointer &)(s.data); + } + + static AllocatorPointer &get_ptr_ref(const FmStorage &s) { + return (AllocatorPointer &)(s.data); + } + }; + + template static const FunctionManager &get_default_fm(); + template + static void create_fm(FmStorage &s, A &&a) { + new (&s.get_alloc()) A(octa::move(a)); + s.manager = &get_default_fm(); + } + struct FunctionManager { - template - inline static const FunctionManager create_default_manager() { + template + inline static constexpr FunctionManager create_default_manager() { return FunctionManager { - &call_move_and_destroy, - &call_copy, - &call_destroy + &call_move_and_destroy, + &call_copy, + &call_copy_fo, + &call_destroy }; } @@ -444,36 +466,47 @@ namespace detail { FmStorage &&rhs); void (* const call_copyf)(FmStorage &lhs, const FmStorage &rhs); + void (* const call_copyf_fo)(FmStorage &lhs, + const FmStorage &rhs); void (* const call_destroyf)(FmStorage &s); - template + template static void call_move_and_destroy(FmStorage &lhs, FmStorage &&rhs) { - typedef FunctorDataManager _spec; - _spec::move_f(lhs.data, octa::move(rhs.data)); - _spec::destroy_f(rhs.data); - lhs.manager = &get_default_fm(); + typedef FunctorDataManager _spec; + _spec::move_f(lhs, octa::move(rhs)); + _spec::destroy_f(rhs.get_alloc(), rhs); + create_fm(lhs, octa::move(rhs.get_alloc())); + rhs.get_alloc().~A(); } - template + template static void call_copy(FmStorage &lhs, const FmStorage &rhs) { - typedef FunctorDataManager _spec; - lhs.manager = &get_default_fm(); - _spec::store_f(lhs.data, _spec::get_ref(rhs.data)); + typedef FunctorDataManager _spec; + create_fm(lhs, A(rhs.get_alloc())); + _spec::store_f(lhs, _spec::get_ref(rhs)); } - template + template + static void call_copy_fo(FmStorage &lhs, + const FmStorage &rhs) { + typedef FunctorDataManager _spec; + _spec::store_f(lhs, _spec::get_ref(rhs)); + } + + template static void call_destroy(FmStorage &s) { - typedef FunctorDataManager _spec; - _spec::destroy_f(s.data); + typedef FunctorDataManager _spec; + _spec::destroy_f(s.get_alloc(), s); + s.get_alloc().~A(); } }; - template + template inline static const FunctionManager &get_default_fm() { static const FunctionManager def_manager - = FunctionManager::create_default_manager(); + = FunctionManager::create_default_manager(); return def_manager; } @@ -536,10 +569,13 @@ namespace detail { decltype(test(nullptr)), R >::value; }; + + template + using FunctorType = decltype(func_to_functor(octa::declval())); } /* namespace detail */ -template -struct Function: octa::detail::FunctionBase { +template +struct Function: octa::detail::FunctionBase { Function( ) { init_empty(); } Function(nullptr_t) { init_empty(); } @@ -554,13 +590,60 @@ struct Function: octa::detail::FunctionBase { template Function(T f, EnableIf< - octa::detail::IsValidFunctor::value, bool + octa::detail::IsValidFunctor::value, bool > = true) { if (func_is_null(f)) { init_empty(); return; } - initialize(octa::detail::func_to_functor(octa::forward(f))); + initialize(octa::detail::func_to_functor(octa::forward(f)), + octa::Allocator>()); + } + + template + Function(octa::AllocatorArg, const A &) { init_empty(); } + + template + Function(octa::AllocatorArg, const A &, nullptr_t) { init_empty(); } + + template + Function(octa::AllocatorArg, const A &, Function &&f) { + init_empty(); + swap(f); + } + + template + Function(octa::AllocatorArg, const A &a, const Function &f): + p_call(f.p_call) { + const octa::detail::FunctionManager *mfa + = &octa::detail::get_default_fm, A>(); + if (f.p_stor.manager == mfa) { + octa::detail::create_fm, A>(p_stor, A(a)); + mfa->call_copyf_fo(p_stor, f.p_stor); + return; + } + + typedef AllocatorRebind AA; + const octa::detail::FunctionManager *mff + = &octa::detail::get_default_fm(); + if (f.p_stor.manager == mff) { + octa::detail::create_fm(p_stor, AA(a)); + mff->call_copyf_fo(p_stor, f.P_stor); + return; + } + + initialize(f, AA(a)); + } + + template + Function(octa::AllocatorArg, const A &a, T f, EnableIf< + octa::detail::IsValidFunctor::value, bool + > = true) { + if (func_is_null(f)) { + init_empty(); + return; + } + initialize(octa::detail::func_to_functor(octa::forward(f)), A(a)); } ~Function() { @@ -575,16 +658,17 @@ struct Function: octa::detail::FunctionBase { Function &operator=(const Function &f) { p_stor.manager->call_destroyf(p_stor); - f.p_stor.manager->call_copyf(p_stor, f.p_stor); + swap(Function(f)); return *this; }; - R operator()(A ...args) const { - return p_call(p_stor.data, octa::forward(args)...); + R operator()(Args ...args) const { + return p_call(p_stor.data, octa::forward(args)...); } - template void assign(_F &&f) { - Function(octa::forward<_F>(f)).swap(*this); + template + void assign(F &&f, const A &a) { + Function(octa::allocator_arg, a, octa::forward(f)).swap(*this); } void swap(Function &f) { @@ -602,37 +686,39 @@ struct Function: octa::detail::FunctionBase { private: octa::detail::FmStorage p_stor; - R (*p_call)(const octa::detail::FunctorData &, A...); + R (*p_call)(const octa::detail::FunctorData &, Args...); - template - void initialize(T f) { - p_call = &octa::detail::FunctorDataManager::template call; - p_stor.manager = &octa::detail::get_default_fm(); - octa::detail::FunctorDataManager::store_f(p_stor.data, + template + void initialize(T &&f, A &&a) { + p_call = &octa::detail::FunctorDataManager::template call; + octa::detail::create_fm(p_stor, octa::forward(a)); + octa::detail::FunctorDataManager::store_f(p_stor, octa::forward(f)); } void init_empty() { - typedef R(*emptyf)(A...); + typedef R(*emptyf)(Args...); + typedef octa::Allocator emptya; p_call = nullptr; - p_stor.manager = &octa::detail::get_default_fm(); - octa::detail::FunctorDataManager::store_f(p_stor.data, nullptr); + octa::detail::create_fm(p_stor, emptya()); + octa::detail::FunctorDataManager::store_f(p_stor, + nullptr); } template 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; } - template - static bool func_is_null(RR (T::* const &fptr)(AA...)) { + template + static bool func_is_null(RR (T::* const &fptr)(AArgs...)) { return fptr == nullptr; } - template - static bool func_is_null(RR (T::* const &fptr)(AA...) const) { + template + static bool func_is_null(RR (T::* const &fptr)(AArgs...) const) { return fptr == nullptr; } }; diff --git a/octa/memory.h b/octa/memory.h index 57c6a0e..c336714 100644 --- a/octa/memory.h +++ b/octa/memory.h @@ -1112,6 +1112,11 @@ inline AllocatorType allocator_container_copy(const A &a) { const A >(), a); } -} + +struct AllocatorArg {}; + +constexpr AllocatorArg allocator_arg = AllocatorArg(); + +} /* namespace octa */ #endif \ No newline at end of file