#pragma once #include #include #include #include #include #include #include #include #include #ifdef __MINGW32__ #include #else #include #endif #if defined(__APPLE__) || defined(__FreeBSD__) #define off64_t off_t #define fopen64 fopen #define fseeko64 fseek #define ftello64 ftell #else template<> struct std::is_integral : public std::true_type { }; template<> struct std::is_integral : public std::true_type { }; template<> struct std::is_signed : public std::true_type { }; #endif #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000 #if __has_include() // Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above #include #endif // libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins. // [concept.derived] (patch from https://reviews.llvm.org/D74292) namespace hex { template concept derived_from = __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); } // [concepts.arithmetic] namespace hex { template concept integral = __is_integral(_Tp); template concept signed_integral = integral<_Tp> && __is_signed(_Tp); template concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>; template concept floating_point = __is_floating_point(_Tp); } #else // Assume supported #include namespace hex { using std::derived_from; using std::integral; using std::signed_integral; using std::unsigned_integral; using std::floating_point; } #endif #define TOKEN_CONCAT_IMPL(x, y) x ## y #define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y) namespace hex { inline std::string to_string(u128 value) { char data[45] = { 0 }; u8 index = sizeof(data) - 2; while (value != 0 && index != 0) { data[index] = '0' + value % 10; value /= 10; index--; } return std::string(data + index + 1); } inline std::string to_string(s128 value) { char data[45] = { 0 }; u128 unsignedValue = value < 0 ? -value : value; u8 index = sizeof(data) - 2; while (unsignedValue != 0 && index != 0) { data[index] = '0' + unsignedValue % 10; unsignedValue /= 10; index--; } if (value < 0) { data[index] = '-'; return std::string(data + index); } else return std::string(data + index + 1); } template inline std::string format(const char *format, Args ... args) { ssize_t size = snprintf( nullptr, 0, format, args ... ); if (size <= 0) return ""; std::vector buffer(size + 1, 0x00); snprintf(buffer.data(), size + 1, format, args ...); return std::string(buffer.data(), buffer.data() + size); } [[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) { std::remove_cvref_t mask = (std::numeric_limits>::max() >> (((sizeof(value) * 8) - 1) - (from - to))) << to; return (value & mask) >> to; } template [[nodiscard]] constexpr inline T signExtend(T value, u8 currWidth, u8 targetWidth) { T mask = 1LLU << (currWidth - 1); return (((value ^ mask) - mask) << ((sizeof(T) * 8) - targetWidth)) >> ((sizeof(T) * 8) - targetWidth); } std::string toByteString(u64 bytes); std::string makePrintable(char c); template struct always_false : std::false_type {}; template constexpr T changeEndianess(T value, std::endian endian) { if (endian == std::endian::native) return value; if constexpr (sizeof(T) == 1) return value; else if constexpr (sizeof(T) == 2) return __builtin_bswap16(value); else if constexpr (sizeof(T) == 4) return __builtin_bswap32(value); else if constexpr (sizeof(T) == 8) return __builtin_bswap64(value); else static_assert(always_false::value, "Invalid type provided!"); } template constexpr T changeEndianess(T value, size_t size, std::endian endian) { if (endian == std::endian::native) return value; if (size == 1) return value; else if (size == 2) return __builtin_bswap16(value); else if (size == 4) return __builtin_bswap32(value); else if (size == 8) return __builtin_bswap64(value); else if (size == 16) { u64 parts[2]; std::memcpy(parts, &value, size); return u128(parts[1]) << 64 | u128(parts[0]); } else throw std::invalid_argument("Invalid value size!"); } template< class T > constexpr T bit_width(T x) noexcept { return std::numeric_limits::digits - std::countl_zero(x); } template constexpr T bit_ceil(T x) noexcept { if (x <= 1u) return T(1); return T(1) << bit_width(T(x - 1)); } inline std::vector splitString(std::string_view string, std::string_view delimiter) { size_t start = 0, end; std::string token; std::vector res; while ((end = string.find (delimiter, start)) != std::string::npos) { token = string.substr(start, end - start); start = end + delimiter.length(); res.push_back(token); } res.push_back(std::string(string.substr(start))); return res; } inline std::string toEngineeringString(double value) { constexpr std::array prefixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" }; int8_t prefixIndex = 6; while (prefixIndex != 0 && prefixIndex != 12 && (value >= 1000 || value < 1) && value != 0) { if (value >= 1000) { value /= 1000; prefixIndex++; } else if (value < 1) { value *= 1000; prefixIndex--; } } return std::to_string(value).substr(0, 5) + prefixes[prefixIndex]; } std::vector readFile(std::string_view path); #define SCOPE_EXIT(func) ScopeExit TOKEN_CONCAT(scopeGuard, __COUNTER__)([&] { func }) class ScopeExit { public: ScopeExit(std::function func) : m_func(func) {} ~ScopeExit() { if (this->m_func != nullptr) this->m_func(); } void release() { this->m_func = nullptr; } private: std::function m_func; }; struct Region { u64 address; size_t size; }; }