diff --git a/include/helpers.hpp b/include/helpers.hpp index fc3c0167..853e487b 100644 --- a/include/helpers.hpp +++ b/include/helpers.hpp @@ -1,6 +1,6 @@ #pragma once -#include <cstdarg> #include <climits> +#include <cstdarg> #include <cstdint> #include <fstream> #include <iostream> @@ -8,8 +8,16 @@ #include <type_traits> #include <utility> #include <vector> + #include "termcolor.hpp" +// We have to detect and special-case AppleClang at the moment since its C++20 support is finicky and doesn't quite support std::bit_cast +#if defined(__clang__) && defined(__apple_build_version__) +#define HELPERS_APPLE_CLANG +#else +#include <bit> +#endif + using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; @@ -23,78 +31,74 @@ using s32 = std::int32_t; using s64 = std::int64_t; namespace Helpers { - [[noreturn]] static void panic(const char* fmt, ...) { - std::va_list args; - va_start(args, fmt); - std::cout << termcolor::on_red << "[FATAL] "; - std::vprintf (fmt, args); - std::cout << termcolor::reset << "\n"; - va_end(args); + [[noreturn]] static void panic(const char* fmt, ...) { + std::va_list args; + va_start(args, fmt); + std::cout << termcolor::on_red << "[FATAL] "; + std::vprintf(fmt, args); + std::cout << termcolor::reset << "\n"; + va_end(args); - exit(1); - } + exit(1); + } - static void warn(const char* fmt, ...) { - std::va_list args; - va_start(args, fmt); - std::cout << termcolor::on_red << "[Warning] "; - std::vprintf (fmt, args); - std::cout << termcolor::reset << "\n"; - va_end(args); - } + static void warn(const char* fmt, ...) { + std::va_list args; + va_start(args, fmt); + std::cout << termcolor::on_red << "[Warning] "; + std::vprintf(fmt, args); + std::cout << termcolor::reset << "\n"; + va_end(args); + } - static std::vector <u8> loadROM(std::string directory) { - std::ifstream file (directory, std::ios::binary); - if (file.fail()) - panic("Couldn't read %s", directory.c_str()); + static std::vector<u8> loadROM(std::string directory) { + std::ifstream file(directory, std::ios::binary); + if (file.fail()) panic("Couldn't read %s", directory.c_str()); - std::vector<u8> ROM; + std::vector<u8> ROM; - file.unsetf(std::ios::skipws); - ROM.insert(ROM.begin(), - std::istream_iterator<uint8_t>(file), - std::istream_iterator<uint8_t>()); + file.unsetf(std::ios::skipws); + ROM.insert(ROM.begin(), std::istream_iterator<uint8_t>(file), std::istream_iterator<uint8_t>()); - file.close(); + file.close(); - printf ("%s loaded successfully\n", directory.c_str()); - return ROM; - } + printf("%s loaded successfully\n", directory.c_str()); + return ROM; + } - static constexpr bool buildingInDebugMode() { - #ifdef NDEBUG - return false; - #endif + static constexpr bool buildingInDebugMode() { +#ifdef NDEBUG + return false; +#endif + return true; + } - return true; - } - - static void debug_printf (const char* fmt, ...) { - if constexpr (buildingInDebugMode()) { - std::va_list args; - va_start(args, fmt); - std::vprintf (fmt, args); - va_end(args); - } - } + static void debug_printf(const char* fmt, ...) { + if constexpr (buildingInDebugMode()) { + std::va_list args; + va_start(args, fmt); + std::vprintf(fmt, args); + va_end(args); + } + } - /// Sign extend an arbitrary-size value to 32 bits - static constexpr u32 inline signExtend32 (u32 value, u32 startingSize) { - auto temp = (s32) value; - auto bitsToShift = 32 - startingSize; - return (u32) (temp << bitsToShift >> bitsToShift); - } + /// Sign extend an arbitrary-size value to 32 bits + static constexpr u32 inline signExtend32(u32 value, u32 startingSize) { + auto temp = (s32)value; + auto bitsToShift = 32 - startingSize; + return (u32)(temp << bitsToShift >> bitsToShift); + } - /// Sign extend an arbitrary-size value to 16 bits - static constexpr u16 signExtend16 (u16 value, u32 startingSize) { - auto temp = (s16) value; - auto bitsToShift = 16 - startingSize; - return (u16) (temp << bitsToShift >> bitsToShift); - } + /// Sign extend an arbitrary-size value to 16 bits + static constexpr u16 signExtend16(u16 value, u32 startingSize) { + auto temp = (s16)value; + auto bitsToShift = 16 - startingSize; + return (u16)(temp << bitsToShift >> bitsToShift); + } /// Create a mask with `count` number of one bits. - template<typename T, usize count> - static constexpr T ones () { + template <typename T, usize count> + static constexpr T ones() { constexpr usize bitsize = CHAR_BIT * sizeof(T); static_assert(count <= bitsize, "count larger than bitsize of T"); @@ -105,80 +109,74 @@ namespace Helpers { } /// Extract bits from an integer-type - template<usize offset, typename T> - static constexpr T getBit (T value) { - return (value >> offset) & T(1); + template <usize offset, typename T> + static constexpr T getBit(T value) { + return (value >> offset) & T(1); } /// Extract bits from an integer-type - template<usize offset, usize bits, typename T> - static constexpr T getBits (T value) { - return (value >> offset) & ones<T, bits>(); + template <usize offset, usize bits, typename T> + static constexpr T getBits(T value) { + return (value >> offset) & ones<T, bits>(); } - /// Check if a bit "bit" of value is set - static constexpr bool isBitSet (u32 value, int bit) { - return (value >> bit) & 1; - } + /// Check if a bit "bit" of value is set + static constexpr bool isBitSet(u32 value, int bit) { return (value >> bit) & 1; } - /// rotate number right - template <typename T> - static constexpr T rotr (T value, int bits) { - constexpr auto bitWidth = sizeof(T) * 8; - bits &= bitWidth - 1; - return (value >> bits) | (value << (bitWidth - bits)); - } + /// rotate number right + template <typename T> + static constexpr T rotr(T value, int bits) { + constexpr auto bitWidth = sizeof(T) * 8; + bits &= bitWidth - 1; + return (value >> bits) | (value << (bitWidth - bits)); + } - // rotate number left - template <typename T> - static constexpr T rotl (T value, int bits) { - constexpr auto bitWidth = sizeof(T) * 8; - bits &= bitWidth - 1; - return (value << bits) | (value >> (bitWidth - bits)); - } + // rotate number left + template <typename T> + static constexpr T rotl(T value, int bits) { + constexpr auto bitWidth = sizeof(T) * 8; + bits &= bitWidth - 1; + return (value << bits) | (value >> (bitWidth - bits)); + } - /// Used to make the compiler evaluate beeg loops at compile time for the tablegen - template <typename T, T Begin, class Func, T ...Is> - static constexpr void static_for_impl( Func&& f, std::integer_sequence<T, Is...> ) { - ( f( std::integral_constant<T, Begin + Is>{ } ),... ); - } + /// Used to make the compiler evaluate beeg loops at compile time for the tablegen + template <typename T, T Begin, class Func, T... Is> + static constexpr void static_for_impl(Func&& f, std::integer_sequence<T, Is...>) { + (f(std::integral_constant<T, Begin + Is>{}), ...); + } - template <typename T, T Begin, T End, class Func> - static constexpr void static_for(Func&& f) { - static_for_impl<T, Begin>( std::forward<Func>(f), std::make_integer_sequence<T, End - Begin>{ } ); - } + template <typename T, T Begin, T End, class Func> + static constexpr void static_for(Func&& f) { + static_for_impl<T, Begin>(std::forward<Func>(f), std::make_integer_sequence<T, End - Begin>{}); + } - // For values < 0x99 - static constexpr inline u8 incBCDByte(u8 value) { - return ((value & 0xf) == 0x9) ? value + 7 : value + 1; - } - // Use this helper for platforms that lack a working std::bit_cast implementation - // TODO: Replace this with C++20 version if available - template< class To, class From > - constexpr To bit_cast( const From& from ) noexcept{ - return *reinterpret_cast<const To*>(&from); - } -}; + // For values < 0x99 + static constexpr inline u8 incBCDByte(u8 value) { return ((value & 0xf) == 0x9) ? value + 7 : value + 1; } + +#ifdef HELPERS_APPLE_CLANG + template <class To, class From> + constexpr To bit_cast(const From& from) noexcept { + return *reinterpret_cast<const To*>(&from); + } +#else + template <class To, class From> + constexpr To bit_cast(const From& from) noexcept { + return std::bit_cast<To, From>(from); + } +#endif +}; // namespace Helpers // UDLs for memory size values -constexpr size_t operator""_KB(unsigned long long int x) { - return 1024ULL * x; -} - -constexpr size_t operator""_MB(unsigned long long int x) { - return 1024_KB * x; -} - -constexpr size_t operator""_GB(unsigned long long int x) { - return 1024_MB * x; -} +constexpr size_t operator""_KB(unsigned long long int x) { return 1024ULL * x; } +constexpr size_t operator""_MB(unsigned long long int x) { return 1024_KB * x; } +constexpr size_t operator""_GB(unsigned long long int x) { return 1024_MB * x; } // useful macros // likely/unlikely #ifdef __GNUC__ - #define likely(x) __builtin_expect((x),1) - #define unlikely(x) __builtin_expect((x),0) -#else - #define likely(x) (x) - #define unlikely(x) (x) -#endif \ No newline at end of file +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif