/* Function objects for OctaSTD. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_FUNCTIONAL_HH #define OSTD_FUNCTIONAL_HH #include #include #include #include #include "ostd/platform.hh" #include "ostd/memory.hh" #include "ostd/utility.hh" #include "ostd/type_traits.hh" namespace ostd { /* basic function objects */ #define OSTD_DEFINE_BINARY_OP(name, op, RT) \ template \ struct name { \ RT operator()(T const &x, T const &y) const { \ return x op y; \ } \ using FirstArgument = T; \ using SecondARgument = T; \ using Result = RT; \ }; OSTD_DEFINE_BINARY_OP(Less, <, bool) OSTD_DEFINE_BINARY_OP(LessEqual, <=, bool) OSTD_DEFINE_BINARY_OP(Greater, >, bool) OSTD_DEFINE_BINARY_OP(GreaterEqual, >=, bool) OSTD_DEFINE_BINARY_OP(Equal, ==, bool) OSTD_DEFINE_BINARY_OP(NotEqual, !=, bool) OSTD_DEFINE_BINARY_OP(LogicalAnd, &&, bool) OSTD_DEFINE_BINARY_OP(LogicalOr, ||, bool) OSTD_DEFINE_BINARY_OP(Modulo, %, T) OSTD_DEFINE_BINARY_OP(Multiply, *, T) OSTD_DEFINE_BINARY_OP(Divide, /, T) OSTD_DEFINE_BINARY_OP(Add, +, T) OSTD_DEFINE_BINARY_OP(Subtract, -, T) OSTD_DEFINE_BINARY_OP(BitAnd, &, T) OSTD_DEFINE_BINARY_OP(BitOr, |, T) OSTD_DEFINE_BINARY_OP(BitXor, ^, T) #undef OSTD_DEFINE_BINARY_OP namespace detail { template, char>> struct CharEqual { using FirstArgument = T *; using SecondArgument = T *; using Result = bool; bool operator()(T *x, T *y) const { return !strcmp(x, y); } }; template struct CharEqual { using FirstArgument = T *; using SecondArgument = T *; using Result = bool; bool operator()(T *x, T *y) const { return x == y; } }; } template struct EqualWithCstr { using FirstArgument = T; using SecondArgument = T; bool operator()(T const &x, T const &y) const { return x == y; } }; template struct EqualWithCstr: detail::CharEqual {}; template struct LogicalNot { bool operator()(T const &x) const { return !x; } using Argument = T; using Result = bool; }; template struct Negate { bool operator()(T const &x) const { return -x; } using Argument = T; using Result = T; }; template struct BinaryNegate { using FirstArgument = typename T::FirstArgument; using SecondArgument = typename T::SecondArgument; using Result = bool; explicit BinaryNegate(T const &f): p_fn(f) {} bool operator()(FirstArgument const &x, SecondArgument const &y) { return !p_fn(x, y); } private: T p_fn; }; template struct UnaryNegate { using Argument = typename T::Argument; using Result = bool; explicit UnaryNegate(T const &f): p_fn(f) {} bool operator()(Argument const &x) { return !p_fn(x); } private: T p_fn; }; template UnaryNegate not1(T const &fn) { return UnaryNegate(fn); } template BinaryNegate not2(T const &fn) { return BinaryNegate(fn); } /* endian swap */ template> struct EndianSwap; template struct EndianSwap { using Argument = T; using Result = T; T operator()(T v) const { union { T iv; uint16_t sv; } u; u.iv = v; u.sv = endian_swap16(u.sv); return u.iv; } }; template struct EndianSwap { using Argument = T; using Result = T; T operator()(T v) const { union { T iv; uint32_t sv; } u; u.iv = v; u.sv = endian_swap32(u.sv); return u.iv; } }; template struct EndianSwap { using Argument = T; using Result = T; T operator()(T v) const { union { T iv; uint64_t sv; } u; u.iv = v; u.sv = endian_swap64(u.sv); return u.iv; } }; template T endian_swap(T x) { return EndianSwap()(x); } namespace detail { template> struct EndianSame; template struct EndianSame { using Argument = T; using Result = T; T operator()(T v) const { return v; } }; template struct EndianSame { using Argument = T; using Result = T; T operator()(T v) const { return v; } }; template struct EndianSame { using Argument = T; using Result = T; T operator()(T v) const { return v; } }; } #if OSTD_BYTE_ORDER == OSTD_ENDIAN_LIL template struct FromLilEndian: detail::EndianSame {}; template struct FromBigEndian: EndianSwap {}; #else template struct FromLilEndian: EndianSwap {}; template struct FromBigEndian: detail::EndianSame {}; #endif template T from_lil_endian(T x) { return FromLilEndian()(x); } template T from_big_endian(T x) { return FromBigEndian()(x); } /* hash */ template struct ToHash { using Argument = T; using Result = Size; Size operator()(T const &v) const { return v.to_hash(); } }; namespace detail { template struct ToHashBase { using Argument = T; using Result = Size; Size operator()(T v) const { return Size(v); } }; } #define OSTD_HASH_BASIC(T) \ template<> \ struct ToHash: detail::ToHashBase {}; OSTD_HASH_BASIC(bool) OSTD_HASH_BASIC(char) OSTD_HASH_BASIC(short) OSTD_HASH_BASIC(int) OSTD_HASH_BASIC(long) OSTD_HASH_BASIC(sbyte) OSTD_HASH_BASIC(byte) OSTD_HASH_BASIC(ushort) OSTD_HASH_BASIC(uint) OSTD_HASH_BASIC(ulong) #ifndef OSTD_TYPES_CHAR_16_32_NO_BUILTINS OSTD_HASH_BASIC(Char16) OSTD_HASH_BASIC(Char32) #endif OSTD_HASH_BASIC(Wchar) #undef OSTD_HASH_BASIC namespace detail { template struct FnvConstants { static constexpr Size prime = 16777619u; static constexpr Size offset = 2166136261u; }; template<> struct FnvConstants<8> { /* conversion is necessary here because when compiling on * 32bit, compilers will complain, despite this template * not being instantiated... */ static constexpr Size prime = Size(1099511628211u); static constexpr Size offset = Size(14695981039346656037u); }; inline Size mem_hash(void const *p, Size l) { using Consts = FnvConstants; byte const *d = static_cast(p); Size h = Consts::offset; for (byte const *it = d, *end = d + l; it != end; ++it) { h ^= *it; h *= Consts::prime; } return h; } template struct ScalarHash; template struct ScalarHash { using Argument = T; using Result = Size; Size operator()(T v) const { union { T v; Size h; } u; u.h = 0; u.v = v; return u.h; } }; template struct ScalarHash { using Argument = T; using Result = Size; Size operator()(T v) const { union { T v; Size h; } u; u.v = v; return u.h; } }; template struct ScalarHash { using Argument = T; using Result = Size; Size operator()(T v) const { union { T v; struct { Size h1, h2; }; } u; u.v = v; return mem_hash(static_cast(&u), sizeof(u)); } }; template struct ScalarHash { using Argument = T; using Result = Size; Size operator()(T v) const { union { T v; struct { Size h1, h2, h3; }; } u; u.v = v; return mem_hash(static_cast(&u), sizeof(u)); } }; template struct ScalarHash { using Argument = T; using Result = Size; Size operator()(T v) const { union { T v; struct { Size h1, h2, h3, h4; }; } u; u.v = v; return mem_hash(static_cast(&u), sizeof(u)); } }; } /* namespace detail */ template<> struct ToHash: detail::ScalarHash {}; template<> struct ToHash: detail::ScalarHash {}; template<> struct ToHash: detail::ScalarHash { Size operator()(float v) const { if (v == 0) return 0; return detail::ScalarHash::operator()(v); } }; template<> struct ToHash: detail::ScalarHash { Size operator()(double v) const { if (v == 0) return 0; return detail::ScalarHash::operator()(v); } }; template<> struct ToHash: detail::ScalarHash { Size operator()(ldouble v) const { if (v == 0) { return 0; } #ifdef __i386__ union { ldouble v; struct { Size 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 h1, h2; }; } u; u.h1 = u.h2 = 0; u.v = v; return (u.h1 ^ u.h2); #else return detail::ScalarHash::operator()(v); #endif #endif } }; namespace detail { template, char>> struct ToHashPtr { using Argument = T *; using Result = Size; Size operator()(T *v) const { union { T *v; Size h; } u; u.v = v; return detail::mem_hash(static_cast(&u), sizeof(u)); } }; template struct ToHashPtr { using Argument = T *; using Result = Size; Size operator()(T *v) const { return detail::mem_hash(v, strlen(v)); } }; } template struct ToHash: detail::ToHashPtr {}; template typename ToHash::Result to_hash(T const &v) { return ToHash()(v); } } /* namespace ostd */ #endif