diff --git a/src/drivers/Qt/ConsoleUtilities.h b/src/drivers/Qt/ConsoleUtilities.h index d867ff47..bbcefc07 100644 --- a/src/drivers/Qt/ConsoleUtilities.h +++ b/src/drivers/Qt/ConsoleUtilities.h @@ -3,7 +3,6 @@ #pragma once #include -#include #include #include @@ -94,162 +93,3 @@ class QCheckBoxRO : public QCheckBox QString fceuGetOpcodeToolTip( uint8_t *opcode, int size ); QDialog *fceuCustomToolTipShow( const QPoint &globalPos, QDialog *popup ); - -// Faster replacement functions for sprintf. It's uglier, but much faster. -class StringBuilder -{ -public: - // Helper struct. Do not use directly. - template - struct IntInfo - { - T x; - int minLen; - char leadChar; - bool upperCase; - Prefix prefix; - }; - - inline StringBuilder(char *str) : start(str), end(str) - { - *end = '\0'; - } - - inline char *str() const - { - return start; - } - - inline size_t size() const - { - return size_t(end - start); - } - - inline StringBuilder &operator <<(char ch) - { - *(end++) = ch; - *end = '\0'; - - return *this; - } - - inline StringBuilder &operator <<(const char *src) - { - size_t len = strlen(src); - memcpy(end, src, len + 1); - - end += len; - - return *this; - } - - template - inline StringBuilder &operator <<(const IntInfo intInfo) - { - *this << intInfo.prefix; - return appendInt(intInfo.x, intInfo.minLen, intInfo.leadChar, intInfo.upperCase); - } - -protected: - inline StringBuilder &operator <<(nullptr_t) - { - return *this; - } - - template - StringBuilder &appendInt(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false) - { - static_assert(Radix >= 2 && Radix <= 36, "Radix must be between 2 and 36"); - static_assert(std::is_integral::value, "T must be an integral type"); - - static const char *upperCaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", - *lowerCaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"; - const char *digits = upperCase ? upperCaseDigits : lowerCaseDigits; - - const bool isSigned = std::is_signed::value; - bool isNeg = isSigned && x < 0; - if (isSigned && isNeg) - // This convoluted expression is to silence an unnecessary compiler warning when unsigned - x = T(-std::make_signed::type(x)); - - unsigned i = 0; - if (x != 0) - { - do - { - end[i++] = digits[x % Radix]; - x /= Radix; - } while (x != 0); - } - else - end[i++] = '0'; - - if (isNeg) - end[i++] = '-'; - - if (minLen < 0) - { - end[i] = '\0'; - - strrev(end); - - for (; i < (unsigned)-minLen; i++) - end[i] = leadChar; - - end[i] = '\0'; - } - else - { - for (; i < (unsigned)minLen; i++) - end[i] = leadChar; - - end[i] = '\0'; - - strrev(end); - } - - end += i; - - return *this; - } - - char *start; - char *end; -}; - -// Formatters for numbers - -// Generic integer with any radius -template -inline StringBuilder::IntInfo sb_int(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false) -{ - return { x, minLen, leadChar, upperCase, nullptr }; -} - -// A decimal number -template -inline StringBuilder::IntInfo<10, T> sb_dec(T x, int minLen = 0, char leadChar = ' ') -{ - return { x, minLen, leadChar, false, nullptr }; -} - -// A hex number -template -inline StringBuilder::IntInfo<16, T> sb_hex(T x, int minLen = 0, bool upperCase = true, char leadChar = '0') -{ - return { x, minLen, leadChar, upperCase, nullptr }; -} - -// An address of the basic form $%x -template -inline StringBuilder::IntInfo<16, T, char> sb_addr(T x, int minLen = 4, bool upperCase = true) -{ - return { x, minLen, '0', upperCase, '$' }; -} - -// A literal value of the form #$%x -template -inline StringBuilder::IntInfo<16, T, const char *> sb_lit(T x, int minLen = 2, bool upperCase = true) -{ - return { x, minLen, '0', upperCase, "#$" }; -} diff --git a/src/drivers/Qt/SymbolicDebug.cpp b/src/drivers/Qt/SymbolicDebug.cpp index 2d735d6f..bbba95e3 100644 --- a/src/drivers/Qt/SymbolicDebug.cpp +++ b/src/drivers/Qt/SymbolicDebug.cpp @@ -31,6 +31,7 @@ #include "../../ines.h" #include "../../asm.h" #include "../../x6502.h" +#include "utils/StringBuilder.h" #include "Qt/fceuWrapper.h" #include "Qt/SymbolicDebug.h" diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 7455beac..8cad1663 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -57,6 +57,7 @@ #include "../../movie.h" #include "common/os_utils.h" +#include "utils/StringBuilder.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleWindow.h" diff --git a/src/utils/StringBuilder.h b/src/utils/StringBuilder.h new file mode 100644 index 00000000..2c95e992 --- /dev/null +++ b/src/utils/StringBuilder.h @@ -0,0 +1,164 @@ +#pragma once + +#include +#include +#include + +// Faster replacement functions for sprintf. It's uglier, but much faster. +class StringBuilder +{ +public: + // Helper struct. Do not use directly. + template + struct IntInfo + { + T x; + int minLen; + char leadChar; + bool upperCase; + Prefix prefix; + }; + + inline StringBuilder(char *str) : start(str), end(str) + { + *end = '\0'; + } + + inline char *str() const + { + return start; + } + + inline size_t size() const + { + return size_t(end - start); + } + + inline StringBuilder &operator <<(char ch) + { + *(end++) = ch; + *end = '\0'; + + return *this; + } + + inline StringBuilder &operator <<(const char *src) + { + size_t len = std::strlen(src); + std::memcpy(end, src, len + 1); + + end += len; + + return *this; + } + + template + inline StringBuilder &operator <<(const IntInfo intInfo) + { + *this << intInfo.prefix; + return appendInt(intInfo.x, intInfo.minLen, intInfo.leadChar, intInfo.upperCase); + } + +protected: + inline StringBuilder &operator <<(nullptr_t) + { + return *this; + } + + template + StringBuilder &appendInt(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false) + { + static_assert(Radix >= 2 && Radix <= 36, "Radix must be between 2 and 36"); + static_assert(std::is_integral::value, "T must be an integral type"); + + static const char *upperCaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + *lowerCaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"; + const char *digits = upperCase ? upperCaseDigits : lowerCaseDigits; + + const bool isSigned = std::is_signed::value; + bool isNeg = isSigned && x < 0; + if (isSigned && isNeg) + // This convoluted expression is to silence an unnecessary compiler warning when unsigned + x = T(-((typename std::make_signed::type)(x))); + + unsigned i = 0; + if (x != 0) + { + do + { + end[i++] = digits[x % Radix]; + x /= Radix; + } while (x != 0); + } + else + end[i++] = '0'; + + if (isNeg) + end[i++] = '-'; + + if (minLen < 0) + { + end[i] = '\0'; + + std::reverse(end, end + i); + + for (; i < (unsigned)-minLen; i++) + end[i] = leadChar; + + end[i] = '\0'; + } + else + { + for (; i < (unsigned)minLen; i++) + end[i] = leadChar; + + end[i] = '\0'; + + std::reverse(end, end + i); + } + + end += i; + + return *this; + } + + char *start; + char *end; +}; + +// Formatters for numbers + +// Generic integer with any radius +template +inline StringBuilder::IntInfo sb_int(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false) +{ + return { x, minLen, leadChar, upperCase, nullptr }; +} + +// A decimal number +template +inline StringBuilder::IntInfo<10, T> sb_dec(T x, int minLen = 0, char leadChar = ' ') +{ + return { x, minLen, leadChar, false, nullptr }; +} + +// A hex number +template +inline StringBuilder::IntInfo<16, T> sb_hex(T x, int minLen = 0, bool upperCase = true, char leadChar = '0') +{ + return { x, minLen, leadChar, upperCase, nullptr }; +} + +// An address of the basic form $%x +template +inline StringBuilder::IntInfo<16, T, char> sb_addr(T x, int minLen = 4, bool upperCase = true) +{ + return { x, minLen, '0', upperCase, '$' }; +} + +// A literal value of the form #$%x +template +inline StringBuilder::IntInfo<16, T, const char *> sb_lit(T x, int minLen = 2, bool upperCase = true) +{ + return { x, minLen, '0', upperCase, "#$" }; +}