forked from OctaForge/libostd
use standard function
This commit is contained in:
parent
faa8c95486
commit
780f7e5b21
|
@ -19,7 +19,7 @@ namespace detail {
|
||||||
SignalBase(SignalBase const &ev):
|
SignalBase(SignalBase const &ev):
|
||||||
p_class(ev.p_class), p_nfuncs(ev.p_nfuncs)
|
p_class(ev.p_class), p_nfuncs(ev.p_nfuncs)
|
||||||
{
|
{
|
||||||
using Func = Function<void(C &, A...)>;
|
using Func = std::function<void(C &, A...)>;
|
||||||
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
|
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
|
||||||
Func *nbuf = reinterpret_cast<Func *>(bufp);
|
Func *nbuf = reinterpret_cast<Func *>(bufp);
|
||||||
for (Size i = 0; i < p_nfuncs; ++i)
|
for (Size i = 0; i < p_nfuncs; ++i)
|
||||||
|
@ -34,7 +34,7 @@ namespace detail {
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalBase &operator=(SignalBase const &ev) {
|
SignalBase &operator=(SignalBase const &ev) {
|
||||||
using Func = Function<void(C &, A...)>;
|
using Func = std::function<void(C &, A...)>;
|
||||||
p_class = ev.p_class;
|
p_class = ev.p_class;
|
||||||
p_nfuncs = ev.p_nfuncs;
|
p_nfuncs = ev.p_nfuncs;
|
||||||
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
|
byte *bufp = new byte[sizeof(Func) * p_nfuncs];
|
||||||
|
@ -54,8 +54,9 @@ namespace detail {
|
||||||
~SignalBase() { clear(); }
|
~SignalBase() { clear(); }
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
using func = std::function<void(C &, A...)>;
|
||||||
for (Size i = 0; i < p_nfuncs; ++i) {
|
for (Size i = 0; i < p_nfuncs; ++i) {
|
||||||
p_funcs[i].~Function<void(C &, A...)>();
|
p_funcs[i].~func();
|
||||||
}
|
}
|
||||||
delete[] reinterpret_cast<byte *>(p_funcs);
|
delete[] reinterpret_cast<byte *>(p_funcs);
|
||||||
p_funcs = nullptr;
|
p_funcs = nullptr;
|
||||||
|
@ -64,7 +65,7 @@ namespace detail {
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Size connect(F &&func) {
|
Size connect(F &&func) {
|
||||||
using Func = Function<void(C &, A...)>;
|
using Func = std::function<void(C &, A...)>;
|
||||||
for (Size i = 0; i < p_nfuncs; ++i) {
|
for (Size i = 0; i < p_nfuncs; ++i) {
|
||||||
if (!p_funcs[i]) {
|
if (!p_funcs[i]) {
|
||||||
p_funcs[i] = std::forward<F>(func);
|
p_funcs[i] = std::forward<F>(func);
|
||||||
|
@ -121,7 +122,7 @@ namespace detail {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
C *p_class;
|
C *p_class;
|
||||||
Function<void(C &, A...)> *p_funcs;
|
std::function<void(C &, A...)> *p_funcs;
|
||||||
Size p_nfuncs;
|
Size p_nfuncs;
|
||||||
};
|
};
|
||||||
} /* namespace detail */
|
} /* namespace detail */
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/* Function objects for OctaSTD.
|
/* Function objects for OctaSTD.
|
||||||
*
|
*
|
||||||
* This file is part of OctaSTD. See COPYING.md for futher information.
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
||||||
* Portions of this file are originally adapted from the libc++ project.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef OSTD_FUNCTIONAL_HH
|
#ifndef OSTD_FUNCTIONAL_HH
|
||||||
|
@ -440,550 +439,6 @@ typename ToHash<T>::Result to_hash(T const &v) {
|
||||||
return ToHash<T>()(v);
|
return ToHash<T>()(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mem_fn */
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename, typename>
|
|
||||||
struct MemTypes;
|
|
||||||
template<typename T, typename R, typename ...A>
|
|
||||||
struct MemTypes<T, R(A...)> {
|
|
||||||
using Result = R;
|
|
||||||
using Argument = T;
|
|
||||||
};
|
|
||||||
template<typename T, typename R, typename A>
|
|
||||||
struct MemTypes<T, R(A)> {
|
|
||||||
using Result = R;
|
|
||||||
using FirstArgument = T;
|
|
||||||
using SecondArgument = A;
|
|
||||||
};
|
|
||||||
template<typename T, typename R, typename ...A>
|
|
||||||
struct MemTypes<T, R(A...) const> {
|
|
||||||
using Result = R;
|
|
||||||
using Argument = T const;
|
|
||||||
};
|
|
||||||
template<typename T, typename R, typename A>
|
|
||||||
struct MemTypes<T, R(A) const> {
|
|
||||||
using Result = R;
|
|
||||||
using FirstArgument = T const;
|
|
||||||
using SecondArgument = A;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename R, typename T>
|
|
||||||
class MemFn: MemTypes<T, R> {
|
|
||||||
R T::*p_ptr;
|
|
||||||
public:
|
|
||||||
MemFn(R T::*ptr): p_ptr(ptr) {}
|
|
||||||
template<typename... A>
|
|
||||||
auto operator()(T &obj, A &&...args) ->
|
|
||||||
decltype(((obj).*(p_ptr))(std::forward<A>(args)...))
|
|
||||||
{
|
|
||||||
return ((obj).*(p_ptr))(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
template<typename... A>
|
|
||||||
auto operator()(T const &obj, A &&...args) ->
|
|
||||||
decltype(((obj).*(p_ptr))(std::forward<A>(args)...))
|
|
||||||
const {
|
|
||||||
return ((obj).*(p_ptr))(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
template<typename... A>
|
|
||||||
auto operator()(T *obj, A &&...args) ->
|
|
||||||
decltype(((obj)->*(p_ptr))(std::forward<A>(args)...))
|
|
||||||
{
|
|
||||||
return ((obj)->*(p_ptr))(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
template<typename... A>
|
|
||||||
auto operator()(T const *obj, A &&...args) ->
|
|
||||||
decltype(((obj)->*(p_ptr))(std::forward<A>(args)...))
|
|
||||||
const {
|
|
||||||
return ((obj)->*(p_ptr))(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} /* namespace detail */
|
|
||||||
|
|
||||||
template<typename R, typename T>
|
|
||||||
detail::MemFn<R, T> mem_fn(R T:: *ptr) {
|
|
||||||
return detail::MemFn<R, T>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* function impl adapted from libc++
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename>
|
|
||||||
class Function;
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
|
||||||
inline bool func_is_not_null(T const &) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline bool func_is_not_null(T *ptr) {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename C>
|
|
||||||
inline bool func_is_not_null(R C::*ptr) {
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline bool func_is_not_null(Function<T> const &f) {
|
|
||||||
return !!f;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
struct FuncInvokeVoidReturnWrapper {
|
|
||||||
template<typename ...A>
|
|
||||||
static R call(A &&...args) {
|
|
||||||
return func_invoke(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct FuncInvokeVoidReturnWrapper<void> {
|
|
||||||
template<typename ...A>
|
|
||||||
static void call(A &&...args) {
|
|
||||||
func_invoke(std::forward<A>(args)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class FuncBase;
|
|
||||||
|
|
||||||
template<typename R, typename ...A>
|
|
||||||
class FuncBase<R(A...)> {
|
|
||||||
FuncBase(FuncBase const &);
|
|
||||||
FuncBase &operator=(FuncBase const &);
|
|
||||||
public:
|
|
||||||
FuncBase() {}
|
|
||||||
virtual ~FuncBase() {}
|
|
||||||
virtual FuncBase *clone() const = 0;
|
|
||||||
virtual void clone(FuncBase *) const = 0;
|
|
||||||
virtual void destroy() noexcept = 0;
|
|
||||||
virtual void destroy_deallocate() noexcept = 0;
|
|
||||||
virtual R operator()(A &&...args) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, typename A, typename AT>
|
|
||||||
class FuncCore;
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
class FuncCore<F, A, R(AT...)>: public FuncBase<R(AT...)> {
|
|
||||||
CompressedPair<F, A> f_stor;
|
|
||||||
public:
|
|
||||||
explicit FuncCore(F &&f):
|
|
||||||
f_stor(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(std::move(f)),
|
|
||||||
std::forward_as_tuple()
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit FuncCore(F const &f, A const &a):
|
|
||||||
f_stor(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(f),
|
|
||||||
std::forward_as_tuple(a)
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit FuncCore(F const &f, A &&a):
|
|
||||||
f_stor(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(f),
|
|
||||||
std::forward_as_tuple(std::move(a))
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit FuncCore(F &&f, A &&a):
|
|
||||||
f_stor(
|
|
||||||
std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(std::move(f)),
|
|
||||||
std::forward_as_tuple(std::move(a))
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual FuncBase<R(AT...)> *clone() const;
|
|
||||||
virtual void clone(FuncBase<R(AT...)> *) const;
|
|
||||||
virtual void destroy() noexcept;
|
|
||||||
virtual void destroy_deallocate() noexcept;
|
|
||||||
virtual R operator()(AT &&...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
FuncBase<R(AT...)> *FuncCore<F, A, R(AT...)>::clone() const {
|
|
||||||
using AA = AllocatorRebind<A, FuncCore>;
|
|
||||||
AA a(f_stor.second());
|
|
||||||
using D = AllocatorDestructor<AA>;
|
|
||||||
Box<FuncCore, D> hold(a.allocate(1), D(a, 1));
|
|
||||||
::new(hold.get()) FuncCore(f_stor.first(), A(a));
|
|
||||||
return hold.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
void FuncCore<F, A, R(AT...)>::clone(FuncBase<R(AT...)> *p) const {
|
|
||||||
::new (p) FuncCore(f_stor.first(), f_stor.second());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
void FuncCore<F, A, R(AT...)>::destroy() noexcept {
|
|
||||||
f_stor.~CompressedPair<F, A>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
void FuncCore<F, A, R(AT...)>::destroy_deallocate() noexcept {
|
|
||||||
using AA = AllocatorRebind<A, FuncCore>;
|
|
||||||
AA a(f_stor.second());
|
|
||||||
f_stor.~CompressedPair<F, A>();
|
|
||||||
a.deallocate(this, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F, typename A, typename R, typename ...AT>
|
|
||||||
R FuncCore<F, A, R(AT...)>::operator()(AT &&...args) {
|
|
||||||
using Invoker = FuncInvokeVoidReturnWrapper<R>;
|
|
||||||
return Invoker::call(f_stor.first(), std::forward<AT>(args)...);
|
|
||||||
}
|
|
||||||
} /* namespace detail */
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
class Function<R(Args...)> {
|
|
||||||
using Base = detail::FuncBase<R(Args...)>;
|
|
||||||
AlignedStorage<3 * sizeof(void *)> p_buf;
|
|
||||||
Base *p_f;
|
|
||||||
|
|
||||||
static inline Base *as_base(void *p) {
|
|
||||||
return reinterpret_cast<Base *>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename F,
|
|
||||||
bool = !IsSame<F, Function> && detail::IsInvokable<F &, Args...>
|
|
||||||
>
|
|
||||||
struct CallableBase;
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
struct CallableBase<F, true> {
|
|
||||||
static constexpr bool value =
|
|
||||||
IsSame<R, void> || IsConvertible<detail::InvokeOf<F &, Args...>, R>;
|
|
||||||
};
|
|
||||||
template<typename F>
|
|
||||||
struct CallableBase<F, false> {
|
|
||||||
static constexpr bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
static constexpr bool Callable = CallableBase<F>::value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Result = R;
|
|
||||||
|
|
||||||
Function() noexcept: p_f(nullptr) {}
|
|
||||||
Function(Nullptr) noexcept: p_f(nullptr) {}
|
|
||||||
|
|
||||||
Function(Function const &);
|
|
||||||
Function(Function &&) noexcept;
|
|
||||||
|
|
||||||
template<
|
|
||||||
typename F, typename = EnableIf<Callable<F> && !IsSame<F, Function>>
|
|
||||||
>
|
|
||||||
Function(F);
|
|
||||||
|
|
||||||
template<typename A>
|
|
||||||
Function(AllocatorArg, A const &) noexcept: p_f(nullptr) {}
|
|
||||||
template<typename A>
|
|
||||||
Function(AllocatorArg, A const &, Nullptr) noexcept: p_f(nullptr) {}
|
|
||||||
template<typename A>
|
|
||||||
Function(AllocatorArg, A const &, Function const &);
|
|
||||||
template<typename A>
|
|
||||||
Function(AllocatorArg, A const &, Function &&);
|
|
||||||
template<typename F, typename A, typename = EnableIf<Callable<F>>>
|
|
||||||
Function(AllocatorArg, A const &, F);
|
|
||||||
|
|
||||||
Function &operator=(Function const &f) {
|
|
||||||
Function(f).swap(*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Function &operator=(Function &&) noexcept;
|
|
||||||
Function &operator=(Nullptr) noexcept;
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
EnableIf<
|
|
||||||
Callable<Decay<F>> && !IsSame<RemoveReference<F>, Function>,
|
|
||||||
Function &
|
|
||||||
> operator=(F &&f) {
|
|
||||||
Function(std::forward<F>(f)).swap(*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Function();
|
|
||||||
|
|
||||||
void swap(Function &) noexcept;
|
|
||||||
|
|
||||||
explicit operator bool() const noexcept { return p_f; }
|
|
||||||
|
|
||||||
/* deleted overloads close possible hole in the type system */
|
|
||||||
template<typename RR, typename ...AA>
|
|
||||||
bool operator==(Function<RR(AA...)> &) const = delete;
|
|
||||||
template<typename RR, typename ...AA>
|
|
||||||
bool operator!=(Function<RR(AA...)> &) const = delete;
|
|
||||||
|
|
||||||
R operator()(Args ...a) const {
|
|
||||||
return (*p_f)(std::forward<Args>(a)...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
Function<R(Args...)>::Function(Function const &f) {
|
|
||||||
if (!f.p_f) {
|
|
||||||
p_f = nullptr;
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
f.p_f->clone(p_f);
|
|
||||||
} else {
|
|
||||||
p_f = f.p_f->clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
template<typename A>
|
|
||||||
Function<R(Args...)>::Function(
|
|
||||||
AllocatorArg, A const &, Function const &f
|
|
||||||
) {
|
|
||||||
if (!f.p_f) {
|
|
||||||
p_f = nullptr;
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
f.p_f->clone(p_f);
|
|
||||||
} else {
|
|
||||||
p_f = f.p_f->clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
Function<R(Args...)>::Function(Function &&f) noexcept {
|
|
||||||
if (!f.p_f) {
|
|
||||||
p_f = nullptr;
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
f.p_f->clone(p_f);
|
|
||||||
} else {
|
|
||||||
p_f = f.p_f;
|
|
||||||
f.p_f = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
template<typename A>
|
|
||||||
Function<R(Args...)>::Function(
|
|
||||||
AllocatorArg, A const &, Function &&f
|
|
||||||
) {
|
|
||||||
if (!f.p_f) {
|
|
||||||
p_f = nullptr;
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
f.p_f->clone(p_f);
|
|
||||||
} else {
|
|
||||||
p_f = f.p_f;
|
|
||||||
f.p_f = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
template<typename F, typename>
|
|
||||||
Function<R(Args...)>::Function(F f): p_f(nullptr) {
|
|
||||||
if (!detail::func_is_not_null(f)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using FF = detail::FuncCore<F, Allocator<F>, R(Args...)>;
|
|
||||||
if ((sizeof(FF) <= sizeof(p_buf)) && IsNothrowCopyConstructible<F>) {
|
|
||||||
p_f = ::new(static_cast<void *>(&p_buf)) FF(std::move(f));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using AA = Allocator<FF>;
|
|
||||||
AA a;
|
|
||||||
using D = detail::AllocatorDestructor<AA>;
|
|
||||||
Box<FF, D> hold(a.allocate(1), D(a, 1));
|
|
||||||
::new(hold.get()) FF(std::move(f), Allocator<F>(a));
|
|
||||||
p_f = hold.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
template<typename F, typename A, typename>
|
|
||||||
Function<R(Args...)>::Function(AllocatorArg, A const &a, F f):
|
|
||||||
p_f(nullptr)
|
|
||||||
{
|
|
||||||
if (!detail::func_is_not_null(f)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using FF = detail::FuncCore<F, A, R(Args...)>;
|
|
||||||
using AA = AllocatorRebind<A, FF>;
|
|
||||||
AA aa(a);
|
|
||||||
if (
|
|
||||||
(sizeof(FF) <= sizeof(p_buf)) && IsNothrowCopyConstructible<F> &&
|
|
||||||
IsNothrowCopyConstructible<AA>
|
|
||||||
) {
|
|
||||||
p_f = ::new(static_cast<void *>(&p_buf)) FF(std::move(f), A(aa));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using D = detail::AllocatorDestructor<AA>;
|
|
||||||
Box<FF, D> hold(aa.allocate(1), D(aa, 1));
|
|
||||||
::new(hold.get()) FF(std::move(f), A(aa));
|
|
||||||
p_f = hold.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
Function<R(Args...)> &Function<R(Args...)>::operator=(Function &&f)
|
|
||||||
noexcept
|
|
||||||
{
|
|
||||||
if (static_cast<void *>(p_f) == &p_buf) {
|
|
||||||
p_f->destroy();
|
|
||||||
} else if (p_f) {
|
|
||||||
p_f->destroy_deallocate();
|
|
||||||
}
|
|
||||||
if (f.p_f == nullptr) {
|
|
||||||
p_f = nullptr;
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
f.p_f->clone(p_f);
|
|
||||||
} else {
|
|
||||||
p_f = f.p_f;
|
|
||||||
f.p_f = nullptr;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
Function<R(Args...)> &Function<R(Args...)>::operator=(Nullptr) noexcept {
|
|
||||||
if (static_cast<void *>(p_f) == &p_buf) {
|
|
||||||
p_f->destroy();
|
|
||||||
} else if (p_f) {
|
|
||||||
p_f->destroy_deallocate();
|
|
||||||
}
|
|
||||||
p_f = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
Function<R(Args...)>::~Function() {
|
|
||||||
if (static_cast<void *>(p_f) == &p_buf) {
|
|
||||||
p_f->destroy();
|
|
||||||
} else if (p_f) {
|
|
||||||
p_f->destroy_deallocate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
void Function<R(Args...)>::swap(Function &f) noexcept {
|
|
||||||
if (
|
|
||||||
(static_cast<void *>(p_f) == &p_buf) &&
|
|
||||||
(static_cast<void *>(f.p_f) == &f.p_buf)
|
|
||||||
) {
|
|
||||||
/* both in small storage */
|
|
||||||
AlignedStorage<sizeof(p_buf)> tmpbuf;
|
|
||||||
Base *t = as_base(&tmpbuf);
|
|
||||||
p_f->clone(t);
|
|
||||||
p_f->destroy();
|
|
||||||
p_f = nullptr;
|
|
||||||
f.p_f->clone(as_base(&p_buf));
|
|
||||||
f.p_f->destroy();
|
|
||||||
f.p_f = nullptr;
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
t->clone(as_base(&f.p_buf));
|
|
||||||
t->destroy();
|
|
||||||
f.p_f = as_base(&f.p_buf);
|
|
||||||
} else if (static_cast<void *>(p_f) == &p_buf) {
|
|
||||||
/* ours in small storage */
|
|
||||||
p_f->clone(as_base(&f.p_buf));
|
|
||||||
p_f->destroy();
|
|
||||||
p_f = f.p_f;
|
|
||||||
f.p_f = as_base(&f.p_buf);
|
|
||||||
} else if (static_cast<void *>(f.p_f) == &f.p_buf) {
|
|
||||||
/* the other in small storage */
|
|
||||||
f.p_f->clone(as_base(&p_buf));
|
|
||||||
f.p_f->destroy();
|
|
||||||
f.p_f = p_f;
|
|
||||||
p_f = as_base(&p_buf);
|
|
||||||
} else {
|
|
||||||
detail::swap_adl(p_f, f.p_f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
inline bool operator==(Function<R(Args...)> const &f, Nullptr) noexcept {
|
|
||||||
return !f;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
inline bool operator==(Nullptr, Function<R(Args...)> const &f) noexcept {
|
|
||||||
return !f;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
inline bool operator!=(Function<R(Args...)> const &f, Nullptr) noexcept {
|
|
||||||
return bool(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R, typename ...Args>
|
|
||||||
inline bool operator!=(Nullptr, Function<R(Args...)> const &f) noexcept {
|
|
||||||
return bool(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template<typename F>
|
|
||||||
struct DcLambdaTypes: DcLambdaTypes<decltype(&F::operator())> {};
|
|
||||||
|
|
||||||
template<typename C, typename R, typename ...A>
|
|
||||||
struct DcLambdaTypes<R (C::*)(A...) const> {
|
|
||||||
using Ptr = R (*)(A...);
|
|
||||||
using Obj = Function<R(A...)>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename FF>
|
|
||||||
static char dc_func_test(typename DcLambdaTypes<FF>::Ptr);
|
|
||||||
template<typename FF>
|
|
||||||
static int dc_func_test(...);
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
constexpr bool DcFuncTest = (sizeof(dc_func_test<F>(declval<F>())) == 1);
|
|
||||||
|
|
||||||
template<typename F, bool = DcFuncTest<F>>
|
|
||||||
struct DcFuncTypeObjBase {
|
|
||||||
using Type = typename DcLambdaTypes<F>::Obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
struct DcFuncTypeObjBase<F, true> {
|
|
||||||
using Type = typename DcLambdaTypes<F>::Ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, bool =
|
|
||||||
IsDefaultConstructible<F> && IsMoveConstructible<F>
|
|
||||||
>
|
|
||||||
struct DcFuncTypeObj {
|
|
||||||
using Type = typename DcFuncTypeObjBase<F>::Type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
struct DcFuncTypeObj<F, true> {
|
|
||||||
using Type = F;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F, bool = IsClass<F>>
|
|
||||||
struct DcFuncType {
|
|
||||||
using Type = F;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
struct DcFuncType<F, true> {
|
|
||||||
using Type = typename DcFuncTypeObj<F>::Type;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
using FunctionMakeDefaultConstructible = typename detail::DcFuncType<F>::Type;
|
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,9 +52,9 @@ inline void swap(T &a, T &b) noexcept(noexcept(detail::swap_fb(a, b))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, Size N>
|
template<typename T, Size N>
|
||||||
inline void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(*a, *b))) {
|
inline void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(ostd::swap(*a, *b))) {
|
||||||
for (Size i = 0; i < N; ++i) {
|
for (Size i = 0; i < N; ++i) {
|
||||||
swap(a[i], b[i]);
|
ostd::swap(a[i], b[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ namespace detail {
|
||||||
namespace adl_swap {
|
namespace adl_swap {
|
||||||
using ostd::swap;
|
using ostd::swap;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void swap_adl(T &a, T &b) noexcept(noexcept(swap(a, b))) {
|
inline void swap_adl(T &a, T &b) noexcept(noexcept(ostd::swap(a, b))) {
|
||||||
swap(a, b);
|
ostd::swap(a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
Loading…
Reference in a new issue