#ifndef UTILITY_H #define UTILITY_H #include #include #include #include #include #include #include #include #include #define KITTY_DECL_CONSTR(x)\ x(x&&) noexcept = default;\ x&operator=(x&&) noexcept = default;\ x(); #define KITTY_DEFAULT_CONSTR(x)\ x(x&&) noexcept = default;\ x&operator=(x&&) noexcept = default;\ x() = default; #define KITTY_DEFAULT_CONSTR_THROW(x)\ x(x&&) = default;\ x&operator=(x&&) = default;\ x() = default; #define TUPLE_2D(a,b, expr)\ decltype(expr) a##_##b = expr;\ auto &a = std::get<0>(a##_##b);\ auto &b = std::get<1>(a##_##b) #define TUPLE_2D_REF(a,b, expr)\ auto &a##_##b = expr;\ auto &a = std::get<0>(a##_##b);\ auto &b = std::get<1>(a##_##b) #define TUPLE_3D(a,b,c, expr)\ decltype(expr) a##_##b##_##c = expr;\ auto &a = std::get<0>(a##_##b##_##c);\ auto &b = std::get<1>(a##_##b##_##c);\ auto &c = std::get<2>(a##_##b##_##c) #define TUPLE_3D_REF(a,b,c, expr)\ auto &a##_##b##_##c = expr;\ auto &a = std::get<0>(a##_##b##_##c);\ auto &b = std::get<1>(a##_##b##_##c);\ auto &c = std::get<2>(a##_##b##_##c) namespace util { template class X, class...Y> struct __instantiation_of : public std::false_type {}; template class X, class... Y> struct __instantiation_of> : public std::true_type {}; template class X, class T, class...Y> static constexpr auto instantiation_of_v = __instantiation_of::value; template struct __either; template struct __either { using type = X; }; template struct __either { using type = Y; }; template using either_t = typename __either::type; template struct __false_v; template struct __false_v>> { static constexpr std::nullopt_t value = std::nullopt; }; template struct __false_v || instantiation_of_v || instantiation_of_v) >> { static constexpr std::nullptr_t value = nullptr; }; template struct __false_v>> { static constexpr bool value = false; }; template static constexpr auto false_v = __false_v::value; template using optional_t = either_t< (std::is_same_v || instantiation_of_v || instantiation_of_v || std::is_pointer_v), T, std::optional>; template class FailGuard { public: FailGuard() = delete; FailGuard(T && f) noexcept : _func { std::forward(f) } {} FailGuard(FailGuard &&other) noexcept : _func { std::move(other._func) } { this->failure = other.failure; other.failure = false; } FailGuard(const FailGuard &) = delete; FailGuard &operator=(const FailGuard &) = delete; FailGuard &operator=(FailGuard &&other) = delete; ~FailGuard() noexcept { if(failure) { _func(); } } void disable() { failure = false; } bool failure { true }; private: T _func; }; template auto fail_guard(T && f) { return FailGuard { std::forward(f) }; } template void append_struct(std::vector &buf, const T &_struct) { constexpr size_t data_len = sizeof(_struct); buf.reserve(data_len); auto *data = (uint8_t *) & _struct; for (size_t x = 0; x < data_len; ++x) { buf.push_back(data[x]); } } template class Hex { public: typedef T elem_type; private: const char _bits[16] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char _hex[sizeof(elem_type) * 2]; public: Hex(const elem_type &elem, bool rev) { if(!rev) { const uint8_t *data = reinterpret_cast(&elem) + sizeof(elem_type) - 1; for (auto it = begin(); it < cend();) { *it++ = _bits[*data / 16]; *it++ = _bits[*data-- % 16]; } } else { const uint8_t *data = reinterpret_cast(&elem); for (auto it = begin(); it < cend();) { *it++ = _bits[*data / 16]; *it++ = _bits[*data++ % 16]; } } } char *begin() { return _hex; } char *end() { return _hex + sizeof(elem_type) * 2; } const char *begin() const { return _hex; } const char *end() const { return _hex + sizeof(elem_type) * 2; } const char *cbegin() const { return _hex; } const char *cend() const { return _hex + sizeof(elem_type) * 2; } std::string to_string() const { return { begin(), end() }; } std::string_view to_string_view() const { return { begin(), sizeof(elem_type) * 2 }; } }; template Hex hex(const T &elem, bool rev = false) { return Hex(elem, rev); } template std::string hex_vec(It begin, It end, bool rev = false) { auto str_size = 2*std::distance(begin, end); std::string hex; hex.resize(str_size); const char _bits[16] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; if(rev) { for (auto it = std::begin(hex); it < std::end(hex);) { *it++ = _bits[((uint8_t)*begin) / 16]; *it++ = _bits[((uint8_t)*begin++) % 16]; } } else { --end; for (auto it = std::begin(hex); it < std::end(hex);) { *it++ = _bits[((uint8_t)*end) / 16]; *it++ = _bits[((uint8_t)*end--) % 16]; } } return hex; } template std::string hex_vec(C&& c, bool rev = false) { return hex_vec(std::begin(c), std::end(c), rev); } template std::optional from_hex(const std::string_view &hex, bool rev = false) { std::uint8_t buf[sizeof(T)]; static char constexpr shift_bit = 'a' - 'A'; auto is_convertable = [] (char ch) -> bool { if(isdigit(ch)) { return true; } ch |= shift_bit; if('a' > ch || ch > 'z') { return false; } return true; }; auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2; if(buf_size != sizeof(T)) { return std::nullopt; } const char *data = hex.data() + hex.size() -1; auto convert = [] (char ch) -> std::uint8_t { if(ch >= '0' && ch <= '9') { return (std::uint8_t)ch - '0'; } return (std::uint8_t)(ch | (char)32) - 'a' + (char)10; }; for(auto &el : buf) { while(!is_convertable(*data)) { --data; } std::uint8_t ch_r = convert(*data--); while(!is_convertable(*data)) { --data; } std::uint8_t ch_l = convert(*data--); el = (ch_l << 4) | ch_r; } if(rev) { std::reverse(std::begin(buf), std::end(buf)); } return *reinterpret_cast(buf); } inline std::string from_hex_vec(const std::string &hex, bool rev = false) { std::string buf; static char constexpr shift_bit = 'a' - 'A'; auto is_convertable = [] (char ch) -> bool { if(isdigit(ch)) { return true; } ch |= shift_bit; if('a' > ch || ch > 'z') { return false; } return true; }; auto buf_size = std::count_if(std::begin(hex), std::end(hex), is_convertable) / 2; buf.resize(buf_size); const char *data = hex.data() + hex.size() -1; auto convert = [] (char ch) -> std::uint8_t { if(ch >= '0' && ch <= '9') { return (std::uint8_t)ch - '0'; } return (std::uint8_t)(ch | (char)32) - 'a' + (char)10; }; for(auto &el : buf) { while(!is_convertable(*data)) { --data; } std::uint8_t ch_r = convert(*data--); while(!is_convertable(*data)) { --data; } std::uint8_t ch_l = convert(*data--); el = (ch_l << 4) | ch_r; } if(rev) { std::reverse(std::begin(buf), std::end(buf)); } return buf; } template class hash { public: using value_type = T; std::size_t operator()(const value_type &value) const { const auto *p = reinterpret_cast(&value); return std::hash{}(std::string_view { p, sizeof(value_type) }); } }; template auto enm(const T& val) -> const std::underlying_type_t& { return *reinterpret_cast*>(&val); } template auto enm(T& val) -> std::underlying_type_t& { return *reinterpret_cast*>(&val); } template struct Function { typedef ReturnType (*type)(Args...); }; template::type function> struct Destroy { typedef T pointer; void operator()(pointer p) { function(p); } }; template::type function> using safe_ptr = std::unique_ptr>; // You cannot specialize an alias template::type function> using safe_ptr_v2 = std::unique_ptr>; template void c_free(T *p) { free(p); } template using c_ptr = safe_ptr>; template class FakeContainer { typedef T pointer; pointer _begin; pointer _end; public: FakeContainer(pointer begin, pointer end) : _begin(begin), _end(end) {} pointer begin() { return _begin; } pointer end() { return _end; } const pointer begin() const { return _begin; } const pointer end() const { return _end; } const pointer cbegin() const { return _begin; } const pointer cend() const { return _end; } pointer data() { return begin(); } const pointer data() const { return cbegin(); } std::size_t size() const { return std::distance(begin(), end()); } }; template FakeContainer toContainer(T begin, T end) { return { begin, end }; } template FakeContainer toContainer(T begin, std::size_t end) { return { begin, begin + end }; } template FakeContainer toContainer(T * const begin) { T *end = begin; auto default_val = T(); while(*end != default_val) { ++end; } return toContainer(begin, end); } template struct _init_helper; template class T, class H, class... Args> struct _init_helper, H> { using type = T; static type move(Args&&... args, H&&) { return std::make_tuple(std::move(args)...); } static type copy(const Args&... args, const H&) { return std::make_tuple(args...); } }; inline std::int64_t from_chars(const char *begin, const char *end) { std::int64_t res {}; std::int64_t mul = 1; while(begin != --end) { res += (std::int64_t)(*end - '0') * mul; mul *= 10; } return *begin != '-' ? res + (std::int64_t)(*begin - '0') * mul : -res; } inline std::int64_t from_view(const std::string_view &number) { return from_chars(std::begin(number), std::end(number)); } template class Either : public std::variant { public: using std::variant::variant; constexpr bool has_left() const { return std::holds_alternative(*this); } constexpr bool has_right() const { return std::holds_alternative(*this); } X &left() { return std::get(*this); } Y &right() { return std::get(*this); } const X &left() const { return std::get(*this); } const Y &right() const { return std::get(*this); } }; template class buffer_t { public: buffer_t() : _els { 0 } {}; buffer_t(buffer_t&&) noexcept = default; buffer_t &operator=(buffer_t&& other) noexcept { std::swap(_els, other._els); _buf = std::move(other._buf); return *this; }; explicit buffer_t(size_t elements) : _els { elements }, _buf { std::make_unique(elements) } {} explicit buffer_t(size_t elements, const T &t) : _els { elements }, _buf { std::make_unique(elements) } { std::fill_n(_buf.get(), elements, t); } T &operator[](size_t el) { return _buf[el]; } const T &operator[](size_t el) const { return _buf[el]; } size_t size() const { return _els; } void fake_resize(std::size_t els) { _els = els; } T *begin() { return _buf.get(); } const T *begin() const { return _buf.get(); } T *end() { return _buf.get() + _els; } const T *end() const { return _buf.get() + _els; } private: size_t _els; std::unique_ptr _buf; }; template T either(std::optional &&l, T &&r) { if(l) { return std::move(*l); } return std::forward(r); } namespace endian { template struct endianness { enum : bool { #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ defined(__BIG_ENDIAN__) || \ defined(__ARMEB__) || \ defined(__THUMBEB__) || \ defined(__AARCH64EB__) || \ defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) // It's a big-endian target architecture little = false, #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \ defined(__LITTLE_ENDIAN__) || \ defined(__ARMEL__) || \ defined(__THUMBEL__) || \ defined(__AARCH64EL__) || \ defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) | \ defined(_WIN32) // It's a little-endian target architecture little = true, #else #error "Unknown Endianness" #endif big = !little }; }; template struct endian_helper { }; template struct endian_helper) >> { static inline T big(T x) { if constexpr (endianness::little) { uint8_t *data = reinterpret_cast(&x); std::reverse(data, data + sizeof(x)); } return x; } static inline T little(T x) { if constexpr (endianness::big) { uint8_t *data = reinterpret_cast(&x); std::reverse(data, data + sizeof(x)); } return x; } }; template struct endian_helper >> { static inline T little(T x) { if(!x) return x; if constexpr (endianness::big) { auto *data = reinterpret_cast(&*x); std::reverse(data, data + sizeof(*x)); } return x; } static inline T big(T x) { if(!x) return x; if constexpr (endianness::big) { auto *data = reinterpret_cast(&*x); std::reverse(data, data + sizeof(*x)); } return x; } }; template inline auto little(T x) { return endian_helper::little(x); } template inline auto big(T x) { return endian_helper::big(x); } } /* endian */ } /* util */ #endif