libostd/octa/functional.h

809 lines
22 KiB
C
Raw Normal View History

/* Function objects for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
#ifndef OCTA_FUNCTIONAL_H
#define OCTA_FUNCTIONAL_H
#include "octa/new.h"
#include "octa/memory.h"
#include "octa/utility.h"
2015-04-25 17:13:21 +02:00
#include "octa/type_traits.h"
namespace octa {
2015-04-18 03:50:20 +02:00
2015-06-04 00:27:09 +02:00
/* basic function objects */
#define OCTA_DEFINE_BINARY_OP(_name, _op, _rettype) \
2015-06-04 23:57:06 +02:00
template<typename T> struct _name { \
_rettype operator()(const T &x, const T &y) const { \
2015-06-04 00:27:09 +02:00
return x _op y; \
} \
2015-06-04 23:57:06 +02:00
typedef T FirstArgument; \
typedef T SecondArgument; \
2015-06-04 00:27:09 +02:00
typedef _rettype Result; \
};
OCTA_DEFINE_BINARY_OP(Less, <, bool)
OCTA_DEFINE_BINARY_OP(LessEqual, <=, bool)
OCTA_DEFINE_BINARY_OP(Greater, >, bool)
OCTA_DEFINE_BINARY_OP(GreaterEqual, >=, bool)
OCTA_DEFINE_BINARY_OP(Equal, ==, bool)
OCTA_DEFINE_BINARY_OP(NotEqual, !=, bool)
OCTA_DEFINE_BINARY_OP(LogicalAnd, &&, bool)
OCTA_DEFINE_BINARY_OP(LogicalOr, ||, bool)
2015-06-04 23:57:06 +02:00
OCTA_DEFINE_BINARY_OP(Modulus, %, T)
OCTA_DEFINE_BINARY_OP(Multiplies, *, T)
OCTA_DEFINE_BINARY_OP(Divides, /, T)
OCTA_DEFINE_BINARY_OP(Plus, +, T)
OCTA_DEFINE_BINARY_OP(Minus, -, T)
OCTA_DEFINE_BINARY_OP(BitAnd, &, T)
OCTA_DEFINE_BINARY_OP(BitOr, |, T)
OCTA_DEFINE_BINARY_OP(BitXor, ^, T)
2015-06-04 00:27:09 +02:00
#undef OCTA_DEFINE_BINARY_OP
2015-06-04 23:57:06 +02:00
template<typename T> struct LogicalNot {
bool operator()(const T &x) const { return !x; }
typedef T Argument;
2015-06-04 00:27:09 +02:00
typedef bool Result;
};
2015-06-04 23:57:06 +02:00
template<typename T> struct Negate {
bool operator()(const T &x) const { return -x; }
typedef T Argument;
typedef T Result;
2015-06-04 00:27:09 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T> struct BinaryNegate {
typedef typename T::FirstArgument FirstArgument;
typedef typename T::SecondArgument SecondArgument;
2015-06-04 00:27:09 +02:00
typedef bool Result;
2015-06-04 23:57:06 +02:00
explicit BinaryNegate(const T &f): p_fn(f) {}
2015-06-04 00:27:09 +02:00
bool operator()(const FirstArgument &x,
const SecondArgument &y) {
return !p_fn(x, y);
}
private:
2015-06-04 23:57:06 +02:00
T p_fn;
2015-06-04 00:27:09 +02:00
};
2015-04-27 20:38:34 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> struct UnaryNegate {
typedef typename T::Argument Argument;
2015-06-04 00:27:09 +02:00
typedef bool Result;
2015-04-18 19:36:06 +02:00
2015-06-04 23:57:06 +02:00
explicit UnaryNegate(const T &f): p_fn(f) {}
2015-06-04 00:27:09 +02:00
bool operator()(const Argument &x) {
return !p_fn(x);
2015-04-18 19:36:06 +02:00
}
2015-06-04 00:27:09 +02:00
private:
2015-06-04 23:57:06 +02:00
T p_fn;
2015-06-04 00:27:09 +02:00
};
2015-04-18 19:36:06 +02:00
2015-06-04 23:57:06 +02:00
template<typename T> UnaryNegate<T> not1(const T &fn) {
return UnaryNegate<T>(fn);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T> BinaryNegate<T> not2(const T &fn) {
return BinaryNegate<T>(fn);
2015-06-04 00:27:09 +02:00
}
2015-06-04 00:27:09 +02:00
/* hash */
2015-06-04 23:57:06 +02:00
template<typename T> struct Hash;
2015-06-04 00:27:09 +02:00
namespace detail {
2015-06-04 23:57:06 +02:00
template<typename T> struct HashBase {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
2015-06-04 00:27:09 +02:00
return size_t(v);
}
};
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
#define OCTA_HASH_BASIC(T) template<> struct Hash<T>: octa::detail::HashBase<T> {};
2015-06-04 00:27:09 +02:00
OCTA_HASH_BASIC(bool)
OCTA_HASH_BASIC(char)
OCTA_HASH_BASIC(schar)
OCTA_HASH_BASIC(uchar)
OCTA_HASH_BASIC(char16_t)
OCTA_HASH_BASIC(char32_t)
OCTA_HASH_BASIC(wchar_t)
OCTA_HASH_BASIC(short)
OCTA_HASH_BASIC(ushort)
OCTA_HASH_BASIC(int)
OCTA_HASH_BASIC(uint)
OCTA_HASH_BASIC(long)
OCTA_HASH_BASIC(ulong)
#undef OCTA_HASH_BASIC
namespace detail {
static inline size_t mem_hash(const void *p, size_t l) {
const uchar *d = (const uchar *)p;
size_t h = 5381;
for (size_t i = 0; i < l; ++i) h = ((h << 5) + h) ^ d[i];
return h;
}
2015-06-04 23:57:06 +02:00
template<typename T, size_t = sizeof(T) / sizeof(size_t)>
2015-06-04 00:27:09 +02:00
struct ScalarHash;
2015-06-04 23:57:06 +02:00
template<typename T> struct ScalarHash<T, 0> {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
union { T v; size_t h; } u;
2015-06-04 00:27:09 +02:00
u.h = 0;
u.v = v;
return u.h;
}
};
2015-06-04 23:57:06 +02:00
template<typename T> struct ScalarHash<T, 1> {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
union { T v; size_t h; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return u.h;
}
};
2015-06-04 23:57:06 +02:00
template<typename T> struct ScalarHash<T, 2> {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
union { T v; struct { size_t h1, h2; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return mem_hash((const void *)&u, sizeof(u));
}
};
2015-06-04 23:57:06 +02:00
template<typename T> struct ScalarHash<T, 3> {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
union { T v; struct { size_t h1, h2, h3; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return mem_hash((const void *)&u, sizeof(u));
}
};
2015-06-04 23:57:06 +02:00
template<typename T> struct ScalarHash<T, 4> {
typedef T Argument;
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T v) const {
union { T v; struct { size_t h1, h2, h3, h4; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return mem_hash((const void *)&u, sizeof(u));
}
};
2015-06-04 00:27:09 +02:00
} /* namespace detail */
2015-06-04 00:27:09 +02:00
template<> struct Hash<llong>: octa::detail::ScalarHash<llong> {};
template<> struct Hash<ullong>: octa::detail::ScalarHash<ullong> {};
2015-06-04 00:27:09 +02:00
template<> struct Hash<float>: octa::detail::ScalarHash<float> {
size_t operator()(float v) const {
if (v == 0) return 0;
return octa::detail::ScalarHash<float>::operator()(v);
}
};
2015-06-04 00:27:09 +02:00
template<> struct Hash<double>: octa::detail::ScalarHash<double> {
size_t operator()(double v) const {
if (v == 0) return 0;
return octa::detail::ScalarHash<double>::operator()(v);
}
};
2015-06-04 00:27:09 +02:00
template<> struct Hash<ldouble>: octa::detail::ScalarHash<ldouble> {
size_t operator()(ldouble v) const {
if (v == 0) return 0;
#ifdef __i386__
2015-06-04 00:27:09 +02:00
union { ldouble v; struct { size_t h1, h2, h3, h4; }; } u;
u.h1 = u.h2 = u.h3 = u.h4 = 0;
u.v = v;
return (u.h1 ^ u.h2 ^ u.h3 ^ u.h4);
#else
#ifdef __x86_64__
2015-06-04 00:27:09 +02:00
union { ldouble v; struct { size_t h1, h2; }; } u;
u.h1 = u.h2 = 0;
u.v = v;
return (u.h1 ^ u.h2);
#else
2015-06-04 00:27:09 +02:00
return octa::detail::ScalarHash<ldouble>::operator()(v);
#endif
#endif
2015-06-04 00:27:09 +02:00
}
};
2015-06-04 23:57:06 +02:00
template<typename T> struct Hash<T *> {
typedef T *Argument;
2015-06-04 00:27:09 +02:00
typedef size_t Result;
2015-06-04 23:57:06 +02:00
size_t operator()(T *v) const {
union { T *v; size_t h; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return octa::detail::mem_hash((const void *)&u, sizeof(u));
}
};
2015-06-04 00:27:09 +02:00
/* reference wrapper */
2015-04-24 19:16:35 +02:00
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 00:27:09 +02:00
struct ReferenceWrapper {
2015-06-04 23:57:06 +02:00
typedef T type;
2015-06-04 23:57:06 +02:00
ReferenceWrapper(T &v): p_ptr(address_of(v)) {}
2015-06-04 00:27:09 +02:00
ReferenceWrapper(const ReferenceWrapper &) = default;
2015-06-04 23:57:06 +02:00
ReferenceWrapper(T &&) = delete;
2015-06-04 00:27:09 +02:00
ReferenceWrapper &operator=(const ReferenceWrapper &) = default;
2015-06-04 23:57:06 +02:00
operator T &() const { return *p_ptr; }
T &get() const { return *p_ptr; }
2015-06-04 00:27:09 +02:00
private:
2015-06-04 23:57:06 +02:00
T *p_ptr;
2015-06-04 00:27:09 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
ReferenceWrapper<T> ref(T &v) {
return ReferenceWrapper<T>(v);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T>
ReferenceWrapper<T> ref(ReferenceWrapper<T> v) {
return ReferenceWrapper<T>(v);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T> void ref(const T &&) = delete;
2015-06-04 23:57:06 +02:00
template<typename T>
ReferenceWrapper<const T> cref(const T &v) {
return ReferenceWrapper<T>(v);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T>
ReferenceWrapper<const T> cref(ReferenceWrapper<T> v) {
return ReferenceWrapper<T>(v);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T> void cref(const T &&) = delete;
2015-06-04 00:27:09 +02:00
/* mem_fn */
2015-04-23 00:25:02 +02:00
2015-06-04 00:27:09 +02:00
namespace detail {
template<typename, typename> struct MemTypes;
2015-06-04 23:57:06 +02:00
template<typename T, typename R, typename ...A>
struct MemTypes<T, R(A...)> {
typedef R Result;
typedef T Argument;
};
2015-06-04 23:57:06 +02:00
template<typename T, typename R, typename A>
struct MemTypes<T, R(A)> {
typedef R Result;
typedef T FirstArgument;
typedef A SecondArgument;
};
2015-06-04 23:57:06 +02:00
template<typename T, typename R, typename ...A>
struct MemTypes<T, R(A...) const> {
typedef R Result;
typedef const T Argument;
};
2015-06-04 23:57:06 +02:00
template<typename T, typename R, typename A>
struct MemTypes<T, R(A) const> {
typedef R Result;
typedef const T FirstArgument;
typedef A SecondArgument;
};
2015-06-04 23:57:06 +02:00
template<typename R, typename T>
class MemFn: MemTypes<T, R> {
R T::*p_ptr;
2015-04-24 19:16:35 +02:00
public:
2015-06-04 23:57:06 +02:00
MemFn(R T::*ptr): p_ptr(ptr) {}
template<typename... A>
auto operator()(T &obj, A &&...args) ->
decltype(((obj).*(p_ptr))(forward<A>(args)...)) {
return ((obj).*(p_ptr))(forward<A>(args)...);
2015-04-24 19:16:35 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename... A>
auto operator()(const T &obj, A &&...args) ->
decltype(((obj).*(p_ptr))(forward<A>(args)...)) const {
return ((obj).*(p_ptr))(forward<A>(args)...);
2015-04-24 19:16:35 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename... A>
auto operator()(T *obj, A &&...args) ->
decltype(((obj)->*(p_ptr))(forward<A>(args)...)) {
return ((obj)->*(p_ptr))(forward<A>(args)...);
2015-04-24 19:16:35 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename... A>
auto operator()(const T *obj, A &&...args) ->
decltype(((obj)->*(p_ptr))(forward<A>(args)...)) const {
return ((obj)->*(p_ptr))(forward<A>(args)...);
2015-04-24 19:16:35 +02:00
}
};
2015-06-04 00:27:09 +02:00
} /* namespace detail */
2015-04-24 19:16:35 +02:00
2015-06-04 23:57:06 +02:00
template<typename R, typename T>
octa::detail::MemFn<R, T> mem_fn(R T:: *ptr) {
return octa::detail::MemFn<R, T>(ptr);
2015-06-04 00:27:09 +02:00
}
2015-04-23 00:25:02 +02:00
2015-06-04 00:27:09 +02:00
/* function impl
* reference: http://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction
*/
2015-06-04 00:27:09 +02:00
template<typename> struct Function;
2015-06-04 00:27:09 +02:00
namespace detail {
struct FunctorData {
void *p1, *p2;
2015-04-24 19:16:35 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename T>
2015-06-04 00:27:09 +02:00
struct FunctorInPlace {
2015-06-04 23:57:06 +02:00
static constexpr bool value = sizeof(T) <= sizeof(FunctorData)
&& (alignof(FunctorData) % alignof(T)) == 0
&& octa::IsMoveConstructible<T>::value;
2015-04-24 19:16:35 +02:00
};
2015-06-07 02:14:04 +02:00
struct FunctionManager;
struct FmStorage {
FunctorData data;
const FunctionManager *manager;
template<typename A>
A &get_alloc() {
2015-06-07 19:30:28 +02:00
union {
const FunctionManager **m;
A *alloc;
} u;
u.m = &manager;
return *u.alloc;
2015-06-07 02:14:04 +02:00
}
template<typename A>
const A &get_alloc() const {
2015-06-07 19:30:28 +02:00
union {
const FunctionManager * const *m;
const A *alloc;
} u;
u.m = &manager;
return *u.alloc;
2015-06-07 02:14:04 +02:00
}
};
template<typename T, typename A, typename E = void>
2015-06-04 00:27:09 +02:00
struct FunctorDataManager {
2015-06-07 02:14:04 +02:00
template<typename R, typename ...Args>
static R call(const FunctorData &s, Args ...args) {
return ((T &)s)(octa::forward<Args>(args)...);
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static void store_f(FmStorage &s, T v) {
2015-06-04 23:57:06 +02:00
new (&get_ref(s)) T(octa::forward<T>(v));
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
2015-06-04 23:57:06 +02:00
new (&get_ref(lhs)) T(octa::move(get_ref(rhs)));
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static void destroy_f(A &, FmStorage &s) {
2015-06-04 23:57:06 +02:00
get_ref(s).~T();
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static T &get_ref(const FmStorage &s) {
2015-06-07 19:30:28 +02:00
union {
const FunctorData *data;
T *ret;
} u;
u.data = &s.data;
return *u.ret;
2015-04-24 19:16:35 +02:00
}
};
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
struct FunctorDataManager<T, A,
2015-06-04 23:57:06 +02:00
EnableIf<!FunctorInPlace<T>::value>
2015-06-04 00:27:09 +02:00
> {
2015-06-07 02:14:04 +02:00
template<typename R, typename ...Args>
static R call(const FunctorData &s, Args ...args) {
return (*(octa::AllocatorPointer<A> &)s)
(octa::forward<Args>(args)...);
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
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));
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
new (&get_ptr_ref(lhs)) AllocatorPointer<A>(octa::move(
get_ptr_ref(rhs)));
2015-06-04 00:27:09 +02:00
get_ptr_ref(rhs) = nullptr;
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static void destroy_f(A &a, FmStorage &s) {
AllocatorPointer<A> &ptr = get_ptr_ref(s);
2015-06-04 00:27:09 +02:00
if (!ptr) return;
2015-06-07 02:14:04 +02:00
allocator_destroy(a, ptr);
allocator_deallocate(a, ptr, 1);
2015-06-04 00:27:09 +02:00
ptr = nullptr;
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static T &get_ref(const FmStorage &s) {
2015-06-04 00:27:09 +02:00
return *get_ptr_ref(s);
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static AllocatorPointer<A> &get_ptr_ref(FmStorage &s) {
return (AllocatorPointer<A> &)(s.data);
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
static AllocatorPointer<A> &get_ptr_ref(const FmStorage &s) {
return (AllocatorPointer<A> &)(s.data);
2015-04-24 19:16:35 +02:00
}
};
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
2015-06-04 00:27:09 +02:00
static const FunctionManager &get_default_fm();
2015-06-07 02:14:04 +02:00
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>();
}
2015-06-04 00:27:09 +02:00
struct FunctionManager {
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
inline static constexpr FunctionManager create_default_manager() {
2015-06-04 00:27:09 +02:00
return FunctionManager {
2015-06-07 02:14:04 +02:00
&call_move_and_destroy<T, A>,
&call_copy<T, A>,
&call_copy_fo<T, A>,
&call_destroy<T, A>
2015-04-24 19:16:35 +02:00
};
}
2015-06-04 00:27:09 +02:00
void (* const call_move_and_destroyf)(FmStorage &lhs,
FmStorage &&rhs);
void (* const call_copyf)(FmStorage &lhs,
const FmStorage &rhs);
2015-06-07 02:14:04 +02:00
void (* const call_copyf_fo)(FmStorage &lhs,
const FmStorage &rhs);
2015-06-04 00:27:09 +02:00
void (* const call_destroyf)(FmStorage &s);
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
2015-06-04 00:27:09 +02:00
static void call_move_and_destroy(FmStorage &lhs,
FmStorage &&rhs) {
2015-06-07 02:14:04 +02:00
typedef FunctorDataManager<T, A> _spec;
_spec::move_f(lhs, octa::move(rhs));
_spec::destroy_f(rhs.get_alloc<A>(), rhs);
create_fm<T, A>(lhs, octa::move(rhs.get_alloc<A>()));
rhs.get_alloc<A>().~A();
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
2015-06-04 00:27:09 +02:00
static void call_copy(FmStorage &lhs,
const FmStorage &rhs) {
2015-06-07 02:14:04 +02:00
typedef FunctorDataManager<T, A> _spec;
create_fm<T, A>(lhs, A(rhs.get_alloc<A>()));
_spec::store_f(lhs, _spec::get_ref(rhs));
}
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));
2015-04-24 19:16:35 +02:00
}
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
2015-06-04 00:27:09 +02:00
static void call_destroy(FmStorage &s) {
2015-06-07 02:14:04 +02:00
typedef FunctorDataManager<T, A> _spec;
_spec::destroy_f(s.get_alloc<A>(), s);
s.get_alloc<A>().~A();
}
2015-04-24 19:16:35 +02:00
};
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
2015-06-04 00:27:09 +02:00
inline static const FunctionManager &get_default_fm() {
static const FunctionManager def_manager
2015-06-07 02:14:04 +02:00
= FunctionManager::create_default_manager<T, A>();
2015-06-04 00:27:09 +02:00
return def_manager;
2015-04-24 19:16:35 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename R, typename...>
2015-06-04 00:27:09 +02:00
struct FunctionBase {
2015-06-04 23:57:06 +02:00
typedef R Result;
2015-04-24 19:16:35 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename R, typename T>
struct FunctionBase<R, T> {
typedef R Result;
typedef T Argument;
2015-04-24 19:16:35 +02:00
};
2015-06-04 23:57:06 +02:00
template<typename R, typename T, typename U>
struct FunctionBase<R, T, U> {
typedef R Result;
typedef T FirstArgument;
typedef U SecondArgument;
2015-04-24 19:16:35 +02:00
};
2015-05-03 17:09:47 +02:00
template<typename, typename>
2015-06-04 00:27:09 +02:00
struct IsValidFunctor {
2015-05-03 17:09:47 +02:00
static constexpr bool value = false;
};
2015-06-04 23:57:06 +02:00
template<typename R, typename ...A>
struct IsValidFunctor<Function<R(A...)>, R(A...)> {
2015-05-03 17:09:47 +02:00
static constexpr bool value = false;
};
2015-06-04 23:57:06 +02:00
template<typename T>
T func_to_functor(T &&f) {
return octa::forward<T>(f);
2015-05-03 17:09:47 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename RR, typename T, typename ...AA>
auto func_to_functor(RR (T::*f)(AA...))
2015-06-04 00:27:09 +02:00
-> decltype(mem_fn(f)) {
return mem_fn(f);
2015-05-03 17:09:47 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename RR, typename T, typename ...AA>
auto func_to_functor(RR (T::*f)(AA...) const)
2015-06-04 00:27:09 +02:00
-> decltype(mem_fn(f)) {
return mem_fn(f);
2015-05-03 17:09:47 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T, typename R, typename ...A>
struct IsValidFunctor<T, R(A...)> {
2015-06-07 01:03:06 +02:00
struct Nat {};
2015-06-04 23:57:06 +02:00
template<typename U>
static decltype(func_to_functor(octa::declval<U>())
(octa::declval<A>()...)) test(U *);
2015-05-03 17:09:47 +02:00
template<typename>
2015-06-07 01:03:06 +02:00
static Nat test(...);
2015-05-03 17:09:47 +02:00
static constexpr bool value = octa::IsConvertible<
2015-06-04 23:57:06 +02:00
decltype(test<T>(nullptr)), R
2015-05-03 17:09:47 +02:00
>::value;
};
2015-06-07 02:14:04 +02:00
template<typename T>
using FunctorType = decltype(func_to_functor(octa::declval<T>()));
2015-06-04 00:27:09 +02:00
} /* namespace detail */
2015-05-03 17:09:47 +02:00
2015-06-07 02:14:04 +02:00
template<typename R, typename ...Args>
struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
2015-06-04 00:27:09 +02:00
Function( ) { init_empty(); }
Function(nullptr_t) { init_empty(); }
2015-06-04 00:27:09 +02:00
Function(Function &&f) {
init_empty();
swap(f);
}
2015-06-04 00:27:09 +02:00
Function(const Function &f): p_call(f.p_call) {
f.p_stor.manager->call_copyf(p_stor, f.p_stor);
}
2015-06-04 23:57:06 +02:00
template<typename T>
Function(T f, EnableIf<
2015-06-07 02:14:04 +02:00
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)),
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
2015-06-07 01:03:06 +02:00
> = true) {
2015-06-04 00:27:09 +02:00
if (func_is_null(f)) {
init_empty();
return;
}
2015-06-07 02:14:04 +02:00
initialize(octa::detail::func_to_functor(octa::forward<T>(f)), A(a));
2015-06-04 00:27:09 +02:00
}
2015-06-04 00:27:09 +02:00
~Function() {
p_stor.manager->call_destroyf(p_stor);
}
2015-06-04 00:27:09 +02:00
Function &operator=(Function &&f) {
p_stor.manager->call_destroyf(p_stor);
swap(f);
return *this;
}
2015-06-04 00:27:09 +02:00
Function &operator=(const Function &f) {
p_stor.manager->call_destroyf(p_stor);
2015-06-07 02:14:04 +02:00
swap(Function(f));
2015-06-04 00:27:09 +02:00
return *this;
};
2015-06-07 02:14:04 +02:00
R operator()(Args ...args) const {
return p_call(p_stor.data, octa::forward<Args>(args)...);
2015-06-04 00:27:09 +02:00
}
2015-06-07 02:14:04 +02:00
template<typename F, typename A>
void assign(F &&f, const A &a) {
Function(octa::allocator_arg, a, octa::forward<F>(f)).swap(*this);
2015-06-04 00:27:09 +02:00
}
2015-06-04 00:27:09 +02:00
void swap(Function &f) {
octa::detail::FmStorage tmp;
f.p_stor.manager->call_move_and_destroyf(tmp,
octa::move(f.p_stor));
p_stor.manager->call_move_and_destroyf(f.p_stor,
octa::move(p_stor));
tmp.manager->call_move_and_destroyf(p_stor,
octa::move(tmp));
octa::swap(p_call, f.p_call);
}
2015-06-04 00:27:09 +02:00
operator bool() const { return p_call != nullptr; }
2015-06-04 00:27:09 +02:00
private:
octa::detail::FmStorage p_stor;
2015-06-07 02:14:04 +02:00
R (*p_call)(const octa::detail::FunctorData &, Args...);
2015-06-04 23:57:06 +02:00
2015-06-07 02:14:04 +02:00
template<typename T, typename A>
void initialize(T &&f, A &&a) {
p_call = &octa::detail::FunctorDataManager<T, A>::template call<R, Args...>;
octa::detail::create_fm<T, A>(p_stor, octa::forward<A>(a));
octa::detail::FunctorDataManager<T, A>::store_f(p_stor,
2015-06-04 23:57:06 +02:00
octa::forward<T>(f));
2015-06-04 00:27:09 +02:00
}
2015-06-04 00:27:09 +02:00
void init_empty() {
2015-06-07 02:14:04 +02:00
typedef R(*emptyf)(Args...);
typedef octa::Allocator<emptyf> emptya;
2015-06-04 00:27:09 +02:00
p_call = nullptr;
2015-06-07 02:14:04 +02:00
octa::detail::create_fm<emptyf, emptya>(p_stor, emptya());
octa::detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor,
nullptr);
2015-06-04 00:27:09 +02:00
}
2015-06-04 23:57:06 +02:00
template<typename T>
static bool func_is_null(const T &) { return false; }
2015-06-07 02:14:04 +02:00
static bool func_is_null(R (* const &fptr)(Args...)) {
2015-06-04 00:27:09 +02:00
return fptr == nullptr;
}
2015-06-07 02:14:04 +02:00
template<typename RR, typename T, typename ...AArgs>
static bool func_is_null(RR (T::* const &fptr)(AArgs...)) {
2015-06-04 00:27:09 +02:00
return fptr == nullptr;
}
2015-06-07 02:14:04 +02:00
template<typename RR, typename T, typename ...AArgs>
static bool func_is_null(RR (T::* const &fptr)(AArgs...) const) {
2015-06-04 00:27:09 +02:00
return fptr == nullptr;
}
};
2015-06-04 23:57:06 +02:00
template<typename T>
bool operator==(nullptr_t, const Function<T> &rhs) { return !rhs; }
2015-06-04 23:57:06 +02:00
template<typename T>
bool operator==(const Function<T> &lhs, nullptr_t) { return !lhs; }
2015-06-04 23:57:06 +02:00
template<typename T>
bool operator!=(nullptr_t, const Function<T> &rhs) { return rhs; }
2015-06-04 23:57:06 +02:00
template<typename T>
bool operator!=(const Function<T> &lhs, nullptr_t) { return lhs; }
2015-06-04 00:27:09 +02:00
namespace detail {
template<typename F>
struct DcLambdaTypes: DcLambdaTypes<decltype(&F::operator())> {};
template<typename C, typename R, typename ...A>
struct DcLambdaTypes<R (C::*)(A...) const> {
2015-06-07 19:31:27 +02:00
typedef R (*Ptr)(A...);
typedef octa::Function<R(A...)> Obj;
};
template<typename F>
struct DcFuncTest {
template<typename FF>
static char test(typename DcLambdaTypes<FF>::Ptr);
template<typename FF>
static int test(...);
static constexpr bool value = (sizeof(test<F>(octa::declval<F>())) == 1);
};
template<typename F, bool = DcFuncTest<F>::value>
struct DcFuncTypeObjBase {
typedef typename DcLambdaTypes<F>::Obj Type;
};
template<typename F>
struct DcFuncTypeObjBase<F, true> {
typedef typename DcLambdaTypes<F>::Ptr Type;
};
template<typename F, bool = octa::IsDefaultConstructible<F>::value &&
octa::IsMoveConstructible<F>::value
> struct DcFuncTypeObj {
typedef typename DcFuncTypeObjBase<F>::Type Type;
};
template<typename F>
struct DcFuncTypeObj<F, true> {
typedef F Type;
};
template<typename F, bool = octa::IsClass<F>::value>
struct DcFuncType {
typedef F Type;
};
template<typename F>
struct DcFuncType<F, true> {
typedef typename DcFuncTypeObj<F>::Type Type;
};
}
template<typename F> using FunctionMakeDefaultConstructible
= typename octa::detail::DcFuncType<F>::Type;
2015-06-04 00:27:09 +02:00
} /* namespace octa */
#endif