From 6832eaa9641f26725c8bae57a68d3d157beea3f3 Mon Sep 17 00:00:00 2001 From: harry Date: Sun, 25 Feb 2024 16:08:35 -0500 Subject: [PATCH] Added custom string class that mirrors the C++ std::string API but also allows for fixed size buffers on the stack. This new class also has various C style functions (like sprintf) built into it. --- src/utils/StringUtils.h | 274 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 src/utils/StringUtils.h diff --git a/src/utils/StringUtils.h b/src/utils/StringUtils.h new file mode 100644 index 00000000..ad175808 --- /dev/null +++ b/src/utils/StringUtils.h @@ -0,0 +1,274 @@ +// StringUtils.h +#pragma once + +#include +#include + +#include "types.h" + +extern "C" +{ + // C Style string copy function that guarantees null termination + inline char *Strlcpy( char* dest, const char* src, size_t n ) + { + if (n > 0) + { + size_t i=0; + n--; // minus 1 to make sure we have room for null byte + while ( (i < n) && (src[i] != 0) ) + { + dest[i] = src[i]; i++; + } + dest[i] = 0; // Force Null + } + return dest; + } +}; + +#ifdef __cplusplus + +#include + +// Custom string type that will allows for fixed size strings on using stack memory with a similar C++ std::string API +namespace FCEU +{ + template + class BaseString + { + public: + BaseString(T* buffer = nullptr, size_t size = 0) + { + buf = buffer; + bufSize = size; + end = 0; + } + + BaseString& assign( const T* str ) + { + if (bufSize > 0) + { + size_t i=0; + const size_t bufEnd = bufSize - 1; + while ( (i < bufEnd) && (str[i] != 0) ) + { + buf[i] = str[i]; i++; + } + buf[i] = 0; + end = i; + } + return *this; + } + + BaseString& assign( BaseString& s ) + { + assign( s.buf ); + + return *this; + } + + BaseString& assign( std::string& s ) + { + assign( s.c_str() ); + + return *this; + } + + BaseString& append( const T* str ) + { + if (bufSize > 0) + { + size_t j=0; + size_t i=end; + const size_t bufEnd = bufSize - 1; + while ( (i < bufEnd) && (str[j] != 0) ) + { + buf[i] = str[j]; i++; j++; + } + buf[i] = 0; + end = i; + } + return *this; + } + + BaseString& append( BaseString& s ) + { + append( s.buf ); + + return *this; + } + + BaseString& append( std::string& s ) + { + append( s.c_str() ); + + return *this; + } + + BaseString& operator= (const T* op) + { + assign(op); + + return *this; + } + + BaseString& operator= (BaseString& op) + { + assign(op); + + return *this; + } + + T& operator[] (int idx) + { + return buf[idx]; + } + + void clear() + { + if (bufSize > 0) + { + buf[0] = 0; + } + end = 0; + } + + const T* c_str() + { + return buf; + } + + size_t size() + { + return end; + } + + std::string toStdString() + { + return std::string(c_str()); + } + + int sprintf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 2, 3 ) + { + int retval; + va_list args; + va_start(args, format); + retval = ::vsnprintf( buf, bufSize, format, args); + va_end(args); + return retval; + } + + int append_sprintf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 2, 3 ) + { + int retval; + va_list args; + va_start(args, format); + size_t sizeAvail = 0; + if (bufSize > end) + { + sizeAvail = bufSize - end; + } + retval = ::vsnprintf( &buf[end], sizeAvail, format, args); + va_end(args); + return retval; + } + + long strtol(int base = 10) + { + return ::strtol(buf, nullptr, base); + } + + long long strtoll(int base = 10) + { + return ::strtoll(buf, nullptr, base); + } + + unsigned long strtoul(int base = 10) + { + return ::strtoul(buf, nullptr, base); + } + + unsigned long long strtoull(int base = 10) + { + return ::strtoull(buf, nullptr, base); + } + + private: + T* buf; + size_t bufSize; + size_t end; + + }; + + template + class FixedString : public BaseString + { + public: + FixedString() + : BaseString( fixedBuffer, N ) + { + } + + FixedString(const char* initValue) + : BaseString( fixedBuffer, N ) + { + if (initValue != nullptr) + { + BaseString::assign(initValue); + } + } + + BaseString& operator= (const T* op) + { + BaseString::assign(op); + + return *this; + } + + BaseString& operator= (BaseString& op) + { + BaseString::assign(op); + + return *this; + } + + BaseString& operator= (std::string& op) + { + BaseString::assign(op); + + return *this; + } + + BaseString& operator+= (const T* op) + { + BaseString::append(op); + + return *this; + } + + BaseString& operator+= (BaseString& op) + { + BaseString::append(op); + + return *this; + } + + BaseString& operator+= (std::string& op) + { + BaseString::append(op); + + return *this; + } + + T& operator[] (int idx) + { + return fixedBuffer[idx]; + } + + private: + T fixedBuffer[N]; + }; + + +}; + +#endif