2015-04-18 01:35:36 +00:00
|
|
|
/* Function objects for OctaSTD.
|
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
2015-06-28 15:04:49 +00:00
|
|
|
#ifndef OCTA_FUNCTIONAL_HH
|
|
|
|
#define OCTA_FUNCTIONAL_HH
|
2015-04-18 01:35:36 +00:00
|
|
|
|
2015-06-30 22:30:48 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-06-28 14:39:04 +00:00
|
|
|
#include "octa/platform.hh"
|
|
|
|
#include "octa/new.hh"
|
|
|
|
#include "octa/memory.hh"
|
|
|
|
#include "octa/utility.hh"
|
|
|
|
#include "octa/type_traits.hh"
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-04-18 01:35:36 +00:00
|
|
|
namespace octa {
|
2015-04-18 01:50:20 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
/* basic function objects */
|
|
|
|
|
2015-06-07 23:55:08 +00:00
|
|
|
#define OCTA_DEFINE_BINARY_OP(name, op, RT) \
|
|
|
|
template<typename T> struct name { \
|
|
|
|
RT operator()(const T &x, const T &y) const { \
|
|
|
|
return x op y; \
|
2015-06-03 22:27:09 +00:00
|
|
|
} \
|
2015-06-07 23:55:08 +00:00
|
|
|
using FirstArgument = T; \
|
|
|
|
using SecondARgument = T; \
|
|
|
|
using Result = RT; \
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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-27 14:00:16 +00:00
|
|
|
OCTA_DEFINE_BINARY_OP(Modulo, %, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(Multiply, *, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(Divide, /, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(Add, +, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(Subtract, -, T)
|
2015-06-04 21:57:06 +00:00
|
|
|
OCTA_DEFINE_BINARY_OP(BitAnd, &, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(BitOr, |, T)
|
|
|
|
OCTA_DEFINE_BINARY_OP(BitXor, ^, T)
|
2015-06-03 22:27:09 +00:00
|
|
|
|
|
|
|
#undef OCTA_DEFINE_BINARY_OP
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct LogicalNot {
|
|
|
|
bool operator()(const T &x) const { return !x; }
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
|
|
|
using Result = bool;
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct Negate {
|
|
|
|
bool operator()(const T &x) const { return -x; }
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct BinaryNegate {
|
2015-06-07 23:55:08 +00:00
|
|
|
using FirstArgument = typename T::FirstArgument;
|
|
|
|
using SecondArgument = typename T::SecondArgument;
|
|
|
|
using Result = bool;
|
2015-06-03 22:27:09 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
explicit BinaryNegate(const T &f): p_fn(f) {}
|
2015-06-03 22:27:09 +00:00
|
|
|
|
|
|
|
bool operator()(const FirstArgument &x,
|
|
|
|
const SecondArgument &y) {
|
|
|
|
return !p_fn(x, y);
|
|
|
|
}
|
|
|
|
private:
|
2015-06-04 21:57:06 +00:00
|
|
|
T p_fn;
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
2015-04-27 18:38:34 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct UnaryNegate {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = typename T::Argument;
|
|
|
|
using Result = bool;
|
2015-04-18 17:36:06 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
explicit UnaryNegate(const T &f): p_fn(f) {}
|
2015-06-03 22:27:09 +00:00
|
|
|
bool operator()(const Argument &x) {
|
|
|
|
return !p_fn(x);
|
2015-04-18 17:36:06 +00:00
|
|
|
}
|
2015-06-03 22:27:09 +00:00
|
|
|
private:
|
2015-06-04 21:57:06 +00:00
|
|
|
T p_fn;
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
2015-04-18 17:36:06 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> UnaryNegate<T> not1(const T &fn) {
|
|
|
|
return UnaryNegate<T>(fn);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> BinaryNegate<T> not2(const T &fn) {
|
|
|
|
return BinaryNegate<T>(fn);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-27 01:38:58 +00:00
|
|
|
/* endian swap */
|
|
|
|
|
|
|
|
template<typename T, octa::Size N = sizeof(T),
|
|
|
|
bool IsNum = octa::IsArithmetic<T>::value
|
|
|
|
> struct EndianSwap;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSwap<T, 2, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const {
|
2015-06-27 01:38:58 +00:00
|
|
|
union { T iv; uint16_t sv; } u;
|
|
|
|
u.iv = v;
|
|
|
|
u.sv = octa::endian_swap16(u.sv);
|
|
|
|
return u.iv;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSwap<T, 4, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const {
|
2015-06-27 01:38:58 +00:00
|
|
|
union { T iv; uint32_t sv; } u;
|
|
|
|
u.iv = v;
|
|
|
|
u.sv = octa::endian_swap32(u.sv);
|
|
|
|
return u.iv;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSwap<T, 8, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const {
|
2015-06-27 01:38:58 +00:00
|
|
|
union { T iv; uint64_t sv; } u;
|
|
|
|
u.iv = v;
|
|
|
|
u.sv = octa::endian_swap64(u.sv);
|
|
|
|
return u.iv;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T endian_swap(T x) { return EndianSwap<T>()(x); }
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
template<typename T, octa::Size N = sizeof(T),
|
|
|
|
bool IsNum = octa::IsArithmetic<T>::value
|
|
|
|
> struct EndianSame;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSame<T, 2, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const { return v; }
|
2015-06-27 01:38:58 +00:00
|
|
|
};
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSame<T, 4, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const { return v; }
|
2015-06-27 01:38:58 +00:00
|
|
|
};
|
|
|
|
template<typename T>
|
|
|
|
struct EndianSame<T, 8, true> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = T;
|
2015-06-27 01:59:54 +00:00
|
|
|
T operator()(T v) const { return v; }
|
2015-06-27 01:38:58 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#if OCTA_BYTE_ORDER == OCTA_ENDIAN_LIL
|
2015-06-27 01:49:56 +00:00
|
|
|
template<typename T> struct FromLilEndian: octa::detail::EndianSame<T> {};
|
|
|
|
template<typename T> struct FromBigEndian: EndianSwap<T> {};
|
2015-06-27 01:38:58 +00:00
|
|
|
#else
|
2015-06-27 01:49:56 +00:00
|
|
|
template<typename T> struct FromLilEndian: EndianSwap<T> {};
|
|
|
|
template<typename T> struct FromBigEndian: octa::detail::EndianSame<T> {};
|
2015-06-27 01:38:58 +00:00
|
|
|
#endif
|
|
|
|
|
2015-06-27 01:49:56 +00:00
|
|
|
template<typename T> T from_lil_endian(T x) { return FromLilEndian<T>()(x); }
|
|
|
|
template<typename T> T from_big_endian(T x) { return FromBigEndian<T>()(x); }
|
2015-06-27 01:38:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
/* hash */
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<typename T> struct ToHash {
|
2015-06-28 20:28:29 +00:00
|
|
|
using Argument = T;
|
2015-06-14 01:36:20 +00:00
|
|
|
using Result = octa::Size;
|
2015-06-09 17:58:21 +00:00
|
|
|
|
|
|
|
octa::Size operator()(const T &v) const {
|
|
|
|
return v.to_hash();
|
|
|
|
}
|
|
|
|
};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
namespace detail {
|
2015-06-09 17:58:21 +00:00
|
|
|
template<typename T> struct ToHashBase {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
return octa::Size(v);
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
#define OCTA_HASH_BASIC(T) template<> struct ToHash<T>: octa::detail::ToHashBase<T> {};
|
2015-06-03 22:27:09 +00:00
|
|
|
|
|
|
|
OCTA_HASH_BASIC(bool)
|
|
|
|
OCTA_HASH_BASIC(char)
|
|
|
|
OCTA_HASH_BASIC(short)
|
|
|
|
OCTA_HASH_BASIC(int)
|
|
|
|
OCTA_HASH_BASIC(long)
|
2015-06-08 20:20:12 +00:00
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
OCTA_HASH_BASIC(octa::sbyte)
|
|
|
|
OCTA_HASH_BASIC(octa::byte)
|
2015-06-08 20:20:12 +00:00
|
|
|
OCTA_HASH_BASIC(octa::ushort)
|
|
|
|
OCTA_HASH_BASIC(octa::uint)
|
|
|
|
OCTA_HASH_BASIC(octa::ulong)
|
|
|
|
|
|
|
|
OCTA_HASH_BASIC(octa::Char16)
|
|
|
|
OCTA_HASH_BASIC(octa::Char32)
|
|
|
|
OCTA_HASH_BASIC(octa::Wchar)
|
2015-06-03 22:27:09 +00:00
|
|
|
|
|
|
|
#undef OCTA_HASH_BASIC
|
|
|
|
|
|
|
|
namespace detail {
|
2015-06-08 20:20:12 +00:00
|
|
|
static inline Size mem_hash(const void *p, octa::Size l) {
|
2015-06-30 22:07:28 +00:00
|
|
|
const octa::byte *d = (const octa::byte *)p;
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size h = 5381;
|
|
|
|
for (Size i = 0; i < l; ++i) h = ((h << 5) + h) ^ d[i];
|
2015-06-03 22:27:09 +00:00
|
|
|
return h;
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
template<typename T, octa::Size = sizeof(T) / sizeof(octa::Size)>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct ScalarHash;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ScalarHash<T, 0> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
union { T v; octa::Size h; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.h = 0;
|
|
|
|
u.v = v;
|
|
|
|
return u.h;
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ScalarHash<T, 1> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
union { T v; octa::Size h; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.v = v;
|
|
|
|
return u.h;
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ScalarHash<T, 2> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
union { T v; struct { octa::Size h1, h2; }; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.v = v;
|
|
|
|
return mem_hash((const void *)&u, sizeof(u));
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ScalarHash<T, 3> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
union { T v; struct { octa::Size h1, h2, h3; }; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.v = v;
|
|
|
|
return mem_hash((const void *)&u, sizeof(u));
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ScalarHash<T, 4> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
2015-06-08 20:20:12 +00:00
|
|
|
using Result = octa::Size;
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(T v) const {
|
|
|
|
union { T v; struct { octa::Size h1, h2, h3, h4; }; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.v = v;
|
|
|
|
return mem_hash((const void *)&u, sizeof(u));
|
2015-05-10 20:57:52 +00:00
|
|
|
}
|
|
|
|
};
|
2015-06-03 22:27:09 +00:00
|
|
|
} /* namespace detail */
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<> struct ToHash<octa::llong>: octa::detail::ScalarHash<octa::llong> {};
|
|
|
|
template<> struct ToHash<octa::ullong>: octa::detail::ScalarHash<octa::ullong> {};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<> struct ToHash<float>: octa::detail::ScalarHash<float> {
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(float v) const {
|
2015-06-03 22:27:09 +00:00
|
|
|
if (v == 0) return 0;
|
|
|
|
return octa::detail::ScalarHash<float>::operator()(v);
|
|
|
|
}
|
|
|
|
};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<> struct ToHash<double>: octa::detail::ScalarHash<double> {
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(double v) const {
|
2015-06-03 22:27:09 +00:00
|
|
|
if (v == 0) return 0;
|
|
|
|
return octa::detail::ScalarHash<double>::operator()(v);
|
|
|
|
}
|
|
|
|
};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<> struct ToHash<octa::ldouble>: octa::detail::ScalarHash<octa::ldouble> {
|
2015-06-08 20:20:12 +00:00
|
|
|
octa::Size operator()(octa::ldouble v) const {
|
2015-06-03 22:27:09 +00:00
|
|
|
if (v == 0) return 0;
|
2015-05-10 20:57:52 +00:00
|
|
|
#ifdef __i386__
|
2015-06-08 20:20:12 +00:00
|
|
|
union { octa::ldouble v; struct { octa::Size h1, h2, h3, h4; }; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.h1 = u.h2 = u.h3 = u.h4 = 0;
|
|
|
|
u.v = v;
|
|
|
|
return (u.h1 ^ u.h2 ^ u.h3 ^ u.h4);
|
2015-05-10 20:57:52 +00:00
|
|
|
#else
|
|
|
|
#ifdef __x86_64__
|
2015-06-08 20:20:12 +00:00
|
|
|
union { octa::ldouble v; struct { octa::Size h1, h2; }; } u;
|
2015-06-03 22:27:09 +00:00
|
|
|
u.h1 = u.h2 = 0;
|
|
|
|
u.v = v;
|
|
|
|
return (u.h1 ^ u.h2);
|
2015-05-10 20:57:52 +00:00
|
|
|
#else
|
2015-06-08 20:20:12 +00:00
|
|
|
return octa::detail::ScalarHash<octa::ldouble>::operator()(v);
|
2015-05-10 20:57:52 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
|
|
|
};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-30 22:30:48 +00:00
|
|
|
namespace detail {
|
|
|
|
template<typename T, bool = octa::IsSame<octa::RemoveConst<T>, char>::value>
|
|
|
|
struct ToHashPtr {
|
|
|
|
using Argument = T *;
|
|
|
|
using Result = octa::Size;
|
|
|
|
octa::Size operator()(T *v) const {
|
|
|
|
union { T *v; octa::Size h; } u;
|
|
|
|
u.v = v;
|
|
|
|
return octa::detail::mem_hash((const void *)&u, sizeof(u));
|
|
|
|
}
|
|
|
|
};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-30 22:30:48 +00:00
|
|
|
template<typename T> struct ToHashPtr<T, true> {
|
|
|
|
using Argument = T *;
|
|
|
|
using Result = octa::Size;
|
|
|
|
octa::Size operator()(T *v) const {
|
|
|
|
return octa::detail::mem_hash(v, strlen(v));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> struct ToHash<T *>: octa::detail::ToHashPtr<T> {};
|
2015-05-10 20:57:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
template<typename T>
|
2015-06-30 22:30:48 +00:00
|
|
|
typename ToHash<T>::Result to_hash(const T &v) {
|
|
|
|
return ToHash<T>()(v);
|
2015-06-09 17:58:21 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
/* reference wrapper */
|
2015-04-24 17:16:35 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct ReferenceWrapper {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = T;
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
ReferenceWrapper(T &v): p_ptr(address_of(v)) {}
|
2015-06-03 22:27:09 +00:00
|
|
|
ReferenceWrapper(const ReferenceWrapper &) = default;
|
2015-06-04 21:57:06 +00:00
|
|
|
ReferenceWrapper(T &&) = delete;
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
ReferenceWrapper &operator=(const ReferenceWrapper &) = default;
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
operator T &() const { return *p_ptr; }
|
|
|
|
T &get() const { return *p_ptr; }
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
private:
|
2015-06-04 21:57:06 +00:00
|
|
|
T *p_ptr;
|
2015-06-03 22:27:09 +00:00
|
|
|
};
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
ReferenceWrapper<T> ref(T &v) {
|
|
|
|
return ReferenceWrapper<T>(v);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
ReferenceWrapper<T> ref(ReferenceWrapper<T> v) {
|
|
|
|
return ReferenceWrapper<T>(v);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> void ref(const T &&) = delete;
|
2015-04-18 18:02:44 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
ReferenceWrapper<const T> cref(const T &v) {
|
|
|
|
return ReferenceWrapper<T>(v);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
ReferenceWrapper<const T> cref(ReferenceWrapper<T> v) {
|
|
|
|
return ReferenceWrapper<T>(v);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> void cref(const T &&) = delete;
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
/* mem_fn */
|
2015-04-22 22:25:02 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
namespace detail {
|
|
|
|
template<typename, typename> struct MemTypes;
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T, typename R, typename ...A>
|
|
|
|
struct MemTypes<T, R(A...)> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using Argument = T;
|
2015-06-01 23:57:34 +00:00
|
|
|
};
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T, typename R, typename A>
|
|
|
|
struct MemTypes<T, R(A)> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using FirstArgument = T;
|
|
|
|
using SecondArgument = A;
|
2015-06-01 23:57:34 +00:00
|
|
|
};
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T, typename R, typename ...A>
|
|
|
|
struct MemTypes<T, R(A...) const> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using Argument = const T;
|
2015-06-01 23:57:34 +00:00
|
|
|
};
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T, typename R, typename A>
|
|
|
|
struct MemTypes<T, R(A) const> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using FirstArgument = const T;
|
|
|
|
using SecondArgument = A;
|
2015-06-01 23:57:34 +00:00
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R, typename T>
|
|
|
|
class MemFn: MemTypes<T, R> {
|
|
|
|
R T::*p_ptr;
|
2015-04-24 17:16:35 +00:00
|
|
|
public:
|
2015-06-04 21:57:06 +00: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 17:16:35 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00: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 17:16:35 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00: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 17:16:35 +00:00
|
|
|
}
|
2015-06-04 21:57:06 +00: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 17:16:35 +00:00
|
|
|
}
|
|
|
|
};
|
2015-06-03 22:27:09 +00:00
|
|
|
} /* namespace detail */
|
2015-04-24 17:16:35 +00:00
|
|
|
|
2015-06-04 21:57:06 +00: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-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 22:25:02 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
/* function impl
|
|
|
|
* reference: http://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction
|
|
|
|
*/
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
template<typename> struct Function;
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
namespace detail {
|
|
|
|
struct FunctorData {
|
|
|
|
void *p1, *p2;
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct FunctorInPlace {
|
2015-06-04 21:57:06 +00:00
|
|
|
static constexpr bool value = sizeof(T) <= sizeof(FunctorData)
|
|
|
|
&& (alignof(FunctorData) % alignof(T)) == 0
|
|
|
|
&& octa::IsMoveConstructible<T>::value;
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
struct FunctionManager;
|
|
|
|
|
|
|
|
struct FmStorage {
|
|
|
|
FunctorData data;
|
|
|
|
const FunctionManager *manager;
|
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
A &get_alloc() {
|
2015-06-07 17:30:28 +00:00
|
|
|
union {
|
|
|
|
const FunctionManager **m;
|
|
|
|
A *alloc;
|
|
|
|
} u;
|
|
|
|
u.m = &manager;
|
|
|
|
return *u.alloc;
|
2015-06-07 00:14:04 +00:00
|
|
|
}
|
|
|
|
template<typename A>
|
|
|
|
const A &get_alloc() const {
|
2015-06-07 17:30:28 +00:00
|
|
|
union {
|
|
|
|
const FunctionManager * const *m;
|
|
|
|
const A *alloc;
|
|
|
|
} u;
|
|
|
|
u.m = &manager;
|
|
|
|
return *u.alloc;
|
2015-06-07 00:14:04 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, typename A, typename E = void>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct FunctorDataManager {
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename R, typename ...Args>
|
|
|
|
static R call(const FunctorData &s, Args ...args) {
|
|
|
|
return ((T &)s)(octa::forward<Args>(args)...);
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static void store_f(FmStorage &s, T v) {
|
2015-06-04 21:57:06 +00:00
|
|
|
new (&get_ref(s)) T(octa::forward<T>(v));
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
|
2015-06-04 21:57:06 +00:00
|
|
|
new (&get_ref(lhs)) T(octa::move(get_ref(rhs)));
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static void destroy_f(A &, FmStorage &s) {
|
2015-06-04 21:57:06 +00:00
|
|
|
get_ref(s).~T();
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static T &get_ref(const FmStorage &s) {
|
2015-06-07 17:30:28 +00:00
|
|
|
union {
|
|
|
|
const FunctorData *data;
|
|
|
|
T *ret;
|
|
|
|
} u;
|
|
|
|
u.data = &s.data;
|
|
|
|
return *u.ret;
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
|
|
|
struct FunctorDataManager<T, A,
|
2015-06-04 21:57:06 +00:00
|
|
|
EnableIf<!FunctorInPlace<T>::value>
|
2015-06-03 22:27:09 +00:00
|
|
|
> {
|
2015-06-07 00:14:04 +00: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 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00: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 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static void move_f(FmStorage &lhs, FmStorage &&rhs) {
|
|
|
|
new (&get_ptr_ref(lhs)) AllocatorPointer<A>(octa::move(
|
|
|
|
get_ptr_ref(rhs)));
|
2015-06-03 22:27:09 +00:00
|
|
|
get_ptr_ref(rhs) = nullptr;
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static void destroy_f(A &a, FmStorage &s) {
|
|
|
|
AllocatorPointer<A> &ptr = get_ptr_ref(s);
|
2015-06-03 22:27:09 +00:00
|
|
|
if (!ptr) return;
|
2015-06-07 00:14:04 +00:00
|
|
|
allocator_destroy(a, ptr);
|
|
|
|
allocator_deallocate(a, ptr, 1);
|
2015-06-03 22:27:09 +00:00
|
|
|
ptr = nullptr;
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static T &get_ref(const FmStorage &s) {
|
2015-06-03 22:27:09 +00:00
|
|
|
return *get_ptr_ref(s);
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static AllocatorPointer<A> &get_ptr_ref(FmStorage &s) {
|
|
|
|
return (AllocatorPointer<A> &)(s.data);
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static AllocatorPointer<A> &get_ptr_ref(const FmStorage &s) {
|
|
|
|
return (AllocatorPointer<A> &)(s.data);
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:27:09 +00:00
|
|
|
static const FunctionManager &get_default_fm();
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00: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-03 22:27:09 +00:00
|
|
|
struct FunctionManager {
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
|
|
|
inline static constexpr FunctionManager create_default_manager() {
|
2015-06-03 22:27:09 +00:00
|
|
|
return FunctionManager {
|
2015-06-07 00:14:04 +00:00
|
|
|
&call_move_and_destroy<T, A>,
|
|
|
|
&call_copy<T, A>,
|
|
|
|
&call_copy_fo<T, A>,
|
|
|
|
&call_destroy<T, A>
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
void (* const call_move_and_destroyf)(FmStorage &lhs,
|
|
|
|
FmStorage &&rhs);
|
|
|
|
void (* const call_copyf)(FmStorage &lhs,
|
|
|
|
const FmStorage &rhs);
|
2015-06-07 00:14:04 +00:00
|
|
|
void (* const call_copyf_fo)(FmStorage &lhs,
|
|
|
|
const FmStorage &rhs);
|
2015-06-03 22:27:09 +00:00
|
|
|
void (* const call_destroyf)(FmStorage &s);
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:27:09 +00:00
|
|
|
static void call_move_and_destroy(FmStorage &lhs,
|
|
|
|
FmStorage &&rhs) {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Spec = FunctorDataManager<T, A>;
|
|
|
|
Spec::move_f(lhs, octa::move(rhs));
|
|
|
|
Spec::destroy_f(rhs.get_alloc<A>(), rhs);
|
2015-06-07 00:14:04 +00:00
|
|
|
create_fm<T, A>(lhs, octa::move(rhs.get_alloc<A>()));
|
|
|
|
rhs.get_alloc<A>().~A();
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:27:09 +00:00
|
|
|
static void call_copy(FmStorage &lhs,
|
|
|
|
const FmStorage &rhs) {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Spec = FunctorDataManager<T, A>;
|
2015-06-07 00:14:04 +00:00
|
|
|
create_fm<T, A>(lhs, A(rhs.get_alloc<A>()));
|
2015-06-07 23:55:08 +00:00
|
|
|
Spec::store_f(lhs, Spec::get_ref(rhs));
|
2015-06-07 00:14:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
|
|
|
static void call_copy_fo(FmStorage &lhs,
|
|
|
|
const FmStorage &rhs) {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Spec = FunctorDataManager<T, A>;
|
|
|
|
Spec::store_f(lhs, Spec::get_ref(rhs));
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:27:09 +00:00
|
|
|
static void call_destroy(FmStorage &s) {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Spec = FunctorDataManager<T, A>;
|
|
|
|
Spec::destroy_f(s.get_alloc<A>(), s);
|
2015-06-07 00:14:04 +00:00
|
|
|
s.get_alloc<A>().~A();
|
2015-04-22 17:42:58 +00:00
|
|
|
}
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:27:09 +00:00
|
|
|
inline static const FunctionManager &get_default_fm() {
|
|
|
|
static const FunctionManager def_manager
|
2015-06-07 00:14:04 +00:00
|
|
|
= FunctionManager::create_default_manager<T, A>();
|
2015-06-03 22:27:09 +00:00
|
|
|
return def_manager;
|
2015-04-24 17:16:35 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R, typename...>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct FunctionBase {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R, typename T>
|
|
|
|
struct FunctionBase<R, T> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using Argument = T;
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R, typename T, typename U>
|
|
|
|
struct FunctionBase<R, T, U> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = R;
|
|
|
|
using FirstArgument = T;
|
|
|
|
using SecondArgument = U;
|
2015-04-24 17:16:35 +00:00
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-05-03 15:09:47 +00:00
|
|
|
template<typename, typename>
|
2015-06-03 22:27:09 +00:00
|
|
|
struct IsValidFunctor {
|
2015-05-03 15:09:47 +00:00
|
|
|
static constexpr bool value = false;
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R, typename ...A>
|
|
|
|
struct IsValidFunctor<Function<R(A...)>, R(A...)> {
|
2015-05-03 15:09:47 +00:00
|
|
|
static constexpr bool value = false;
|
|
|
|
};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
T func_to_functor(T &&f) {
|
|
|
|
return octa::forward<T>(f);
|
2015-05-03 15:09:47 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename RR, typename T, typename ...AA>
|
|
|
|
auto func_to_functor(RR (T::*f)(AA...))
|
2015-06-03 22:27:09 +00:00
|
|
|
-> decltype(mem_fn(f)) {
|
|
|
|
return mem_fn(f);
|
2015-05-03 15:09:47 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename RR, typename T, typename ...AA>
|
|
|
|
auto func_to_functor(RR (T::*f)(AA...) const)
|
2015-06-03 22:27:09 +00:00
|
|
|
-> decltype(mem_fn(f)) {
|
|
|
|
return mem_fn(f);
|
2015-05-03 15:09:47 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T, typename R, typename ...A>
|
|
|
|
struct IsValidFunctor<T, R(A...)> {
|
2015-06-06 23:03:06 +00:00
|
|
|
struct Nat {};
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename U>
|
|
|
|
static decltype(func_to_functor(octa::declval<U>())
|
|
|
|
(octa::declval<A>()...)) test(U *);
|
2015-05-03 15:09:47 +00:00
|
|
|
template<typename>
|
2015-06-06 23:03:06 +00:00
|
|
|
static Nat test(...);
|
2015-05-03 15:09:47 +00:00
|
|
|
|
2015-06-01 23:57:34 +00:00
|
|
|
static constexpr bool value = octa::IsConvertible<
|
2015-06-04 21:57:06 +00:00
|
|
|
decltype(test<T>(nullptr)), R
|
2015-05-03 15:09:47 +00:00
|
|
|
>::value;
|
|
|
|
};
|
2015-06-07 00:14:04 +00:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
using FunctorType = decltype(func_to_functor(octa::declval<T>()));
|
2015-06-03 22:27:09 +00:00
|
|
|
} /* namespace detail */
|
2015-05-03 15:09:47 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename R, typename ...Args>
|
|
|
|
struct Function<R(Args...)>: octa::detail::FunctionBase<R, Args...> {
|
2015-06-08 20:20:12 +00:00
|
|
|
Function( ) { init_empty(); }
|
|
|
|
Function(octa::Nullptr) { init_empty(); }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
Function(Function &&f) {
|
|
|
|
init_empty();
|
|
|
|
swap(f);
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
Function(const Function &f): p_call(f.p_call) {
|
|
|
|
f.p_stor.manager->call_copyf(p_stor, f.p_stor);
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-29 20:56:13 +00:00
|
|
|
template<typename T, typename = octa::EnableIf<
|
|
|
|
octa::detail::IsValidFunctor<T, R(Args...)>::value
|
|
|
|
>> Function(T f) {
|
2015-06-07 00:14:04 +00:00
|
|
|
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>
|
2015-06-08 20:20:12 +00:00
|
|
|
Function(octa::AllocatorArg, const A &, octa::Nullptr) { init_empty(); }
|
2015-06-07 00:14:04 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-06-07 23:55:08 +00:00
|
|
|
using AA = AllocatorRebind<A, Function>;
|
2015-06-07 00:14:04 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2015-06-29 20:56:13 +00:00
|
|
|
template<typename A, typename T, typename = octa::EnableIf<
|
|
|
|
octa::detail::IsValidFunctor<T, R(Args...)>::value
|
|
|
|
>> Function(octa::AllocatorArg, const A &a, T f) {
|
2015-06-03 22:27:09 +00:00
|
|
|
if (func_is_null(f)) {
|
|
|
|
init_empty();
|
|
|
|
return;
|
|
|
|
}
|
2015-06-07 00:14:04 +00:00
|
|
|
initialize(octa::detail::func_to_functor(octa::forward<T>(f)), A(a));
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
~Function() {
|
|
|
|
p_stor.manager->call_destroyf(p_stor);
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
Function &operator=(Function &&f) {
|
|
|
|
p_stor.manager->call_destroyf(p_stor);
|
|
|
|
swap(f);
|
|
|
|
return *this;
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
Function &operator=(const Function &f) {
|
|
|
|
p_stor.manager->call_destroyf(p_stor);
|
2015-06-07 00:14:04 +00:00
|
|
|
swap(Function(f));
|
2015-06-03 22:27:09 +00:00
|
|
|
return *this;
|
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
R operator()(Args ...args) const {
|
|
|
|
return p_call(p_stor.data, octa::forward<Args>(args)...);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00: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-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00: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-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
operator bool() const { return p_call != nullptr; }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
private:
|
|
|
|
octa::detail::FmStorage p_stor;
|
2015-06-07 00:14:04 +00:00
|
|
|
R (*p_call)(const octa::detail::FunctorData &, Args...);
|
2015-06-04 21:57:06 +00:00
|
|
|
|
2015-06-07 00:14:04 +00: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 21:57:06 +00:00
|
|
|
octa::forward<T>(f));
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
void init_empty() {
|
2015-06-07 23:55:08 +00:00
|
|
|
using emptyf = R(*)(Args...);
|
|
|
|
using emptya = octa::Allocator<emptyf>;
|
2015-06-03 22:27:09 +00:00
|
|
|
p_call = nullptr;
|
2015-06-07 00:14:04 +00:00
|
|
|
octa::detail::create_fm<emptyf, emptya>(p_stor, emptya());
|
|
|
|
octa::detail::FunctorDataManager<emptyf, emptya>::store_f(p_stor,
|
|
|
|
nullptr);
|
2015-06-03 22:27:09 +00:00
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
static bool func_is_null(const T &) { return false; }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
static bool func_is_null(R (* const &fptr)(Args...)) {
|
2015-06-03 22:27:09 +00:00
|
|
|
return fptr == nullptr;
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename RR, typename T, typename ...AArgs>
|
|
|
|
static bool func_is_null(RR (T::* const &fptr)(AArgs...)) {
|
2015-06-03 22:27:09 +00:00
|
|
|
return fptr == nullptr;
|
|
|
|
}
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-07 00:14:04 +00:00
|
|
|
template<typename RR, typename T, typename ...AArgs>
|
|
|
|
static bool func_is_null(RR (T::* const &fptr)(AArgs...) const) {
|
2015-06-03 22:27:09 +00:00
|
|
|
return fptr == nullptr;
|
|
|
|
}
|
|
|
|
};
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-08 20:20:12 +00:00
|
|
|
bool operator==(octa::Nullptr, const Function<T> &rhs) { return !rhs; }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-08 20:20:12 +00:00
|
|
|
bool operator==(const Function<T> &lhs, octa::Nullptr) { return !lhs; }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-08 20:20:12 +00:00
|
|
|
bool operator!=(octa::Nullptr, const Function<T> &rhs) { return rhs; }
|
2015-04-22 17:42:58 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-06-08 20:20:12 +00:00
|
|
|
bool operator!=(const Function<T> &lhs, octa::Nullptr) { return lhs; }
|
2015-06-03 22:27:09 +00:00
|
|
|
|
2015-06-07 17:06:29 +00: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 23:55:08 +00:00
|
|
|
using Ptr = R (*)(A...);
|
|
|
|
using Obj = octa::Function<R(A...)>;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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 {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = typename DcLambdaTypes<F>::Obj;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename F>
|
|
|
|
struct DcFuncTypeObjBase<F, true> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = typename DcLambdaTypes<F>::Ptr;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename F, bool = octa::IsDefaultConstructible<F>::value &&
|
|
|
|
octa::IsMoveConstructible<F>::value
|
|
|
|
> struct DcFuncTypeObj {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = typename DcFuncTypeObjBase<F>::Type;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename F>
|
|
|
|
struct DcFuncTypeObj<F, true> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = F;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename F, bool = octa::IsClass<F>::value>
|
|
|
|
struct DcFuncType {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = F;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename F>
|
|
|
|
struct DcFuncType<F, true> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Type = typename DcFuncTypeObj<F>::Type;
|
2015-06-07 17:06:29 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename F> using FunctionMakeDefaultConstructible
|
|
|
|
= typename octa::detail::DcFuncType<F>::Type;
|
|
|
|
|
2015-06-03 22:27:09 +00:00
|
|
|
} /* namespace octa */
|
2015-04-18 01:35:36 +00:00
|
|
|
|
|
|
|
#endif
|