/* 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" #include "octa/type_traits.h" namespace octa { /* basic function objects */ #define OCTA_DEFINE_BINARY_OP(_name, _op, _rettype) \ template struct _name { \ _rettype operator()(const _T &x, const _T &y) const { \ return x _op y; \ } \ typedef _T FirstArgument; \ typedef _T SecondArgument; \ 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) 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) #undef OCTA_DEFINE_BINARY_OP template struct LogicalNot { bool operator()(const _T &x) const { return !x; } typedef _T Argument; typedef bool Result; }; template struct Negate { bool operator()(const _T &x) const { return -x; } typedef _T Argument; typedef _T Result; }; template struct BinaryNegate { typedef typename _T::FirstArgument FirstArgument; typedef typename _T::SecondArgument SecondArgument; typedef bool Result; explicit BinaryNegate(const _T &f): p_fn(f) {} bool operator()(const FirstArgument &x, const SecondArgument &y) { return !p_fn(x, y); } private: _T p_fn; }; template struct UnaryNegate { typedef typename _T::Argument Argument; typedef bool Result; explicit UnaryNegate(const _T &f): p_fn(f) {} bool operator()(const Argument &x) { return !p_fn(x); } private: _T p_fn; }; template UnaryNegate<_T> not1(const _T &fn) { return UnaryNegate<_T>(fn); } template BinaryNegate<_T> not2(const _T &fn) { return BinaryNegate<_T>(fn); } /* hash */ template struct Hash; namespace detail { template struct HashBase { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { return size_t(v); } }; } #define OCTA_HASH_BASIC(_T) template<> struct Hash<_T>: octa::detail::HashBase<_T> {}; 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; } template struct ScalarHash; template struct ScalarHash<_T, 0> { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { union { _T v; size_t h; } u; u.h = 0; u.v = v; return u.h; } }; template struct ScalarHash<_T, 1> { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { union { _T v; size_t h; } u; u.v = v; return u.h; } }; template struct ScalarHash<_T, 2> { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { union { _T v; struct { size_t h1, h2; }; } u; u.v = v; return mem_hash((const void *)&u, sizeof(u)); } }; template struct ScalarHash<_T, 3> { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { union { _T v; struct { size_t h1, h2, h3; }; } u; u.v = v; return mem_hash((const void *)&u, sizeof(u)); } }; template struct ScalarHash<_T, 4> { typedef _T Argument; typedef size_t Result; size_t operator()(_T v) const { union { _T v; struct { size_t h1, h2, h3, h4; }; } u; u.v = v; return mem_hash((const void *)&u, sizeof(u)); } }; } /* namespace detail */ template<> struct Hash: octa::detail::ScalarHash {}; template<> struct Hash: octa::detail::ScalarHash {}; template<> struct Hash: octa::detail::ScalarHash { size_t operator()(float v) const { if (v == 0) return 0; return octa::detail::ScalarHash::operator()(v); } }; template<> struct Hash: octa::detail::ScalarHash { size_t operator()(double v) const { if (v == 0) return 0; return octa::detail::ScalarHash::operator()(v); } }; template<> struct Hash: octa::detail::ScalarHash { size_t operator()(ldouble v) const { if (v == 0) return 0; #ifdef __i386__ 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__ union { ldouble v; struct { size_t h1, h2; }; } u; u.h1 = u.h2 = 0; u.v = v; return (u.h1 ^ u.h2); #else return octa::detail::ScalarHash::operator()(v); #endif #endif } }; template struct Hash<_T *> { typedef _T *Argument; typedef size_t Result; size_t operator()(_T *v) const { union { _T *v; size_t h; } u; u.v = v; return octa::detail::mem_hash((const void *)&u, sizeof(u)); } }; /* reference wrapper */ template struct ReferenceWrapper { typedef _T type; ReferenceWrapper(_T &v): p_ptr(address_of(v)) {} ReferenceWrapper(const ReferenceWrapper &) = default; ReferenceWrapper(_T &&) = delete; ReferenceWrapper &operator=(const ReferenceWrapper &) = default; operator _T &() const { return *p_ptr; } _T &get() const { return *p_ptr; } private: _T *p_ptr; }; template ReferenceWrapper<_T> ref(_T &v) { return ReferenceWrapper<_T>(v); } template ReferenceWrapper<_T> ref(ReferenceWrapper<_T> v) { return ReferenceWrapper<_T>(v); } template void ref(const _T &&) = delete; template ReferenceWrapper cref(const _T &v) { return ReferenceWrapper<_T>(v); } template ReferenceWrapper cref(ReferenceWrapper<_T> v) { return ReferenceWrapper<_T>(v); } template void cref(const _T &&) = delete; /* mem_fn */ namespace detail { template struct MemTypes; template struct MemTypes<_T, _R(_A...)> { typedef _R Result; typedef _T Argument; }; template struct MemTypes<_T, _R(_A)> { typedef _R Result; typedef _T FirstArgument; typedef _A SecondArgument; }; template struct MemTypes<_T, _R(_A...) const> { typedef _R Result; typedef const _T Argument; }; template struct MemTypes<_T, _R(_A) const> { typedef _R Result; typedef const _T FirstArgument; typedef _A SecondArgument; }; template class MemFn: MemTypes<_T, _R> { _R _T::*p_ptr; public: MemFn(_R _T::*ptr): p_ptr(ptr) {} template auto operator()(_T &obj, _A &&...args) -> decltype(((obj).*(p_ptr))(forward<_A>(args)...)) { return ((obj).*(p_ptr))(forward<_A>(args)...); } template auto operator()(const _T &obj, _A &&...args) -> decltype(((obj).*(p_ptr))(forward<_A>(args)...)) const { return ((obj).*(p_ptr))(forward<_A>(args)...); } template auto operator()(_T *obj, _A &&...args) -> decltype(((obj)->*(p_ptr))(forward<_A>(args)...)) { return ((obj)->*(p_ptr))(forward<_A>(args)...); } template auto operator()(const _T *obj, _A &&...args) -> decltype(((obj)->*(p_ptr))(forward<_A>(args)...)) const { return ((obj)->*(p_ptr))(forward<_A>(args)...); } }; } /* namespace detail */ template octa::detail::MemFn<_R, _T> mem_fn(_R _T:: *ptr) { return octa::detail::MemFn<_R, _T>(ptr); } /* function impl * reference: http://probablydance.com/2013/01/13/a-faster-implementation-of-stdfunction */ template struct Function; namespace detail { struct FunctorData { void *p1, *p2; }; template struct FunctorInPlace { static constexpr bool value = sizeof(_T) <= sizeof(FunctorData) && (alignof(FunctorData) % alignof(_T)) == 0 && octa::IsMoveConstructible<_T>::value; }; template struct FunctorDataManager { template static _R call(const FunctorData &s, _A ...args) { return ((_T &)s)(octa::forward<_A>(args)...); } static void store_f(FunctorData &s, _T v) { new (&get_ref(s)) _T(octa::forward<_T>(v)); } static void move_f(FunctorData &lhs, FunctorData &&rhs) { new (&get_ref(lhs)) _T(octa::move(get_ref(rhs))); } static void destroy_f(FunctorData &s) { get_ref(s).~_T(); } static _T &get_ref(const FunctorData &s) { return (_T &)s; } }; template struct FunctorDataManager<_T, EnableIf::value> > { template static _R call(const FunctorData &s, _A ...args) { return (*(_T *&)s)(octa::forward<_A>(args)...); } static void store_f(FunctorData &s, _T v) { new (&get_ptr_ref(s)) _T *(new _T(octa::forward<_T>(v))); } static void move_f(FunctorData &lhs, FunctorData &&rhs) { new (&get_ptr_ref(lhs)) _T *(get_ptr_ref(rhs)); get_ptr_ref(rhs) = nullptr; } static void destroy_f(FunctorData &s) { _T *&ptr = get_ptr_ref(s); if (!ptr) return; delete ptr; ptr = nullptr; } static _T &get_ref(const FunctorData &s) { return *get_ptr_ref(s); } static _T *&get_ptr_ref(FunctorData &s) { return (_T *&)s; } static _T *&get_ptr_ref(const FunctorData &s) { return (_T *&)s; } }; struct FunctionManager; struct FmStorage { FunctorData data; const FunctionManager *manager; }; template static const FunctionManager &get_default_fm(); struct FunctionManager { template inline static const FunctionManager create_default_manager() { return FunctionManager { &call_move_and_destroy<_T>, &call_copy<_T>, &call_destroy<_T> }; } void (* const call_move_and_destroyf)(FmStorage &lhs, FmStorage &&rhs); void (* const call_copyf)(FmStorage &lhs, const FmStorage &rhs); void (* const call_destroyf)(FmStorage &s); template static void call_move_and_destroy(FmStorage &lhs, FmStorage &&rhs) { typedef FunctorDataManager<_T> _spec; _spec::move_f(lhs.data, octa::move(rhs.data)); _spec::destroy_f(rhs.data); lhs.manager = &get_default_fm<_T>(); } template static void call_copy(FmStorage &lhs, const FmStorage &rhs) { typedef FunctorDataManager<_T> _spec; lhs.manager = &get_default_fm<_T>(); _spec::store_f(lhs.data, _spec::get_ref(rhs.data)); } template static void call_destroy(FmStorage &s) { typedef FunctorDataManager<_T> _spec; _spec::destroy_f(s.data); } }; template inline static const FunctionManager &get_default_fm() { static const FunctionManager def_manager = FunctionManager::create_default_manager<_T>(); return def_manager; } template struct FunctionBase { typedef _R Result; }; template struct FunctionBase<_R, _T> { typedef _R Result; typedef _T Argument; }; template struct FunctionBase<_R, _T, _U> { typedef _R Result; typedef _T FirstArgument; typedef _U SecondArgument; }; template struct IsValidFunctor { static constexpr bool value = false; }; template struct IsValidFunctor, _R(_A...)> { static constexpr bool value = false; }; struct Empty { }; template _T func_to_functor(_T &&f) { return octa::forward<_T>(f); } template auto func_to_functor(_RR (_T::*f)(_AA...)) -> decltype(mem_fn(f)) { return mem_fn(f); } template auto func_to_functor(_RR (_T::*f)(_AA...) const) -> decltype(mem_fn(f)) { return mem_fn(f); } template struct IsValidFunctor<_T, _R(_A...)> { template static decltype(func_to_functor(octa::declval<_U>()) (octa::declval<_A>()...)) test(_U *); template static Empty test(...); static constexpr bool value = octa::IsConvertible< decltype(test<_T>(nullptr)), _R >::value; }; } /* namespace detail */ template struct Function<_R(_A...)>: octa::detail::FunctionBase<_R, _A...> { Function( ) { init_empty(); } Function(nullptr_t) { init_empty(); } Function(Function &&f) { init_empty(); swap(f); } Function(const Function &f): p_call(f.p_call) { f.p_stor.manager->call_copyf(p_stor, f.p_stor); } template Function(_T f, EnableIf< octa::detail::IsValidFunctor<_T, _R(_A...)>::value, octa::detail::Empty > = octa::detail::Empty()) { if (func_is_null(f)) { init_empty(); return; } initialize(octa::detail::func_to_functor(octa::forward<_T>(f))); } ~Function() { p_stor.manager->call_destroyf(p_stor); } Function &operator=(Function &&f) { p_stor.manager->call_destroyf(p_stor); swap(f); return *this; } Function &operator=(const Function &f) { p_stor.manager->call_destroyf(p_stor); f.p_stor.manager->call_copyf(p_stor, f.p_stor); return *this; }; _R operator()(_A ...args) const { return p_call(p_stor.data, octa::forward<_A>(args)...); } template void assign(_F &&f) { Function(octa::forward<_F>(f)).swap(*this); } 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); } operator bool() const { return p_call != nullptr; } private: octa::detail::FmStorage p_stor; _R (*p_call)(const octa::detail::FunctorData &, _A...); template void initialize(_T f) { p_call = &octa::detail::FunctorDataManager<_T>::template call<_R, _A...>; p_stor.manager = &octa::detail::get_default_fm<_T>(); octa::detail::FunctorDataManager<_T>::store_f(p_stor.data, octa::forward<_T>(f)); } void init_empty() { typedef _R(*emptyf)(_A...); p_call = nullptr; p_stor.manager = &octa::detail::get_default_fm(); octa::detail::FunctorDataManager::store_f(p_stor.data, nullptr); } template static bool func_is_null(const _T &) { return false; } static bool func_is_null(_R (* const &fptr)(_A...)) { return fptr == nullptr; } template static bool func_is_null(_RR (_T::* const &fptr)(_AA...)) { return fptr == nullptr; } template static bool func_is_null(_RR (_T::* const &fptr)(_AA...) const) { return fptr == nullptr; } }; template bool operator==(nullptr_t, const Function<_T> &rhs) { return !rhs; } template bool operator==(const Function<_T> &lhs, nullptr_t) { return !lhs; } template bool operator!=(nullptr_t, const Function<_T> &rhs) { return rhs; } template bool operator!=(const Function<_T> &lhs, nullptr_t) { return lhs; } } /* namespace octa */ #endif