#ifndef UTILITY_H #define UTILITY_H #include #include #include #include #include #include #include #include #include #define KITTY_WHILE_LOOP(x, y, z) \ { \ x; \ while(y) z \ } template struct argument_type; template struct argument_type { typedef U type; }; #define KITTY_USING_MOVE_T(move_t, t, init_val, z) \ class move_t { \ public: \ using element_type = typename argument_type::type; \ \ move_t() : el { init_val } {} \ template \ move_t(Args &&...args) : el { std::forward(args)... } {} \ move_t(const move_t &) = delete; \ \ move_t(move_t &&other) noexcept : el { std::move(other.el) } { \ other.el = element_type { init_val }; \ } \ \ move_t &operator=(const move_t &) = delete; \ \ move_t &operator=(move_t &&other) { \ std::swap(el, other.el); \ return *this; \ } \ element_type *operator->() { return ⪙ } \ const element_type *operator->() const { return ⪙ } \ \ ~move_t() z \ \ element_type el; \ } #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) #define TUPLE_EL(a, b, expr) \ decltype(expr) a##_ = expr; \ auto &a = std::get(a##_) #define TUPLE_EL_REF(a, b, expr) \ auto &a = std::get(expr) 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 overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; 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 [[nodiscard]] 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); } 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); } }; // Compared to std::unique_ptr, it adds the ability to get the address of the pointer itself template> class uniq_ptr { public: using element_type = T; using pointer = element_type *; using deleter_type = D; constexpr uniq_ptr() noexcept : _p { nullptr } {} constexpr uniq_ptr(std::nullptr_t) noexcept : _p { nullptr } {} uniq_ptr(const uniq_ptr &other) noexcept = delete; uniq_ptr &operator=(const uniq_ptr &other) noexcept = delete; template uniq_ptr(V *p) noexcept : _p { p } { static_assert(std::is_same_v || std::is_same_v || std::is_base_of_v, "element_type must be base class of V"); } template uniq_ptr(std::unique_ptr &&uniq) noexcept : _p { uniq.release() } { static_assert(std::is_same_v || std::is_same_v || std::is_base_of_v, "element_type must be base class of V"); } template uniq_ptr(uniq_ptr &&other) noexcept : _p { other.release() } { static_assert(std::is_same_v || std::is_same_v || std::is_base_of_v, "element_type must be base class of V"); } template uniq_ptr &operator=(uniq_ptr &&other) noexcept { static_assert(std::is_same_v || std::is_same_v || std::is_base_of_v, "element_type must be base class of V"); reset(other.release()); return *this; } template uniq_ptr &operator=(std::unique_ptr &&uniq) noexcept { static_assert(std::is_same_v || std::is_same_v || std::is_base_of_v, "element_type must be base class of V"); reset(uniq.release()); return *this; } ~uniq_ptr() { reset(); } void reset(pointer p = pointer()) { if(_p) { _deleter(_p); } _p = p; } pointer release() { auto tmp = _p; _p = nullptr; return tmp; } pointer get() { return _p; } const pointer get() const { return _p; } const std::add_lvalue_reference_t operator*() const { return *_p; } std::add_lvalue_reference_t operator*() { return *_p; } const pointer operator->() const { return _p; } pointer operator->() { return _p; } pointer *operator&() const { return &_p; } pointer *operator&() { return &_p; } deleter_type &get_deleter() { return _deleter; } const deleter_type &get_deleter() const { return _deleter; } explicit operator bool() const { return _p != nullptr; } protected: pointer _p; deleter_type _deleter; }; template bool operator==(const uniq_ptr &x, const uniq_ptr &y) { return x.get() == y.get(); } template bool operator!=(const uniq_ptr &x, const uniq_ptr &y) { return x.get() != y.get(); } template bool operator==(const std::unique_ptr &x, const uniq_ptr &y) { return x.get() == y.get(); } template bool operator!=(const std::unique_ptr &x, const uniq_ptr &y) { return x.get() != y.get(); } template bool operator==(const uniq_ptr &x, const std::unique_ptr &y) { return x.get() == y.get(); } template bool operator!=(const uniq_ptr &x, const std::unique_ptr &y) { return x.get() != y.get(); } template bool operator==(const uniq_ptr &x, std::nullptr_t) { return !(bool)x; } template bool operator!=(const uniq_ptr &x, std::nullptr_t) { return (bool)x; } template bool operator==(std::nullptr_t, const uniq_ptr &y) { return !(bool)y; } template bool operator!=(std::nullptr_t, const uniq_ptr &y) { return (bool)y; } template class wrap_ptr { public: using element_type = T; using pointer = element_type *; using reference = element_type &; wrap_ptr() : _own_ptr { false }, _p { nullptr } {} wrap_ptr(pointer p) : _own_ptr { false }, _p { p } {} wrap_ptr(std::unique_ptr &&uniq_p) : _own_ptr { true }, _p { uniq_p.release() } {} wrap_ptr(wrap_ptr &&other) : _own_ptr { other._own_ptr }, _p { other._p } { other._own_ptr = false; } wrap_ptr &operator=(wrap_ptr &&other) noexcept { if(_own_ptr) { delete _p; } _p = other._p; _own_ptr = other._own_ptr; other._own_ptr = false; return *this; } template wrap_ptr &operator=(std::unique_ptr &&uniq_ptr) { static_assert(std::is_base_of_v, "element_type must be base class of V"); _own_ptr = true; _p = uniq_ptr.release(); return *this; } wrap_ptr &operator=(pointer p) { if(_own_ptr) { delete _p; } _p = p; _own_ptr = false; return *this; } ~wrap_ptr() { if(_own_ptr) { delete _p; } _own_ptr = false; } const reference operator*() const { return *_p; } reference operator*() { return *_p; } const pointer operator->() const { return _p; } pointer operator->() { return _p; } private: bool _own_ptr; pointer _p; }; template constexpr bool is_pointer_v = instantiation_of_v || instantiation_of_v || instantiation_of_v || std::is_pointer_v; template struct __false_v; template struct __false_v>> { static constexpr std::nullopt_t value = std::nullopt; }; template struct __false_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 || is_pointer_v), T, std::optional>; template class buffer_t { public: buffer_t() : _els { 0 } {}; buffer_t(buffer_t &&) noexcept = default; buffer_t &operator=(buffer_t &&other) noexcept = default; 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); } 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 = uniq_ptr>; // You cannot specialize an alias template::type function> using safe_ptr_v2 = uniq_ptr>; template void c_free(T *p) { free(p); } template void dynamic(T *p) { (*function)(p); } template using dyn_safe_ptr = safe_ptr>; template using dyn_safe_ptr_v2 = safe_ptr>; template using c_ptr = safe_ptr>; template std::string_view view(It begin, It end) { return std::string_view { (const char *)begin, (std::size_t)(end - begin) }; } template std::string_view view(const T &data) { return std::string_view((const char *)&data, sizeof(T)); } 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); } } // namespace endian } // namespace util #endif