libostd/ostd/functional.hh

445 lines
10 KiB
C++
Raw Normal View History

/* Function objects for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
2015-07-13 21:08:55 +02:00
#ifndef OSTD_FUNCTIONAL_HH
#define OSTD_FUNCTIONAL_HH
#include <string.h>
2017-01-14 15:09:27 +01:00
#include <new>
#include <functional>
2017-01-28 19:39:50 +01:00
#include <tuple>
2015-07-13 21:08:55 +02:00
#include "ostd/platform.hh"
#include "ostd/memory.hh"
#include "ostd/utility.hh"
#include "ostd/type_traits.hh"
2015-07-13 21:07:14 +02:00
namespace ostd {
2015-04-18 03:50:20 +02:00
2015-06-04 00:27:09 +02:00
/* basic function objects */
2015-07-13 21:08:55 +02:00
#define OSTD_DEFINE_BINARY_OP(name, op, RT) \
template<typename T> \
struct name { \
2016-06-23 20:18:35 +02:00
RT operator()(T const &x, T const &y) const { \
2015-06-08 01:55:08 +02:00
return x op y; \
2015-06-04 00:27:09 +02:00
} \
2015-06-08 01:55:08 +02:00
using FirstArgument = T; \
using SecondARgument = T; \
using Result = RT; \
2015-06-04 00:27:09 +02:00
};
2015-07-13 21:08:55 +02:00
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
2015-06-04 00:27:09 +02:00
namespace detail {
2016-01-12 23:24:40 +01:00
template<typename T, bool = IsSame<RemoveConst<T>, char>>
struct CharEqual {
using FirstArgument = T *;
using SecondArgument = T *;
using Result = bool;
bool operator()(T *x, T *y) const {
return !strcmp(x, y);
}
};
template<typename T>
struct CharEqual<T, false> {
using FirstArgument = T *;
using SecondArgument = T *;
using Result = bool;
bool operator()(T *x, T *y) const {
return x == y;
}
};
}
template<typename T>
struct EqualWithCstr {
using FirstArgument = T;
using SecondArgument = T;
2016-06-23 20:18:35 +02:00
bool operator()(T const &x, T const &y) const {
return x == y;
}
};
template<typename T>
struct EqualWithCstr<T *>: detail::CharEqual<T> {};
template<typename T>
struct LogicalNot {
2016-06-23 20:18:35 +02:00
bool operator()(T const &x) const { return !x; }
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = bool;
2015-06-04 00:27:09 +02:00
};
template<typename T>
struct Negate {
2016-06-23 20:18:35 +02:00
bool operator()(T const &x) const { return -x; }
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = T;
2015-06-04 00:27:09 +02:00
};
template<typename T>
struct BinaryNegate {
2015-06-08 01:55:08 +02:00
using FirstArgument = typename T::FirstArgument;
using SecondArgument = typename T::SecondArgument;
using Result = bool;
2015-06-04 00:27:09 +02:00
2016-06-23 20:18:35 +02:00
explicit BinaryNegate(T const &f): p_fn(f) {}
2015-06-04 00:27:09 +02:00
bool operator()(FirstArgument const &x, SecondArgument const &y) {
2015-06-04 00:27:09 +02:00
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
template<typename T>
struct UnaryNegate {
2015-06-08 01:55:08 +02:00
using Argument = typename T::Argument;
using Result = bool;
2015-04-18 19:36:06 +02:00
2016-06-23 20:18:35 +02:00
explicit UnaryNegate(T const &f): p_fn(f) {}
bool operator()(Argument const &x) {
2015-06-04 00:27:09 +02:00
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
template<typename T>
UnaryNegate<T> not1(T const &fn) {
2015-06-04 23:57:06 +02:00
return UnaryNegate<T>(fn);
2015-06-04 00:27:09 +02:00
}
template<typename T>
BinaryNegate<T> not2(T const &fn) {
2015-06-04 23:57:06 +02:00
return BinaryNegate<T>(fn);
2015-06-04 00:27:09 +02:00
}
/* endian swap */
template<typename T, Size N = sizeof(T), bool IsNum = IsArithmetic<T>>
struct EndianSwap;
template<typename T>
struct EndianSwap<T, 2, true> {
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<typename T>
struct EndianSwap<T, 4, true> {
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<typename T>
struct EndianSwap<T, 8, true> {
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<typename T>
T endian_swap(T x) { return EndianSwap<T>()(x); }
namespace detail {
template<typename T, Size N = sizeof(T), bool IsNum = IsArithmetic<T>>
struct EndianSame;
template<typename T>
struct EndianSame<T, 2, true> {
using Argument = T;
using Result = T;
T operator()(T v) const { return v; }
};
template<typename T>
struct EndianSame<T, 4, true> {
using Argument = T;
using Result = T;
T operator()(T v) const { return v; }
};
template<typename T>
struct EndianSame<T, 8, true> {
using Argument = T;
using Result = T;
T operator()(T v) const { return v; }
};
}
2015-07-13 21:08:55 +02:00
#if OSTD_BYTE_ORDER == OSTD_ENDIAN_LIL
template<typename T>
struct FromLilEndian: detail::EndianSame<T> {};
template<typename T>
struct FromBigEndian: EndianSwap<T> {};
#else
template<typename T>
struct FromLilEndian: EndianSwap<T> {};
template<typename T>
struct FromBigEndian: detail::EndianSame<T> {};
#endif
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-04 00:27:09 +02:00
/* hash */
template<typename T>
struct ToHash {
using Argument = T;
using Result = Size;
2016-06-23 20:18:35 +02:00
Size operator()(T const &v) const {
return v.to_hash();
}
};
2015-06-04 00:27:09 +02:00
namespace detail {
template<typename T>
struct ToHashBase {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
return Size(v);
}
};
2015-06-04 00:27:09 +02:00
}
#define OSTD_HASH_BASIC(T) \
template<> \
struct ToHash<T>: detail::ToHashBase<T> {};
2015-06-04 00:27:09 +02:00
2015-07-13 21:08:55 +02:00
OSTD_HASH_BASIC(bool)
OSTD_HASH_BASIC(char)
OSTD_HASH_BASIC(short)
OSTD_HASH_BASIC(int)
OSTD_HASH_BASIC(long)
2015-07-13 21:08:55 +02:00
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
2015-07-13 21:08:55 +02:00
OSTD_HASH_BASIC(Char16)
OSTD_HASH_BASIC(Char32)
#endif
2015-07-13 21:08:55 +02:00
OSTD_HASH_BASIC(Wchar)
2015-06-04 00:27:09 +02:00
2015-07-13 21:08:55 +02:00
#undef OSTD_HASH_BASIC
2015-06-04 00:27:09 +02:00
namespace detail {
template<Size E>
struct FnvConstants {
2015-07-20 03:20:35 +02:00
static constexpr Size prime = 16777619u;
static constexpr Size offset = 2166136261u;
};
template<>
struct FnvConstants<8> {
2015-07-26 20:08:47 +02:00
/* 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);
2015-07-20 03:20:35 +02:00
};
2016-06-23 20:18:35 +02:00
inline Size mem_hash(void const *p, Size l) {
2015-07-20 03:20:35 +02:00
using Consts = FnvConstants<sizeof(Size)>;
2016-07-02 05:56:23 +02:00
byte const *d = static_cast<byte const *>(p);
2015-07-20 03:20:35 +02:00
Size h = Consts::offset;
2016-06-23 20:18:35 +02:00
for (byte const *it = d, *end = d + l; it != end; ++it) {
2015-07-20 03:20:35 +02:00
h ^= *it;
h *= Consts::prime;
}
2015-06-04 00:27:09 +02:00
return h;
}
template<typename T, Size = sizeof(T) / sizeof(Size)>
2015-06-04 00:27:09 +02:00
struct ScalarHash;
template<typename T>
struct ScalarHash<T, 0> {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
union { T v; Size h; } u;
2015-06-04 00:27:09 +02:00
u.h = 0;
u.v = v;
return u.h;
}
};
template<typename T>
struct ScalarHash<T, 1> {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
union { T v; Size h; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
return u.h;
}
};
template<typename T>
struct ScalarHash<T, 2> {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
union { T v; struct { Size h1, h2; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
2016-07-02 05:56:23 +02:00
return mem_hash(static_cast<void const *>(&u), sizeof(u));
}
};
template<typename T>
struct ScalarHash<T, 3> {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
union { T v; struct { Size h1, h2, h3; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
2016-07-02 05:56:23 +02:00
return mem_hash(static_cast<void const *>(&u), sizeof(u));
}
};
template<typename T>
struct ScalarHash<T, 4> {
2015-06-08 01:55:08 +02:00
using Argument = T;
using Result = Size;
Size operator()(T v) const {
union { T v; struct { Size h1, h2, h3, h4; }; } u;
2015-06-04 00:27:09 +02:00
u.v = v;
2016-07-02 05:56:23 +02:00
return mem_hash(static_cast<void const *>(&u), sizeof(u));
}
};
2015-06-04 00:27:09 +02:00
} /* namespace detail */
template<>
struct ToHash<llong>: detail::ScalarHash<llong> {};
template<>
struct ToHash<ullong>: detail::ScalarHash<ullong> {};
template<>
struct ToHash<float>: detail::ScalarHash<float> {
Size operator()(float v) const {
2015-06-04 00:27:09 +02:00
if (v == 0) return 0;
return detail::ScalarHash<float>::operator()(v);
2015-06-04 00:27:09 +02:00
}
};
template<>
struct ToHash<double>: detail::ScalarHash<double> {
Size operator()(double v) const {
2015-06-04 00:27:09 +02:00
if (v == 0) return 0;
return detail::ScalarHash<double>::operator()(v);
2015-06-04 00:27:09 +02:00
}
};
template<>
struct ToHash<ldouble>: detail::ScalarHash<ldouble> {
Size operator()(ldouble v) const {
if (v == 0) {
return 0;
}
#ifdef __i386__
union { ldouble v; struct { Size h1, h2, h3, h4; }; } u;
2015-06-04 00:27:09 +02:00
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;
2015-06-04 00:27:09 +02:00
u.h1 = u.h2 = 0;
u.v = v;
return (u.h1 ^ u.h2);
#else
return detail::ScalarHash<ldouble>::operator()(v);
#endif
#endif
2015-06-04 00:27:09 +02:00
}
};
namespace detail {
2016-01-12 23:24:40 +01:00
template<typename T, bool = IsSame<RemoveConst<T>, char>>
struct ToHashPtr {
using Argument = T *;
using Result = Size;
Size operator()(T *v) const {
union { T *v; Size h; } u;
u.v = v;
2016-07-02 05:56:23 +02:00
return detail::mem_hash(static_cast<void const *>(&u), sizeof(u));
}
};
template<typename T>
struct ToHashPtr<T, true> {
using Argument = T *;
using Result = Size;
Size operator()(T *v) const {
return detail::mem_hash(v, strlen(v));
}
};
}
template<typename T>
struct ToHash<T *>: detail::ToHashPtr<T> {};
template<typename T>
2016-06-23 20:18:35 +02:00
typename ToHash<T>::Result to_hash(T const &v) {
return ToHash<T>()(v);
}
2015-07-13 21:07:14 +02:00
} /* namespace ostd */
2016-02-07 22:17:15 +01:00
#endif