diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 0e4feae4f..3eb3cd005 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -46,8 +46,8 @@ add_library(common settings_interface.h sha1_digest.cpp sha1_digest.h - string.cpp - string.h + small_string.cpp + small_string.h string_util.cpp string_util.h thirdparty/thread_pool.cpp diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index e45b765d8..577354780 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -34,7 +34,7 @@ - + @@ -62,7 +62,7 @@ - + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 8d91fee45..fcfd083bb 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -7,7 +7,7 @@ - + @@ -46,7 +46,7 @@ - + diff --git a/src/common/log.cpp b/src/common/log.cpp index 4e5f18145..140f7fb3e 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -4,7 +4,7 @@ #include "log.h" #include "assert.h" #include "file_system.h" -#include "string.h" +#include "small_string.h" #include "timer.h" #include #include @@ -36,7 +36,7 @@ static LOGLEVEL s_filter_level = LOGLEVEL_TRACE; static Common::Timer::Value s_startTimeStamp = Common::Timer::GetCurrentValue(); static bool s_console_output_enabled = false; -static String s_console_output_channel_filter; +static std::string s_console_output_channel_filter; static LOGLEVEL s_console_output_level_filter = LOGLEVEL_TRACE; #ifdef _WIN32 @@ -46,12 +46,12 @@ static HANDLE s_hConsoleStdErr = NULL; #endif static bool s_debug_output_enabled = false; -static String s_debug_output_channel_filter; +static std::string s_debug_output_channel_filter; static LOGLEVEL s_debug_output_level_filter = LOGLEVEL_TRACE; static bool s_file_output_enabled = false; static bool s_file_output_timestamp = false; -static String s_file_output_channel_filter; +static std::string s_file_output_channel_filter; static LOGLEVEL s_file_output_level_filter = LOGLEVEL_TRACE; std::unique_ptr s_fileOutputHandle(nullptr, [](std::FILE* fp) { if (fp) @@ -242,7 +242,7 @@ static void ConsoleOutputLogCallback(void* pUserParam, const char* channelName, LOGLEVEL level, const char* message) { if (!s_console_output_enabled || level > s_console_output_level_filter || - s_console_output_channel_filter.Find(channelName) >= 0) + s_console_output_channel_filter.find(channelName) != std::string::npos) { return; } @@ -267,7 +267,7 @@ static void DebugOutputLogCallback(void* pUserParam, const char* channelName, co const char* message) { if (!s_debug_output_enabled || level > s_debug_output_level_filter || - s_debug_output_channel_filter.Find(functionName) >= 0) + s_debug_output_channel_filter.find(functionName) != std::string::npos) { return; } @@ -393,7 +393,7 @@ void SetDebugOutputParams(bool enabled, const char* channelFilter /* = nullptr * static void FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, LOGLEVEL level, const char* message) { - if (level > s_file_output_level_filter || s_file_output_channel_filter.Find(channelName) >= 0) + if (level > s_file_output_level_filter || s_file_output_channel_filter.find(channelName) != std::string::npos) return; FormatLogMessageAndPrint( diff --git a/src/common/progress_callback.cpp b/src/common/progress_callback.cpp index b63b10c99..7a6564fd0 100644 --- a/src/common/progress_callback.cpp +++ b/src/common/progress_callback.cpp @@ -18,7 +18,7 @@ void ProgressCallback::SetFormattedStatusText(const char* Format, ...) va_list ap; va_start(ap, Format); - str.FormatVA(Format, ap); + str.format_va(Format, ap); va_end(ap); SetStatusText(str); @@ -30,7 +30,7 @@ void ProgressCallback::DisplayFormattedError(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); DisplayError(str); @@ -42,7 +42,7 @@ void ProgressCallback::DisplayFormattedWarning(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); DisplayWarning(str); @@ -54,7 +54,7 @@ void ProgressCallback::DisplayFormattedInformation(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); DisplayInformation(str); @@ -66,7 +66,7 @@ void ProgressCallback::DisplayFormattedDebugMessage(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); DisplayDebugMessage(str); @@ -78,7 +78,7 @@ void ProgressCallback::DisplayFormattedModalError(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); ModalError(str); @@ -90,7 +90,7 @@ bool ProgressCallback::DisplayFormattedModalConfirmation(const char* format, ... va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); return ModalConfirmation(str); @@ -102,7 +102,7 @@ void ProgressCallback::DisplayFormattedModalInformation(const char* format, ...) va_list ap; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); ModalInformation(str); @@ -312,10 +312,10 @@ void ConsoleProgressCallback::Clear() { SmallString message; for (u32 i = 0; i < COLUMNS; i++) - message.AppendCharacter(' '); - message.AppendCharacter('\r'); + message.append(' '); + message.append('\r'); - std::fwrite(message.GetCharArray(), message.GetLength(), 1, stderr); + std::fwrite(message.c_str(), message.length(), 1, stderr); std::fflush(stderr); } @@ -325,7 +325,7 @@ void ConsoleProgressCallback::Redraw(bool update_value_only) if (percent_complete > 100.0f) percent_complete = 100.0f; - const u32 current_length = m_status_text.GetLength() + 14; + const u32 current_length = static_cast(m_status_text.length()) + 14; const u32 max_bar_length = (current_length < COLUMNS) ? COLUMNS - current_length : 0; const u32 current_bar_length = (max_bar_length > 0) ? (static_cast(percent_complete / 100.0f * (float)max_bar_length)) : 0; @@ -340,25 +340,25 @@ void ConsoleProgressCallback::Redraw(bool update_value_only) m_last_percent_complete = percent_complete; SmallString message; - message.AppendString(m_status_text); - message.AppendFormattedString(" [%.2f%%]", percent_complete); + message.append(m_status_text); + message.append_fmt(" [{:.2f}%]", percent_complete); if (max_bar_length > 0) { - message.AppendString(" |"); + message.append(" |"); u32 i; for (i = 0; i < current_bar_length; i++) - message.AppendCharacter('='); + message.append('='); for (; i < max_bar_length; i++) - message.AppendCharacter(' '); + message.append(' '); - message.AppendString("|"); + message.append('|'); } - message.AppendCharacter('\r'); + message.append('\r'); - std::fwrite(message.GetCharArray(), message.GetLength(), 1, stderr); + std::fwrite(message.c_str(), message.length(), 1, stderr); std::fflush(stderr); } diff --git a/src/common/progress_callback.h b/src/common/progress_callback.h index 2ce1951c3..425ddd633 100644 --- a/src/common/progress_callback.h +++ b/src/common/progress_callback.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "string.h" +#include "small_string.h" #include "types.h" class ByteStream; @@ -73,7 +73,7 @@ protected: struct State { State* next_saved_state; - String status_text; + std::string status_text; u32 progress_range; u32 progress_value; u32 base_progress_value; @@ -82,7 +82,7 @@ protected: bool m_cancellable; bool m_cancelled; - String m_status_text; + std::string m_status_text; u32 m_progress_range; u32 m_progress_value; diff --git a/src/common/small_string.cpp b/src/common/small_string.cpp new file mode 100644 index 000000000..cffee6ead --- /dev/null +++ b/src/common/small_string.cpp @@ -0,0 +1,699 @@ +// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#include "small_string.h" +#include "assert.h" + +#include +#include +#include +#include + +#ifdef _MSC_VER +#define CASE_COMPARE _stricmp +#define CASE_N_COMPARE _strnicmp +#else +#define CASE_COMPARE strcasecmp +#define CASE_N_COMPARE strncasecmp +#endif + +SmallStringBase::SmallStringBase() = default; + +SmallStringBase::SmallStringBase(const SmallStringBase& copy) +{ + assign(copy.m_buffer, copy.m_length); +} + +SmallStringBase::SmallStringBase(const char* str) +{ + assign(str); +} + +SmallStringBase::SmallStringBase(const char* str, u32 count) +{ + assign(str, count); +} + +SmallStringBase::SmallStringBase(SmallStringBase&& move) +{ + assign(std::move(move)); +} + +SmallStringBase::SmallStringBase(const std::string_view& sv) +{ + assign(sv); +} + +SmallStringBase::SmallStringBase(const std::string& str) +{ + assign(str); +} + +SmallStringBase::~SmallStringBase() +{ + if (m_on_heap) + std::free(m_buffer); +} + +void SmallStringBase::reserve(u32 new_reserve) +{ + if (m_buffer_size >= new_reserve) + return; + + if (m_on_heap) + { + char* new_ptr = static_cast(std::realloc(m_buffer, new_reserve)); + if (!new_ptr) + Panic("Memory allocation failed."); + +#ifdef _DEBUG + std::memset(new_ptr + m_length, 0, new_reserve - m_length); +#endif + m_buffer = new_ptr; + } + else + { + char* new_ptr = static_cast(std::malloc(new_reserve)); + if (!new_ptr) + Panic("Memory allocation failed."); + + if (m_length > 0) + std::memcpy(new_ptr, m_buffer, m_length); +#ifdef _DEBUG + std::memset(new_ptr + m_length, 0, new_reserve - m_length); +#else + new_ptr[m_length] = 0; +#endif + m_buffer = new_ptr; + m_on_heap = true; + } +} + +void SmallStringBase::shrink_to_fit() +{ + if (!m_on_heap || m_length == m_buffer_size) + return; + + if (m_length == 0) + { + std::free(m_buffer); + m_buffer_size = 0; + return; + } + + char* new_ptr = static_cast(std::realloc(m_buffer, m_length)); + if (!new_ptr) + Panic("Memory allocation failed."); + + m_buffer = new_ptr; + m_buffer_size = m_length; +} + +std::string_view SmallStringBase::view() const +{ + return (m_length == 0) ? std::string_view() : std::string_view(m_buffer, m_length); +} + +SmallStringBase& SmallStringBase::operator=(SmallStringBase&& move) +{ + assign(move); + return *this; +} + +SmallStringBase& SmallStringBase::operator=(const std::string_view& str) +{ + assign(str); + return *this; +} + +SmallStringBase& SmallStringBase::operator=(const std::string& str) +{ + assign(str); + return *this; +} + +SmallStringBase& SmallStringBase::operator=(const char* str) +{ + assign(str); + return *this; +} + +SmallStringBase& SmallStringBase::operator=(const SmallStringBase& copy) +{ + assign(copy); + return *this; +} + +void SmallStringBase::make_room_for(u32 space) +{ + const u32 required_size = m_length + space + 1; + if (m_buffer_size >= required_size) + return; + + reserve(std::max(required_size, m_buffer_size * 2)); +} + +void SmallStringBase::append(const char* str, u32 length) +{ + if (length == 0) + return; + + make_room_for(length); + + DebugAssert((length + m_length) < m_buffer_size); + + std::memcpy(m_buffer + m_length, str, length); + m_length += length; + m_buffer[m_length] = 0; +} + +void SmallStringBase::prepend(const char* str, u32 length) +{ + if (length == 0) + return; + + make_room_for(length); + + DebugAssert((length + m_length) < m_buffer_size); + + std::memmove(m_buffer + length, m_buffer, m_length); + std::memcpy(m_buffer, str, length); + m_length += length; + m_buffer[m_length] = 0; +} + +void SmallStringBase::append(char c) +{ + append(&c, 1); +} + +void SmallStringBase::append(const SmallStringBase& str) +{ + append(str.m_buffer, str.m_length); +} + +void SmallStringBase::append(const char* str) +{ + append(str, static_cast(std::strlen(str))); +} + +void SmallStringBase::append(const std::string& str) +{ + append(str.c_str(), static_cast(str.length())); +} + +void SmallStringBase::append(const std::string_view& str) +{ + append(str.data(), static_cast(str.length())); +} + +void SmallStringBase::append_format(const char* format, ...) +{ + std::va_list ap; + va_start(ap, format); + append_format_va(format, ap); + va_end(ap); +} + +void SmallStringBase::append_format_va(const char* format, va_list ap) +{ + // We have a 1KB byte buffer on the stack here. If this is too little, we'll grow it via the heap, + // but 1KB should be enough for most strings. + char stack_buffer[1024]; + char* heap_buffer = nullptr; + char* buffer = stack_buffer; + u32 buffer_size = static_cast(std::size(stack_buffer)); + u32 written; + + for (;;) + { + std::va_list ap_copy; + va_copy(ap_copy, ap); + const int ret = std::vsnprintf(buffer, buffer_size, format, ap_copy); + va_end(ap_copy); + if (ret < 0 || ((u32)ret >= (buffer_size - 1))) + { + buffer_size *= 2; + buffer = heap_buffer = reinterpret_cast(std::realloc(heap_buffer, buffer_size)); + continue; + } + + written = static_cast(ret); + break; + } + + append(buffer, written); + + if (heap_buffer) + std::free(heap_buffer); +} + +void SmallStringBase::prepend(char c) +{ + prepend(&c, 1); +} + +void SmallStringBase::prepend(const SmallStringBase& str) +{ + prepend(str.m_buffer, str.m_length); +} + +void SmallStringBase::prepend(const char* str) +{ + prepend(str, static_cast(std::strlen(str))); +} + +void SmallStringBase::prepend(const std::string& str) +{ + prepend(str.c_str(), static_cast(str.length())); +} + +void SmallStringBase::prepend(const std::string_view& str) +{ + prepend(str.data(), static_cast(str.length())); +} + +void SmallStringBase::prepend_format(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + prepend_format_va(format, ap); + va_end(ap); +} + +void SmallStringBase::prepend_format_va(const char* format, va_list ArgPtr) +{ + // We have a 1KB byte buffer on the stack here. If this is too little, we'll grow it via the heap, + // but 1KB should be enough for most strings. + char stack_buffer[1024]; + char* heap_buffer = NULL; + char* buffer = stack_buffer; + u32 buffer_size = static_cast(std::size(stack_buffer)); + u32 written; + + for (;;) + { + int ret = std::vsnprintf(buffer, buffer_size, format, ArgPtr); + if (ret < 0 || (static_cast(ret) >= (buffer_size - 1))) + { + buffer_size *= 2; + buffer = heap_buffer = reinterpret_cast(std::realloc(heap_buffer, buffer_size)); + continue; + } + + written = static_cast(ret); + break; + } + + prepend(buffer, written); + + if (heap_buffer) + std::free(heap_buffer); +} + +void SmallStringBase::insert(s32 offset, const char* str) +{ + insert(offset, str, static_cast(std::strlen(str))); +} + +void SmallStringBase::insert(s32 offset, const SmallStringBase& str) +{ + insert(offset, str, str.m_length); +} + +void SmallStringBase::insert(s32 offset, const char* str, u32 length) +{ + if (length == 0) + return; + + make_room_for(length); + + // calc real offset + u32 real_offset; + if (offset < 0) + real_offset = static_cast(std::max(0, static_cast(m_length) + offset)); + else + real_offset = std::min(static_cast(offset), m_length); + + // determine number of characters after offset + DebugAssert(real_offset <= m_length); + const u32 chars_after_offset = m_length - real_offset; + if (chars_after_offset > 0) + std::memmove(m_buffer + offset + length, m_buffer + offset, chars_after_offset); + + // insert the string + std::memcpy(m_buffer + real_offset, str, length); + m_length += length; + + // ensure null termination + m_buffer[m_length] = 0; +} + +void SmallStringBase::insert(s32 offset, const std::string& str) +{ + insert(offset, str.c_str(), static_cast(str.size())); +} + +void SmallStringBase::insert(s32 offset, const std::string_view& str) +{ + insert(offset, str.data(), static_cast(str.size())); +} + +void SmallStringBase::format(const char* format, ...) +{ + va_list ap; + va_start(ap, format); + format_va(format, ap); + va_end(ap); +} + +void SmallStringBase::format_va(const char* format, va_list ap) +{ + clear(); + append_format_va(format, ap); +} + +void SmallStringBase::assign(const SmallStringBase& copy) +{ + assign(copy.c_str(), copy.length()); +} + +void SmallStringBase::assign(const char* str) +{ + assign(str, static_cast(std::strlen(str))); +} + +void SmallStringBase::assign(const char* str, u32 length) +{ + clear(); + if (length > 0) + append(str, length); +} + +void SmallStringBase::assign(SmallStringBase&& move) +{ + if (move.m_on_heap) + { + if (m_on_heap) + std::free(m_buffer); + m_buffer = move.m_buffer; + m_buffer_size = move.m_buffer_size; + m_length = move.m_length; + m_on_heap = true; + move.m_buffer = nullptr; + move.m_buffer_size = 0; + move.m_length = 0; + } + else + { + assign(move.m_buffer, move.m_buffer_size); + } +} + +void SmallStringBase::assign(const std::string& str) +{ + clear(); + append(str.data(), static_cast(str.size())); +} + +void SmallStringBase::assign(const std::string_view& str) +{ + clear(); + append(str.data(), static_cast(str.size())); +} + +bool SmallStringBase::equals(const char* str) const +{ + if (m_length == 0) + return (std::strlen(str) == 0); + else + return (std::strcmp(m_buffer, str) == 0); +} + +bool SmallStringBase::equals(const SmallStringBase& str) const +{ + return (m_length == str.m_length && (m_length == 0 || std::strcmp(m_buffer, str.m_buffer) == 0)); +} + +bool SmallStringBase::equals(const std::string_view& str) const +{ + return (m_length == static_cast(str.length()) && + (m_length == 0 || CASE_N_COMPARE(m_buffer, str.data(), m_length) == 0)); +} + +bool SmallStringBase::iequals(const char* otherText) const +{ + if (m_length == 0) + return (std::strlen(otherText) == 0); + else + return (CASE_COMPARE(m_buffer, otherText) == 0); +} + +bool SmallStringBase::iequals(const SmallStringBase& str) const +{ + return (m_length == str.m_length && (m_length == 0 || std::strcmp(m_buffer, str.m_buffer) == 0)); +} + +bool SmallStringBase::iequals(const std::string_view& str) const +{ + return (m_length == static_cast(str.length()) && + (m_length == 0 || CASE_N_COMPARE(m_buffer, str.data(), m_length) == 0)); +} + +int SmallStringBase::compare(const SmallStringBase& str) const +{ + return std::strcmp(m_buffer, str.m_buffer); +} + +int SmallStringBase::compare(const char* otherText) const +{ + return std::strcmp(m_buffer, otherText); +} + +int SmallStringBase::icompare(const SmallStringBase& otherString) const +{ + return CASE_COMPARE(m_buffer, otherString.m_buffer); +} + +int SmallStringBase::icompare(const char* otherText) const +{ + return CASE_COMPARE(m_buffer, otherText); +} + +bool SmallStringBase::starts_with(const char* str, bool case_sensitive) const +{ + const u32 other_length = static_cast(std::strlen(str)); + if (other_length > m_length) + return false; + + return (case_sensitive) ? (std::strncmp(str, m_buffer, other_length) == 0) : + (CASE_N_COMPARE(str, m_buffer, other_length) == 0); +} + +bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitive) const +{ + const u32 other_length = str.m_length; + if (other_length > m_length) + return false; + + return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer, other_length) == 0) : + (CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0); +} + +bool SmallStringBase::starts_with(const std::string_view& str, bool case_sensitive) const +{ + const u32 other_length = static_cast(str.length()); + if (other_length > m_length) + return false; + + return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) : + (CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0); +} + +bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const +{ + const u32 other_length = static_cast(std::strlen(str)); + if (other_length > m_length) + return false; + + u32 start_offset = m_length - other_length; + return (case_sensitive) ? (std::strncmp(str, m_buffer + start_offset, other_length) == 0) : + (CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0); +} + +bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive) const +{ + const u32 other_length = str.m_length; + if (other_length > m_length) + return false; + + const u32 start_offset = m_length - other_length; + return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer + start_offset, other_length) == 0) : + (CASE_N_COMPARE(str.m_buffer, m_buffer + start_offset, other_length) == 0); +} + +bool SmallStringBase::ends_with(const std::string_view& str, bool case_sensitive) const +{ + const u32 other_length = static_cast(str.length()); + if (other_length > m_length) + return false; + + const u32 start_offset = m_length - other_length; + return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) : + (CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0); +} + +void SmallStringBase::clear() +{ + // in debug, zero whole string, in release, zero only the first character +#if _DEBUG + std::memset(m_buffer, 0, m_buffer_size); +#else + m_buffer[0] = '\0'; +#endif + m_length = 0; +} + +s32 SmallStringBase::find(char c, u32 offset) const +{ + if (m_length == 0) + return -1; + + DebugAssert(offset <= m_length); + const char* at = std::strchr(m_buffer + offset, c); + return at ? static_cast(at - m_buffer) : -1; +} + +s32 SmallStringBase::rfind(char c, u32 offset) const +{ + if (m_length == 0) + return -1; + + DebugAssert(offset <= m_length); + const char* at = std::strrchr(m_buffer + offset, c); + return at ? static_cast(at - m_buffer) : -1; +} + +s32 SmallStringBase::find(const char* str, u32 offset) const +{ + if (m_length == 0) + return -1; + + DebugAssert(offset <= m_length); + const char* at = std::strstr(m_buffer + offset, str); + return at ? static_cast(at - m_buffer) : -1; +} + +void SmallStringBase::resize(u32 new_size, char fill, bool shrink_if_smaller) +{ + // if going larger, or we don't own the buffer, realloc + if (new_size >= m_buffer_size) + { + reserve(new_size); + + if (m_length < new_size) + { + std::memset(m_buffer + m_length, fill, m_buffer_size - m_length - 1); + } + + m_length = new_size; + } + else + { + // update length and terminator +#if _DEBUG + std::memset(m_buffer + new_size, 0, m_buffer_size - new_size); +#else + m_buffer[new_size] = 0; +#endif + m_length = new_size; + + // shrink if requested + if (shrink_if_smaller) + shrink_to_fit(); + } +} + +void SmallStringBase::update_size() +{ + m_length = static_cast(std::strlen(m_buffer)); +} + +std::string_view SmallStringBase::substr(s32 offset, s32 count) const +{ + // calc real offset + u32 real_offset; + if (offset < 0) + real_offset = static_cast(std::max(0, static_cast(m_length + offset))); + else + real_offset = std::min((u32)offset, m_length); + + // calc real count + u32 real_count; + if (count < 0) + { + real_count = + std::min(m_length - real_offset, static_cast(std::max(0, static_cast(m_length) + count))); + } + else + { + real_count = std::min(m_length - real_offset, static_cast(count)); + } + + return (real_count > 0) ? std::string_view(m_buffer + real_offset, real_count) : std::string_view(); +} + +void SmallStringBase::erase(s32 offset, s32 count) +{ + // calc real offset + u32 real_offset; + if (offset < 0) + real_offset = static_cast(std::max(0, static_cast(m_length + offset))); + else + real_offset = std::min((u32)offset, m_length); + + // calc real count + u32 real_count; + if (count < 0) + { + real_count = + std::min(m_length - real_offset, static_cast(std::max(0, static_cast(m_length) + count))); + } + else + { + real_count = std::min(m_length - real_offset, static_cast(count)); + } + + // Fastpath: offset == 0, count < 0, wipe whole string. + if (real_offset == 0 && real_count == m_length) + { + clear(); + return; + } + + // Fastpath: offset >= 0, count < 0, wipe everything after offset + count + if ((real_offset + real_count) == m_length) + { + m_length -= real_count; +#ifdef _DEBUG + std::memset(m_buffer + m_length, 0, m_buffer_size - m_length); +#else + m_buffer[m_length] = 0; +#endif + } + // Slowpath: offset >= 0, count < length + else + { + const u32 after_erase_block = m_length - real_offset - real_count; + DebugAssert(after_erase_block > 0); + + std::memmove(m_buffer + offset, m_buffer + real_offset + real_count, after_erase_block); + m_length = m_length - real_count; + +#ifdef _DEBUG + std::memset(m_buffer + m_length, 0, m_buffer_size - m_length); +#else + m_buffer[m_length] = 0; +#endif + } +} diff --git a/src/common/small_string.h b/src/common/small_string.h new file mode 100644 index 000000000..15ae54ddc --- /dev/null +++ b/src/common/small_string.h @@ -0,0 +1,343 @@ +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#pragma once +#include "types.h" + +#include "fmt/core.h" + +#include +#include +#include +#include +#include +#include + +// +// SmallString +// Lightweight string class which can be allocated on the stack, instead of with heap allocations. +// +class SmallStringBase +{ +public: + using value_type = char; + + SmallStringBase(); + SmallStringBase(const char* str); + SmallStringBase(const char* str, u32 length); + SmallStringBase(const SmallStringBase& copy); + SmallStringBase(SmallStringBase&& move); + SmallStringBase(const std::string& str); + SmallStringBase(const std::string_view& sv); + + // Destructor. Child classes may not have any destructors, as this is not virtual. + ~SmallStringBase(); + + // manual assignment + void assign(const char* str); + void assign(const char* str, u32 length); + void assign(const std::string& copy); + void assign(const std::string_view& copy); + void assign(const SmallStringBase& copy); + void assign(SmallStringBase&& move); + + // Ensures that we have space bytes free in the buffer. + void make_room_for(u32 space); + + // clears the contents of the string + void clear(); + + // append a single character to this string + void append(char c); + + // append a string to this string + void append(const char* appendText); + void append(const char* str, u32 length); + void append(const std::string& str); + void append(const std::string_view& str); + void append(const SmallStringBase& str); + + // append formatted string to this string + void append_format(const char* format, ...) printflike(2, 3); + void append_format_va(const char* format, va_list ap); + + template + void append_fmt(fmt::format_string fmt, T&&... args); + + // append a single character to this string + void prepend(char c); + + // append a string to this string + void prepend(const char* str); + void prepend(const char* str, u32 length); + void prepend(const std::string& str); + void prepend(const std::string_view& str); + void prepend(const SmallStringBase& str); + + // append formatted string to this string + void prepend_format(const char* format, ...) printflike(2, 3); + void prepend_format_va(const char* format, va_list ap); + + template + void prepend_fmt(fmt::format_string fmt, T&&... args); + + // insert a string at the specified offset + void insert(s32 offset, const char* str); + void insert(s32 offset, const char* str, u32 length); + void insert(s32 offset, const std::string& str); + void insert(s32 offset, const std::string_view& str); + void insert(s32 offset, const SmallStringBase& str); + + // set to formatted string + void format(const char* format, ...) printflike(2, 3); + void format_va(const char* format, va_list ap); + + template + void fmt(fmt::format_string fmt, T&&... args); + + // compare one string to another + bool equals(const char* str) const; + bool equals(const SmallStringBase& str) const; + bool equals(const std::string_view& str) const; + bool iequals(const char* str) const; + bool iequals(const SmallStringBase& str) const; + bool iequals(const std::string_view& str) const; + + // numerical compares + int compare(const char* str) const; + int compare(const SmallStringBase& str) const; + int compare(const std::string_view& str) const; + int icompare(const char* str) const; + int icompare(const SmallStringBase& str) const; + int icompare(const std::string_view& str) const; + + // starts with / ends with + bool starts_with(const char* str, bool case_sensitive = true) const; + bool starts_with(const std::string_view& str, bool case_sensitive = true) const; + bool starts_with(const SmallStringBase& str, bool case_sensitive = true) const; + bool ends_with(const char* str, bool case_sensitive = true) const; + bool ends_with(const std::string_view& str, bool case_sensitive = true) const; + bool ends_with(const SmallStringBase& str, bool case_sensitive = true) const; + + // searches for a character inside a string + // rfind is the same except it starts at the end instead of the start + // returns -1 if it is not found, otherwise the offset in the string + s32 find(char c, u32 offset = 0) const; + s32 rfind(char c, u32 offset = 0) const; + + // searches for a string inside a string + // rfind is the same except it starts at the end instead of the start + // returns -1 if it is not found, otherwise the offset in the string + s32 find(const char* str, u32 offset = 0) const; + + // removes characters from string + void erase(s32 offset, s32 count = std::numeric_limits::max()); + + // alters the length of the string to be at least len bytes long + void reserve(u32 new_reserve); + + // Cuts characters off the string to reduce it to len bytes long. + void resize(u32 new_size, char fill = ' ', bool shrink_if_smaller = false); + + // updates the internal length counter when the string is externally modified + void update_size(); + + // shrink the string to the minimum size possible + void shrink_to_fit(); + + // gets the size of the string + ALWAYS_INLINE u32 length() const { return m_length; } + ALWAYS_INLINE bool empty() const { return (m_length == 0); } + + // gets the maximum number of bytes we can write to the string, currently + ALWAYS_INLINE u32 buffer_size() const { return m_buffer_size; } + + // gets a constant pointer to the C string + ALWAYS_INLINE const char* c_str() const { return m_buffer; } + + // gets a writable char array, do not write more than reserve characters to it. + ALWAYS_INLINE char* data() { return m_buffer; } + + // returns the end of the string (pointer is past the last character) + ALWAYS_INLINE const char* end_ptr() const { return m_buffer + m_length; } + + // STL adapters + ALWAYS_INLINE void push_back(value_type&& val) { append(val); } + + // returns a string view for this string + std::string_view view() const; + + // returns a substring view for this string + std::string_view substr(s32 offset, s32 count) const; + + // accessor operators + ALWAYS_INLINE operator const char*() const { return c_str(); } + ALWAYS_INLINE operator char*() { return data(); } + ALWAYS_INLINE operator std::string_view() const { return view(); } + + // comparative operators + ALWAYS_INLINE bool operator==(const char* str) const { return equals(str); } + ALWAYS_INLINE bool operator==(const SmallStringBase& str) const { return equals(str); } + ALWAYS_INLINE bool operator==(const std::string_view& str) const { return equals(str); } + ALWAYS_INLINE bool operator!=(const char* str) const { return !equals(str); } + ALWAYS_INLINE bool operator!=(const SmallStringBase& str) const { return !equals(str); } + ALWAYS_INLINE bool operator!=(const std::string_view& str) const { return !equals(str); } + ALWAYS_INLINE bool operator<(const char* str) const { return (compare(str) < 0); } + ALWAYS_INLINE bool operator<(const SmallStringBase& str) const { return (compare(str) < 0); } + ALWAYS_INLINE bool operator<(const std::string_view& str) const { return (compare(str) < 0); } + ALWAYS_INLINE bool operator>(const char* str) const { return (compare(str) > 0); } + ALWAYS_INLINE bool operator>(const SmallStringBase& str) const { return (compare(str) > 0); } + ALWAYS_INLINE bool operator>(const std::string_view& str) const { return (compare(str) > 0); } + + SmallStringBase& operator=(const SmallStringBase& copy); + SmallStringBase& operator=(const char* str); + SmallStringBase& operator=(const std::string& str); + SmallStringBase& operator=(const std::string_view& str); + SmallStringBase& operator=(SmallStringBase&& move); + +protected: + // Pointer to memory where the string is located + char* m_buffer = nullptr; + + // Length of the string located in pBuffer (in characters) + u32 m_length = 0; + + // Size of the buffer pointed to by pBuffer + u32 m_buffer_size = 0; + + // True if the string is dynamically allocated on the heap. + bool m_on_heap = false; +}; + +// stack-allocated string +template +class SmallStackString : public SmallStringBase +{ +public: + ALWAYS_INLINE SmallStackString() { init(); } + + ALWAYS_INLINE SmallStackString(const char* str) + { + init(); + assign(str); + } + + ALWAYS_INLINE SmallStackString(const char* str, u32 length) + { + init(); + assign(str, length); + } + + ALWAYS_INLINE SmallStackString(const SmallStringBase& copy) + { + init(); + assign(copy); + } + + ALWAYS_INLINE SmallStackString(SmallStringBase&& move) + { + init(); + assign(move); + } + + ALWAYS_INLINE SmallStackString(const std::string_view& sv) + { + init(); + assign(sv); + } + + // Override the fromstring method + static SmallStackString from_format(const char* format, ...) printflike(1, 2); + + template + static SmallStackString from_fmt(fmt::format_string fmt, T&&... args); + +private: + char m_stack_buffer[L + 1]; + + ALWAYS_INLINE void init() + { + m_buffer = m_stack_buffer; + m_buffer_size = L + 1; + +#ifdef _DEBUG + std::memset(m_stack_buffer, 0, sizeof(m_stack_buffer)); +#else + m_stack_buffer[0] = '\0'; +#endif + } +}; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4459) // warning C4459: declaration of 'uint' hides global declaration +#endif + +template +ALWAYS_INLINE SmallStackString SmallStackString::from_format(const char* format, ...) +{ + std::va_list ap; + va_start(ap, format); + + SmallStackString ret; + ret.format_va(format, ap); + + va_end(ap); + + return ret; +} + +template +template +ALWAYS_INLINE SmallStackString SmallStackString::from_fmt(fmt::format_string fmt, T&&... args) +{ + SmallStackString ret; + fmt::vformat_to(std::back_inserter(ret), fmt, fmt::make_format_args(args...)); + return ret; +} + +// stack string types +using TinyString = SmallStackString<64>; +using SmallString = SmallStackString<256>; +using LargeString = SmallStackString<512>; + +template +ALWAYS_INLINE void SmallStringBase::append_fmt(fmt::format_string fmt, T&&... args) +{ + fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...)); +} + +template +ALWAYS_INLINE void SmallStringBase::prepend_fmt(fmt::format_string fmt, T&&... args) +{ + TinyString str; + fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...)); + prepend(str); +} + +template +ALWAYS_INLINE void SmallStringBase::fmt(fmt::format_string fmt, T&&... args) +{ + clear(); + fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...)); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +template<> +struct fmt::formatter +{ + template + constexpr auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(const SmallStringBase& str, FormatContext& ctx) + { + return fmt::format_to(ctx.out(), "{}", str.view()); + } +}; diff --git a/src/common/string.cpp b/src/common/string.cpp deleted file mode 100644 index dc7593586..000000000 --- a/src/common/string.cpp +++ /dev/null @@ -1,1103 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "string.h" -#include "assert.h" -#include -#include -#include -#include - -#ifdef _MSC_VER -#define CASE_COMPARE _stricmp -#define CASE_N_COMPARE _strnicmp -#else -#define CASE_COMPARE strcasecmp -#define CASE_N_COMPARE strncasecmp -#endif - -// globals -const String::StringData String::s_EmptyStringData = {const_cast(""), 0, 1, -1, true}; -const String EmptyString; - -// helper functions -static String::StringData* StringDataAllocate(u32 allocSize) -{ - DebugAssert(allocSize > 0); - - String::StringData* pStringData = - reinterpret_cast(std::malloc(sizeof(String::StringData) + allocSize)); - pStringData->pBuffer = reinterpret_cast(pStringData + 1); - pStringData->StringLength = 0; - pStringData->BufferSize = allocSize; - pStringData->ReadOnly = false; - pStringData->ReferenceCount = 1; - - // if in debug build, set all to zero, otherwise only the first to zero. -#ifdef _DEBUG - std::memset(pStringData->pBuffer, 0, allocSize); -#else - pStringData->pBuffer[0] = 0; - if (allocSize > 1) - pStringData->pBuffer[allocSize - 1] = 0; -#endif - - return pStringData; -} - -static inline void StringDataAddRef(String::StringData* pStringData) -{ - DebugAssert(pStringData->ReferenceCount > 0); - ++pStringData->ReferenceCount; -} - -static inline void StringDataRelease(String::StringData* pStringData) -{ - if (pStringData->ReferenceCount == -1) - return; - - DebugAssert(pStringData->ReferenceCount > 0); - u32 newRefCount = --pStringData->ReferenceCount; - if (!newRefCount) - std::free(pStringData); -} - -static String::StringData* StringDataClone(const String::StringData* pStringData, u32 newSize, bool copyPastString) -{ - DebugAssert(newSize >= 0); - - String::StringData* pClone = StringDataAllocate(newSize); - if (pStringData->StringLength > 0) - { - u32 copyLength; - - if (copyPastString) - { - copyLength = std::min(newSize, pStringData->BufferSize); - if (copyLength > 0) - { - std::memcpy(pClone->pBuffer, pStringData->pBuffer, copyLength); - if (copyLength < pStringData->BufferSize) - pClone->pBuffer[copyLength - 1] = 0; - } - } - else - { - copyLength = std::min(newSize, pStringData->StringLength); - if (copyLength > 0) - { - std::memcpy(pClone->pBuffer, pStringData->pBuffer, copyLength); - pClone->pBuffer[copyLength] = 0; - } - } - - pClone->StringLength = copyLength; - } - - return pClone; -} - -static String::StringData* StringDataReallocate(String::StringData* pStringData, u32 newSize) -{ - DebugAssert(newSize > pStringData->StringLength); - DebugAssert(pStringData->ReferenceCount == 1); - - // perform realloc - pStringData = reinterpret_cast(std::realloc(pStringData, sizeof(String::StringData) + newSize)); - pStringData->pBuffer = reinterpret_cast(pStringData + 1); - - // zero bytes in debug -#ifdef _DEBUG - if (newSize > pStringData->BufferSize) - { - u32 bytesToZero = newSize - pStringData->BufferSize; - std::memset(pStringData->pBuffer + (newSize - bytesToZero), 0, bytesToZero); - } -#else - if (newSize > pStringData->BufferSize) - { - pStringData->pBuffer[newSize - 1] = 0; - } -#endif - - // update size - pStringData->BufferSize = newSize; - return pStringData; -} - -static bool StringDataIsSharable(const String::StringData* pStringData) -{ - return pStringData->ReadOnly || pStringData->ReferenceCount != -1; -} - -static bool StringDataIsShared(const String::StringData* pStringData) -{ - return pStringData->ReferenceCount > 1; -} - -String::String() : m_pStringData(const_cast(&s_EmptyStringData)) {} - -String::String(const String& copyString) -{ - // special case: empty strings - if (copyString.IsEmpty()) - { - m_pStringData = const_cast(&s_EmptyStringData); - } - // is the string data sharable? - else if (StringDataIsSharable(copyString.m_pStringData)) - { - m_pStringData = copyString.m_pStringData; - if (!m_pStringData->ReadOnly) - StringDataAddRef(m_pStringData); - } - // create a clone for ourselves - else - { - // since we're going to the effort of creating a clone, we might as well create it as the smallest size possible - m_pStringData = StringDataClone(copyString.m_pStringData, copyString.m_pStringData->StringLength + 1, false); - } -} - -String::String(const char* Text) : m_pStringData(const_cast(&s_EmptyStringData)) -{ - Assign(Text); -} - -String::String(const char* Text, u32 Count) : m_pStringData(const_cast(&s_EmptyStringData)) -{ - AppendString(Text, Count); -} - -String::String(String&& moveString) -{ - Assign(moveString); -} - -String::String(const std::string_view& sv) -{ - AppendString(sv.data(), static_cast(sv.size())); -} - -String::~String() -{ - StringDataRelease(m_pStringData); -} - -void String::EnsureOwnWritableCopy() -{ - if (StringDataIsShared(m_pStringData) || m_pStringData->ReadOnly) - { - StringData* pNewStringData = StringDataClone(m_pStringData, m_pStringData->StringLength + 1, false); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - } -} - -void String::EnsureRemainingSpace(u32 spaceRequired) -{ - StringData* pNewStringData; - u32 requiredReserve = m_pStringData->StringLength + spaceRequired + 1; - - if (StringDataIsShared(m_pStringData) || m_pStringData->ReadOnly) - { - pNewStringData = StringDataClone(m_pStringData, std::max(requiredReserve, m_pStringData->BufferSize), false); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - } - else if (m_pStringData->BufferSize < requiredReserve) - { - u32 newSize = std::max(requiredReserve, m_pStringData->BufferSize * 2); - - // if we are the only owner of the buffer, we can simply realloc it - if (m_pStringData->ReferenceCount == 1) - { - // do realloc and update pointer - m_pStringData = StringDataReallocate(m_pStringData, newSize); - } - else - { - // clone and release old - pNewStringData = StringDataClone(m_pStringData, std::max(requiredReserve, newSize), false); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - } - } -} - -void String::InternalAppend(const char* pString, u32 Length) -{ - EnsureRemainingSpace(Length); - - DebugAssert((Length + m_pStringData->StringLength) < m_pStringData->BufferSize); - DebugAssert(m_pStringData->ReferenceCount <= 1 && !m_pStringData->ReadOnly); - - std::memcpy(m_pStringData->pBuffer + m_pStringData->StringLength, pString, Length); - m_pStringData->StringLength += Length; - m_pStringData->pBuffer[m_pStringData->StringLength] = 0; -} - -void String::InternalPrepend(const char* pString, u32 Length) -{ - EnsureRemainingSpace(Length); - - DebugAssert((Length + m_pStringData->StringLength) < m_pStringData->BufferSize); - DebugAssert(m_pStringData->ReferenceCount <= 1 && !m_pStringData->ReadOnly); - - std::memmove(m_pStringData->pBuffer + Length, m_pStringData->pBuffer, m_pStringData->StringLength); - std::memcpy(m_pStringData->pBuffer, pString, Length); - m_pStringData->StringLength += Length; - m_pStringData->pBuffer[m_pStringData->StringLength] = 0; -} - -void String::AppendCharacter(char c) -{ - InternalAppend(&c, 1); -} - -void String::AppendString(const String& appendStr) -{ - if (appendStr.GetLength() > 0) - InternalAppend(appendStr.GetCharArray(), appendStr.GetLength()); -} - -void String::AppendString(const char* appendText) -{ - u32 textLength = static_cast(std::strlen(appendText)); - if (textLength > 0) - InternalAppend(appendText, textLength); -} - -void String::AppendString(const char* appendString, u32 Count) -{ - if (Count > 0) - InternalAppend(appendString, Count); -} - -void String::AppendString(const std::string& appendString) -{ - if (!appendString.empty()) - InternalAppend(appendString.c_str(), static_cast(appendString.size())); -} - -void String::AppendString(const std::string_view& appendString) -{ - if (!appendString.empty()) - InternalAppend(appendString.data(), static_cast(appendString.size())); -} - -void String::AppendSubString(const String& appendStr, s32 Offset /* = 0 */, s32 Count /* = INT_std::max */) -{ - u32 appendStrLength = appendStr.GetLength(); - - // calc real offset - u32 realOffset; - if (Offset < 0) - realOffset = (u32)std::max((s32)0, (s32)appendStrLength + Offset); - else - realOffset = std::min((u32)Offset, appendStrLength); - - // calc real count - u32 realCount; - if (Count < 0) - realCount = std::min(appendStrLength - realOffset, (u32)std::max((s32)0, (s32)appendStrLength + Count)); - else - realCount = std::min(appendStrLength - realOffset, (u32)Count); - - // should be safe - DebugAssert((realOffset + realCount) <= appendStrLength); - if (realCount > 0) - InternalAppend(appendStr.GetCharArray() + realOffset, realCount); -} - -void String::AppendSubString(const char* appendText, s32 Offset /* = 0 */, s32 Count /* = INT_std::max */) -{ - u32 appendTextLength = static_cast(std::strlen(appendText)); - - // calc real offset - u32 realOffset; - if (Offset < 0) - realOffset = (u32)std::max((s32)0, (s32)appendTextLength + Offset); - else - realOffset = std::min((u32)Offset, appendTextLength); - - // calc real count - u32 realCount; - if (Count < 0) - realCount = std::min(appendTextLength - realOffset, (u32)std::max((s32)0, (s32)appendTextLength + Count)); - else - realCount = std::min(appendTextLength - realOffset, (u32)Count); - - // should be safe - DebugAssert((realOffset + realCount) <= appendTextLength); - if (realCount > 0) - InternalAppend(appendText + realOffset, realCount); -} - -void String::AppendFormattedString(const char* FormatString, ...) -{ - va_list ap; - va_start(ap, FormatString); - AppendFormattedStringVA(FormatString, ap); - va_end(ap); -} - -void String::AppendFormattedStringVA(const char* FormatString, va_list ArgPtr) -{ - // We have a 1KB byte buffer on the stack here. If this is too little, we'll grow it via the heap, - // but 1KB should be enough for most strings. - char stackBuffer[1024]; - char* pHeapBuffer = NULL; - char* pBuffer = stackBuffer; - u32 currentBufferSize = countof(stackBuffer); - u32 charsWritten; - - for (;;) - { - va_list ArgPtrCopy; - va_copy(ArgPtrCopy, ArgPtr); - int ret = std::vsnprintf(pBuffer, currentBufferSize, FormatString, ArgPtrCopy); - va_end(ArgPtrCopy); - if (ret < 0 || ((u32)ret >= (currentBufferSize - 1))) - { - currentBufferSize *= 2; - pBuffer = pHeapBuffer = reinterpret_cast(std::realloc(pHeapBuffer, currentBufferSize)); - continue; - } - - charsWritten = (u32)ret; - break; - } - - InternalAppend(pBuffer, charsWritten); - - if (pHeapBuffer != NULL) - std::free(pHeapBuffer); -} - -void String::PrependCharacter(char c) -{ - InternalPrepend(&c, 1); -} - -void String::PrependString(const String& appendStr) -{ - if (appendStr.GetLength() > 0) - InternalPrepend(appendStr.GetCharArray(), appendStr.GetLength()); -} - -void String::PrependString(const char* appendText) -{ - u32 textLength = static_cast(std::strlen(appendText)); - if (textLength > 0) - InternalPrepend(appendText, textLength); -} - -void String::PrependString(const char* appendString, u32 Count) -{ - if (Count > 0) - InternalPrepend(appendString, Count); -} - -void String::PrependString(const std::string& appendStr) -{ - if (!appendStr.empty()) - InternalPrepend(appendStr.c_str(), static_cast(appendStr.size())); -} - -void String::PrependString(const std::string_view& appendStr) -{ - if (!appendStr.empty()) - InternalPrepend(appendStr.data(), static_cast(appendStr.size())); -} - -void String::PrependSubString(const String& appendStr, s32 Offset /* = 0 */, s32 Count /* = INT_std::max */) -{ - u32 appendStrLength = appendStr.GetLength(); - - // calc real offset - u32 realOffset; - if (Offset < 0) - realOffset = (u32)std::max((s32)0, (s32)appendStrLength + Offset); - else - realOffset = std::min((u32)Offset, appendStrLength); - - // calc real count - u32 realCount; - if (Count < 0) - realCount = std::min(appendStrLength - realOffset, (u32)std::max((s32)0, (s32)appendStrLength + Count)); - else - realCount = std::min(appendStrLength - realOffset, (u32)Count); - - // should be safe - DebugAssert((realOffset + realCount) <= appendStrLength); - if (realCount > 0) - InternalPrepend(appendStr.GetCharArray() + realOffset, realCount); -} - -void String::PrependSubString(const char* appendText, s32 Offset /* = 0 */, s32 Count /* = INT_std::max */) -{ - u32 appendTextLength = static_cast(std::strlen(appendText)); - - // calc real offset - u32 realOffset; - if (Offset < 0) - realOffset = (u32)std::max((s32)0, (s32)appendTextLength + Offset); - else - realOffset = std::min((u32)Offset, appendTextLength); - - // calc real count - u32 realCount; - if (Count < 0) - realCount = std::min(appendTextLength - realOffset, (u32)std::max((s32)0, (s32)appendTextLength + Count)); - else - realCount = std::min(appendTextLength - realOffset, (u32)Count); - - // should be safe - DebugAssert((realOffset + realCount) <= appendTextLength); - if (realCount > 0) - InternalPrepend(appendText + realOffset, realCount); -} - -void String::PrependFormattedString(const char* FormatString, ...) -{ - va_list ap; - va_start(ap, FormatString); - PrependFormattedStringVA(FormatString, ap); - va_end(ap); -} - -void String::PrependFormattedStringVA(const char* FormatString, va_list ArgPtr) -{ - // We have a 1KB byte buffer on the stack here. If this is too little, we'll grow it via the heap, - // but 1KB should be enough for most strings. - char stackBuffer[1024]; - char* pHeapBuffer = NULL; - char* pBuffer = stackBuffer; - u32 currentBufferSize = countof(stackBuffer); - u32 charsWritten; - - for (;;) - { - int ret = std::vsnprintf(pBuffer, currentBufferSize, FormatString, ArgPtr); - if (ret < 0 || ((u32)ret >= (currentBufferSize - 1))) - { - currentBufferSize *= 2; - pBuffer = pHeapBuffer = reinterpret_cast(std::realloc(pHeapBuffer, currentBufferSize)); - continue; - } - - charsWritten = (u32)ret; - break; - } - - InternalPrepend(pBuffer, charsWritten); - - if (pHeapBuffer != NULL) - std::free(pHeapBuffer); -} - -void String::InsertString(s32 offset, const String& appendStr) -{ - InsertString(offset, appendStr, appendStr.GetLength()); -} - -void String::InsertString(s32 offset, const char* appendStr) -{ - InsertString(offset, appendStr, static_cast(std::strlen(appendStr))); -} - -void String::InsertString(s32 offset, const char* appendStr, u32 appendStrLength) -{ - if (appendStrLength == 0) - return; - - EnsureRemainingSpace(appendStrLength); - - // calc real offset - u32 realOffset; - if (offset < 0) - realOffset = (u32)std::max((s32)0, (s32)m_pStringData->StringLength + offset); - else - realOffset = std::min((u32)offset, m_pStringData->StringLength); - - // determine number of characters after offset - DebugAssert(realOffset <= m_pStringData->StringLength); - u32 charactersAfterOffset = m_pStringData->StringLength - realOffset; - if (charactersAfterOffset > 0) - std::memmove(m_pStringData->pBuffer + offset + appendStrLength, m_pStringData->pBuffer + offset, - charactersAfterOffset); - - // insert the string - std::memcpy(m_pStringData->pBuffer + realOffset, appendStr, appendStrLength); - m_pStringData->StringLength += appendStrLength; - - // ensure null termination - m_pStringData->pBuffer[m_pStringData->StringLength] = 0; -} - -void String::InsertString(s32 offset, const std::string& appendStr) -{ - InsertString(offset, appendStr.c_str(), static_cast(appendStr.size())); -} - -void String::InsertString(s32 offset, const std::string_view& appendStr) -{ - InsertString(offset, appendStr.data(), static_cast(appendStr.size())); -} - -void String::Format(const char* FormatString, ...) -{ - va_list ap; - va_start(ap, FormatString); - FormatVA(FormatString, ap); - va_end(ap); -} - -void String::FormatVA(const char* FormatString, va_list ArgPtr) -{ - if (GetLength() > 0) - Clear(); - - AppendFormattedStringVA(FormatString, ArgPtr); -} - -void String::Assign(const String& copyString) -{ - // special case: empty strings - if (copyString.IsEmpty()) - { - m_pStringData = const_cast(&s_EmptyStringData); - } - // is the string data sharable? - else if (StringDataIsSharable(copyString.m_pStringData)) - { - m_pStringData = copyString.m_pStringData; - if (!m_pStringData->ReadOnly) - StringDataAddRef(m_pStringData); - } - // create a clone for ourselves - else - { - // since we're going to the effort of creating a clone, we might as well create it as the smallest size possible - m_pStringData = StringDataClone(copyString.m_pStringData, copyString.m_pStringData->StringLength + 1, false); - } -} - -void String::Assign(const char* copyText) -{ - Clear(); - AppendString(copyText); -} - -void String::Assign(String&& moveString) -{ - Clear(); - m_pStringData = moveString.m_pStringData; - moveString.m_pStringData = const_cast(&s_EmptyStringData); -} - -void String::Assign(const std::string& copyString) -{ - Clear(); - AppendString(copyString.data(), static_cast(copyString.size())); -} - -void String::Assign(const std::string_view& copyString) -{ - Clear(); - AppendString(copyString.data(), static_cast(copyString.size())); -} - -void String::AssignCopy(const String& copyString) -{ - Clear(); - AppendString(copyString); -} - -void String::Swap(String& swapString) -{ - std::swap(m_pStringData, swapString.m_pStringData); -} - -bool String::Compare(const String& otherString) const -{ - return (std::strcmp(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer) == 0); -} - -bool String::Compare(const char* otherText) const -{ - return (std::strcmp(m_pStringData->pBuffer, otherText) == 0); -} - -bool String::SubCompare(const String& otherString, u32 Length) const -{ - return (std::strncmp(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer, Length) == 0); -} - -bool String::SubCompare(const char* otherText, u32 Length) const -{ - return (std::strncmp(m_pStringData->pBuffer, otherText, Length) == 0); -} - -bool String::CompareInsensitive(const String& otherString) const -{ - return (CASE_COMPARE(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer) == 0); -} - -bool String::CompareInsensitive(const char* otherText) const -{ - return (CASE_COMPARE(m_pStringData->pBuffer, otherText) == 0); -} - -bool String::SubCompareInsensitive(const String& otherString, u32 Length) const -{ - return (CASE_N_COMPARE(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer, Length) == 0); -} - -bool String::SubCompareInsensitive(const char* otherText, u32 Length) const -{ - return (CASE_N_COMPARE(m_pStringData->pBuffer, otherText, Length) == 0); -} - -int String::NumericCompare(const String& otherString) const -{ - return std::strcmp(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer); -} - -int String::NumericCompare(const char* otherText) const -{ - return std::strcmp(m_pStringData->pBuffer, otherText); -} - -int String::NumericCompareInsensitive(const String& otherString) const -{ - return CASE_COMPARE(m_pStringData->pBuffer, otherString.m_pStringData->pBuffer); -} - -int String::NumericCompareInsensitive(const char* otherText) const -{ - return CASE_COMPARE(m_pStringData->pBuffer, otherText); -} - -bool String::StartsWith(const char* compareString, bool caseSensitive /*= true*/) const -{ - u32 compareStringLength = static_cast(std::strlen(compareString)); - if (compareStringLength > m_pStringData->StringLength) - return false; - - return (caseSensitive) ? (std::strncmp(compareString, m_pStringData->pBuffer, compareStringLength) == 0) : - (CASE_N_COMPARE(compareString, m_pStringData->pBuffer, compareStringLength) == 0); -} - -bool String::StartsWith(const String& compareString, bool caseSensitive /*= true*/) const -{ - u32 compareStringLength = compareString.GetLength(); - if (compareStringLength > m_pStringData->StringLength) - return false; - - return (caseSensitive) ? - (std::strncmp(compareString.m_pStringData->pBuffer, m_pStringData->pBuffer, compareStringLength) == 0) : - (CASE_N_COMPARE(compareString.m_pStringData->pBuffer, m_pStringData->pBuffer, compareStringLength) == 0); -} - -bool String::EndsWith(const char* compareString, bool caseSensitive /*= true*/) const -{ - u32 compareStringLength = static_cast(std::strlen(compareString)); - if (compareStringLength > m_pStringData->StringLength) - return false; - - u32 startOffset = m_pStringData->StringLength - compareStringLength; - return (caseSensitive) ? - (std::strncmp(compareString, m_pStringData->pBuffer + startOffset, compareStringLength) == 0) : - (CASE_N_COMPARE(compareString, m_pStringData->pBuffer + startOffset, compareStringLength) == 0); -} - -bool String::EndsWith(const String& compareString, bool caseSensitive /*= true*/) const -{ - u32 compareStringLength = compareString.GetLength(); - if (compareStringLength > m_pStringData->StringLength) - return false; - - u32 startOffset = m_pStringData->StringLength - compareStringLength; - return (caseSensitive) ? (std::strncmp(compareString.m_pStringData->pBuffer, m_pStringData->pBuffer + startOffset, - compareStringLength) == 0) : - (CASE_N_COMPARE(compareString.m_pStringData->pBuffer, m_pStringData->pBuffer + startOffset, - compareStringLength) == 0); -} - -void String::Clear() -{ - if (m_pStringData == &s_EmptyStringData) - return; - - // Do we have a shared buffer? If so, cancel it and allocate a new one when we need to. - // Otherwise, clear the current buffer. - if (StringDataIsShared(m_pStringData) || m_pStringData->ReadOnly) - { - // replace with empty string data - Obliterate(); - } - else - { - // in debug, zero whole string, in release, zero only the first character -#if _DEBUG - std::memset(m_pStringData->pBuffer, 0, m_pStringData->BufferSize); -#else - m_pStringData->pBuffer[0] = '\0'; -#endif - m_pStringData->StringLength = 0; - } -} - -void String::Obliterate() -{ - if (m_pStringData == &s_EmptyStringData) - return; - - // Force a release of the current buffer. - StringDataRelease(m_pStringData); - m_pStringData = const_cast(&s_EmptyStringData); -} - -s32 String::Find(char c, u32 Offset /* = 0*/) const -{ - DebugAssert(Offset <= m_pStringData->StringLength); - char* pAt = std::strchr(m_pStringData->pBuffer + Offset, c); - return (pAt == NULL) ? -1 : s32(pAt - m_pStringData->pBuffer); -} - -s32 String::RFind(char c, u32 Offset /* = 0*/) const -{ - DebugAssert(Offset <= m_pStringData->StringLength); - char* pAt = std::strrchr(m_pStringData->pBuffer + Offset, c); - return (pAt == NULL) ? -1 : s32(pAt - m_pStringData->pBuffer); -} - -s32 String::Find(const char* str, u32 Offset /* = 0 */) const -{ - DebugAssert(Offset <= m_pStringData->StringLength); - char* pAt = std::strstr(m_pStringData->pBuffer + Offset, str); - return (pAt == NULL) ? -1 : s32(pAt - m_pStringData->pBuffer); -} - -void String::Reserve(u32 newReserve, bool Force /* = false */) -{ - DebugAssert(!Force || newReserve >= m_pStringData->StringLength); - - u32 newSize = (Force) ? newReserve + 1 : std::max(newReserve + 1, m_pStringData->BufferSize); - StringData* pNewStringData; - - if (StringDataIsShared(m_pStringData) || m_pStringData->ReadOnly) - { - pNewStringData = StringDataClone(m_pStringData, newSize, false); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - } - else - { - // skip if smaller, and not forced - if (newSize <= m_pStringData->BufferSize && !Force) - return; - - // if we are the only owner of the buffer, we can simply realloc it - if (m_pStringData->ReferenceCount == 1) - { - // do realloc and update pointer - m_pStringData = StringDataReallocate(m_pStringData, newSize); - } - else - { - // clone and release old - pNewStringData = StringDataClone(m_pStringData, newSize, false); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - } - } -} - -void String::Resize(u32 newSize, char fillerCharacter /* = ' ' */, bool skrinkIfSmaller /* = false */) -{ - StringData* pNewStringData; - - // if going larger, or we don't own the buffer, realloc - if (StringDataIsShared(m_pStringData) || m_pStringData->ReadOnly || newSize >= m_pStringData->BufferSize) - { - pNewStringData = StringDataClone(m_pStringData, newSize + 1, true); - StringDataRelease(m_pStringData); - m_pStringData = pNewStringData; - - if (m_pStringData->StringLength < newSize) - { - std::memset(m_pStringData->pBuffer + m_pStringData->StringLength, fillerCharacter, - m_pStringData->BufferSize - m_pStringData->StringLength - 1); - } - - m_pStringData->StringLength = newSize; - } - else - { - // owns the buffer, and going smaller - DebugAssert(newSize < m_pStringData->BufferSize); - - // update length and terminator -#if _DEBUG - std::memset(m_pStringData->pBuffer + newSize, 0, m_pStringData->BufferSize - newSize); -#else - m_pStringData->pBuffer[newSize] = 0; -#endif - m_pStringData->StringLength = newSize; - - // shrink if requested - if (skrinkIfSmaller) - Shrink(false); - } -} - -void String::UpdateSize() -{ - EnsureOwnWritableCopy(); - m_pStringData->StringLength = static_cast(std::strlen(m_pStringData->pBuffer)); -} - -void String::Shrink(bool Force /* = false */) -{ - // only shrink of we own the buffer, or forced - if (Force || m_pStringData->ReferenceCount == 1) - Reserve(m_pStringData->StringLength); -} - -String String::SubString(s32 Offset, s32 Count /* = -1 */) const -{ - String returnStr; - returnStr.AppendSubString(*this, Offset, Count); - return returnStr; -} - -void String::Erase(s32 Offset, s32 Count /* = INT_std::max */) -{ - u32 currentLength = m_pStringData->StringLength; - - // calc real offset - u32 realOffset; - if (Offset < 0) - realOffset = (u32)std::max((s32)0, (s32)currentLength + Offset); - else - realOffset = std::min((u32)Offset, currentLength); - - // calc real count - u32 realCount; - if (Count < 0) - realCount = std::min(currentLength - realOffset, (u32)std::max((s32)0, (s32)currentLength + Count)); - else - realCount = std::min(currentLength - realOffset, (u32)Count); - - // Fastpath: offset == 0, count < 0, wipe whole string. - if (realOffset == 0 && realCount == currentLength) - { - Clear(); - return; - } - - // Fastpath: offset >= 0, count < 0, wipe everything after offset + count - if ((realOffset + realCount) == m_pStringData->StringLength) - { - m_pStringData->StringLength -= realCount; -#ifdef _DEBUG - std::memset(m_pStringData->pBuffer + m_pStringData->StringLength, 0, - m_pStringData->BufferSize - m_pStringData->StringLength); -#else - m_pStringData->pBuffer[m_pStringData->StringLength] = 0; -#endif - } - // Slowpath: offset >= 0, count < length - else - { - u32 afterEraseBlock = m_pStringData->StringLength - realOffset - realCount; - DebugAssert(afterEraseBlock > 0); - - std::memmove(m_pStringData->pBuffer + Offset, m_pStringData->pBuffer + realOffset + realCount, afterEraseBlock); - m_pStringData->StringLength = m_pStringData->StringLength - realCount; - -#ifdef _DEBUG - std::memset(m_pStringData->pBuffer + m_pStringData->StringLength, 0, - m_pStringData->BufferSize - m_pStringData->StringLength); -#else - m_pStringData->pBuffer[m_pStringData->StringLength] = 0; -#endif - } -} - -u32 String::Replace(char searchCharacter, char replaceCharacter) -{ - u32 nReplacements = 0; - char* pCurrent = std::strchr(m_pStringData->pBuffer, searchCharacter); - while (pCurrent != NULL) - { - if ((nReplacements++) == 0) - EnsureOwnWritableCopy(); - - *pCurrent = replaceCharacter; - pCurrent = std::strchr(pCurrent + 1, searchCharacter); - } - - return nReplacements; -} - -u32 String::Replace(const char* searchString, const char* replaceString) -{ - u32 nReplacements = 0; - u32 searchStringLength = static_cast(std::strlen(searchString)); - -#if 0 - u32 replaceStringLength = static_cast(std::strlen(replaceString)); - s32 lengthDifference = (s32)replaceStringLength - (s32)searchStringLength; - - char *pCurrent = std::strchr(m_pStringData->pBuffer, searchString); - while (pCurrent != NULL) - { - if ((nReplacements++) == 0) - { - if (lengthDifference > 0) - EnsureRemainingSpace(lengthDifference); - else - EnsureOwnCopy(); - } - else if (lengthDifference > 0) - EnsureRemainingSpace(lengthDifference); - } -#endif - - // TODO: Fastpath if strlen(searchString) == strlen(replaceString) - - String tempString; - char* pStart = m_pStringData->pBuffer; - char* pCurrent = std::strstr(pStart, searchString); - char* pLast = NULL; - while (pCurrent != NULL) - { - if ((nReplacements++) == 0) - tempString.Reserve(m_pStringData->StringLength); - - tempString.AppendSubString(*this, s32(pStart - pCurrent), s32(pStart - pCurrent - 1)); - tempString.AppendString(replaceString); - pLast = pCurrent + searchStringLength; - nReplacements++; - - pCurrent = std::strstr(pLast, searchString); - } - - if (pLast != NULL) - tempString.AppendSubString(*this, s32(pLast - pStart)); - - if (nReplacements) - Swap(tempString); - - return nReplacements; -} - -void String::ToLower() -{ - // fixme for utf8 - EnsureOwnWritableCopy(); - for (u32 i = 0; i < m_pStringData->StringLength; i++) - { - if (std::isprint(m_pStringData->pBuffer[i])) - m_pStringData->pBuffer[i] = static_cast(std::tolower(m_pStringData->pBuffer[i])); - } -} - -void String::ToUpper() -{ - // fixme for utf8 - EnsureOwnWritableCopy(); - for (u32 i = 0; i < m_pStringData->StringLength; i++) - { - if (std::isprint(m_pStringData->pBuffer[i])) - m_pStringData->pBuffer[i] = static_cast(std::toupper(m_pStringData->pBuffer[i])); - } -} - -void String::LStrip(const char* szStripCharacters /* = " " */) -{ - u32 stripCharactersLen = static_cast(std::strlen(szStripCharacters)); - u32 removeCount = 0; - u32 i = 0; - u32 j; - - // for each character in str - for (i = 0; i < m_pStringData->StringLength; i++) - { - char ch = m_pStringData->pBuffer[i]; - - // if it exists in szStripCharacters - for (j = 0; j < stripCharactersLen; j++) - { - if (ch == szStripCharacters[j]) - { - removeCount++; - goto OUTER; - } - } - - // not found, exit - break; - OUTER: - continue; - } - - // chars to remove? - if (removeCount > 0) - Erase(0, removeCount); -} - -void String::RStrip(const char* szStripCharacters /* = " " */) -{ - u32 stripCharactersLen = static_cast(std::strlen(szStripCharacters)); - u32 removeCount = 0; - u32 i = 0; - u32 j; - - // for each character in str - for (i = 0; i < m_pStringData->StringLength; i++) - { - char ch = m_pStringData->pBuffer[m_pStringData->StringLength - i - 1]; - - // if it exists in szStripCharacters - for (j = 0; j < stripCharactersLen; j++) - { - if (ch == szStripCharacters[j]) - { - removeCount++; - goto OUTER; - } - } - - // not found, exit - break; - OUTER: - continue; - } - - // chars to remove? - if (removeCount > 0) - Erase(m_pStringData->StringLength - removeCount); -} - -void String::Strip(const char* szStripCharacters /* = " " */) -{ - RStrip(szStripCharacters); - LStrip(szStripCharacters); -} - -String String::FromFormat(const char* FormatString, ...) -{ - String returnStr; - va_list ap; - - va_start(ap, FormatString); - returnStr.FormatVA(FormatString, ap); - va_end(ap); - - return returnStr; -} diff --git a/src/common/string.h b/src/common/string.h deleted file mode 100644 index 32de851f2..000000000 --- a/src/common/string.h +++ /dev/null @@ -1,472 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once -#include "fmt/core.h" -#include "types.h" -#include -#include -#include -#include -#include -#include -#include - -// -// String -// Implements a UTF-8 string container with copy-on-write behavior. -// The data class is not currently threadsafe (creating a mutex on each container would be overkill), -// so locking is still required when multiple threads are involved. -// -class String -{ -public: - // Internal StringData class. - struct StringData - { - // Pointer to memory where the string is located - char* pBuffer; - - // Length of the string located in pBuffer (in characters) - u32 StringLength; - - // Size of the buffer pointed to by pBuffer - u32 BufferSize; - - // Reference count of this data object. If set to -1, - // it is considered noncopyable and any copies of the string - // will always create their own copy. - s32 ReferenceCount; - - // Whether the memory pointed to by pBuffer is writable. - bool ReadOnly; - }; - -public: - using value_type = char; - - // Creates an empty string. - String(); - - // Creates a string containing the specified text. - // Note that this will incur a heap allocation, even if Text is on the stack. - // For strings that do not allocate any space on the heap, see StaticString. - String(const char* Text); - - // Creates a string contained the specified text (with length). - String(const char* Text, u32 Count); - - // Creates a string using the same buffer as another string (copy-on-write). - String(const String& copyString); - - // Move constructor, take reference from other string. - String(String&& moveString); - - // Construct a string from a data object, does not increment the reference count on the string data, use carefully. - explicit String(StringData* pStringData) : m_pStringData(pStringData) {} - - // Creates string from string_view. - String(const std::string_view& sv); - - // Destructor. Child classes may not have any destructors, as this is not virtual. - ~String(); - - // manual assignment - void Assign(const String& copyString); - void Assign(const char* copyText); - void Assign(const std::string& copyString); - void Assign(const std::string_view& copyString); - void Assign(String&& moveString); - - // assignment but ensures that we have our own copy. - void AssignCopy(const String& copyString); - - // Ensures that the string has its own unique copy of the data. - void EnsureOwnWritableCopy(); - - // Ensures that we have our own copy of the buffer, and spaceRequired bytes free in the buffer. - void EnsureRemainingSpace(u32 spaceRequired); - - // clears the contents of the string - void Clear(); - - // clear the contents of the string, and free any memory currently being used - void Obliterate(); - - // swaps strings - void Swap(String& swapString); - - // append a single character to this string - void AppendCharacter(char c); - - // append a string to this string - void AppendString(const String& appendStr); - void AppendString(const char* appendText); - void AppendString(const char* appendString, u32 Count); - void AppendString(const std::string& appendString); - void AppendString(const std::string_view& appendString); - - // append a substring of the specified string to this string - void AppendSubString(const String& appendStr, s32 Offset = 0, s32 Count = std::numeric_limits::max()); - void AppendSubString(const char* appendText, s32 Offset = 0, s32 Count = std::numeric_limits::max()); - - // append formatted string to this string - void AppendFormattedString(const char* FormatString, ...) printflike(2, 3); - void AppendFormattedStringVA(const char* FormatString, va_list ArgPtr); - - template - void AppendFmtString(fmt::format_string fmt, T&&... args); - - // append a single character to this string - void PrependCharacter(char c); - - // append a string to this string - void PrependString(const String& appendStr); - void PrependString(const char* appendText); - void PrependString(const char* appendString, u32 Count); - void PrependString(const std::string& appendStr); - void PrependString(const std::string_view& appendStr); - - // append a substring of the specified string to this string - void PrependSubString(const String& appendStr, s32 Offset = 0, s32 Count = std::numeric_limits::max()); - void PrependSubString(const char* appendText, s32 Offset = 0, s32 Count = std::numeric_limits::max()); - - // append formatted string to this string - void PrependFormattedString(const char* FormatString, ...) printflike(2, 3); - void PrependFormattedStringVA(const char* FormatString, va_list ArgPtr); - - template - void PrependFmtString(fmt::format_string fmt, T&&... args); - - // insert a string at the specified offset - void InsertString(s32 offset, const String& appendStr); - void InsertString(s32 offset, const char* appendStr); - void InsertString(s32 offset, const char* appendStr, u32 appendStrLength); - void InsertString(s32 offset, const std::string& appendStr); - void InsertString(s32 offset, const std::string_view& appendStr); - - // set to formatted string - void Format(const char* FormatString, ...) printflike(2, 3); - void FormatVA(const char* FormatString, va_list ArgPtr); - - template - void Fmt(fmt::format_string fmt, T&&... args); - - // compare one string to another - bool Compare(const String& otherString) const; - bool Compare(const char* otherText) const; - bool SubCompare(const String& otherString, u32 Length) const; - bool SubCompare(const char* otherText, u32 Length) const; - bool CompareInsensitive(const String& otherString) const; - bool CompareInsensitive(const char* otherText) const; - bool SubCompareInsensitive(const String& otherString, u32 Length) const; - bool SubCompareInsensitive(const char* otherText, u32 Length) const; - - // numerical compares - int NumericCompare(const String& otherString) const; - int NumericCompare(const char* otherText) const; - int NumericCompareInsensitive(const String& otherString) const; - int NumericCompareInsensitive(const char* otherText) const; - - // starts with / ends with - bool StartsWith(const char* compareString, bool caseSensitive = true) const; - bool StartsWith(const String& compareString, bool caseSensitive = true) const; - bool EndsWith(const char* compareString, bool caseSensitive = true) const; - bool EndsWith(const String& compareString, bool caseSensitive = true) const; - - // searches for a character inside a string - // rfind is the same except it starts at the end instead of the start - // returns -1 if it is not found, otherwise the offset in the string - s32 Find(char c, u32 Offset = 0) const; - s32 RFind(char c, u32 Offset = 0) const; - - // searches for a string inside a string - // rfind is the same except it starts at the end instead of the start - // returns -1 if it is not found, otherwise the offset in the string - s32 Find(const char* str, u32 Offset = 0) const; - - // alters the length of the string to be at least len bytes long - void Reserve(u32 newReserve, bool Force = false); - - // Cuts characters off the string to reduce it to len bytes long. - void Resize(u32 newSize, char fillerCharacter = ' ', bool skrinkIfSmaller = false); - - // updates the internal length counter when the string is externally modified - void UpdateSize(); - - // shrink the string to the minimum size possible - void Shrink(bool Force = false); - - // gets the size of the string - u32 GetLength() const { return m_pStringData->StringLength; } - bool IsEmpty() const { return (m_pStringData->StringLength == 0); } - - // gets the maximum number of bytes we can write to the string, currently - u32 GetBufferSize() const { return m_pStringData->BufferSize; } - u32 GetWritableBufferSize() - { - EnsureOwnWritableCopy(); - return m_pStringData->BufferSize; - } - - // creates a new string using part of this string - String SubString(s32 Offset, s32 Count = std::numeric_limits::max()) const; - - // erase count characters at offset from this string. if count is less than zero, everything past offset is erased - void Erase(s32 Offset, s32 Count = std::numeric_limits::max()); - - // replaces all instances of character c with character r in this string - // returns the number of changes - u32 Replace(char searchCharacter, char replaceCharacter); - - // replaces all instances of string s with string r in this string - // returns the number of changes - u32 Replace(const char* searchString, const char* replaceString); - - // convert string to lowercase - void ToLower(); - - // convert string to upper - void ToUpper(); - - // strip characters from start and end of the string - void LStrip(const char* szStripCharacters = " \t\r\n"); - void RStrip(const char* szStripCharacters = " \t\r\n"); - void Strip(const char* szStripCharacters = " \t\r\n"); - - // gets a constant pointer to the string - const char* GetCharArray() const { return m_pStringData->pBuffer; } - - // gets a writable char array, do not write more than reserve characters to it. - char* GetWriteableCharArray() - { - EnsureOwnWritableCopy(); - return m_pStringData->pBuffer; - } - - // returns a string view for this string - std::string_view GetStringView() const - { - return IsEmpty() ? std::string_view() : std::string_view(GetCharArray(), GetLength()); - } - std::string ToStdString() const - { - return std::string(GetStringView()); - } - - // creates a new string from the specified format - static String FromFormat(const char* FormatString, ...) printflike(1, 2); - - // accessor operators - // const char &operator[](u32 i) const { DebugAssert(i < m_pStringData->StringLength); return - // m_pStringData->pBuffer[i]; } char &operator[](u32 i) { DebugAssert(i < m_pStringData->StringLength); return - // m_pStringData->pBuffer[i]; } - operator const char*() const { return GetCharArray(); } - operator char*() { return GetWriteableCharArray(); } - operator std::string_view() const { return GetStringView(); } - - // Will use the string data provided. - String& operator=(const String& copyString) - { - Assign(copyString); - return *this; - } - - // Allocates own buffer and copies text. - String& operator=(const char* Text) - { - Assign(Text); - return *this; - } - String& operator=(const std::string& Text) - { - Assign(Text); - return *this; - } - String& operator=(const std::string_view& Text) - { - Assign(Text); - return *this; - } - - // Move operator. - String& operator=(String&& moveString) - { - Assign(moveString); - return *this; - } - - // comparative operators - bool operator==(const String& compString) const { return Compare(compString); } - bool operator==(const char* compString) const { return Compare(compString); } - bool operator!=(const String& compString) const { return !Compare(compString); } - bool operator!=(const char* compString) const { return !Compare(compString); } - bool operator<(const String& compString) const { return (NumericCompare(compString) < 0); } - bool operator<(const char* compString) const { return (NumericCompare(compString) < 0); } - bool operator>(const String& compString) const { return (NumericCompare(compString) > 0); } - bool operator>(const char* compString) const { return (NumericCompare(compString) > 0); } - - // STL adapters - ALWAYS_INLINE void push_back(value_type&& val) { AppendCharacter(val); } - -protected: - // Internal append function. - void InternalPrepend(const char* pString, u32 Length); - void InternalAppend(const char* pString, u32 Length); - - // Pointer to string data. - StringData* m_pStringData; - - // Empty string data. - static const StringData s_EmptyStringData; -}; - -// static string, stored in .rodata -#define StaticString(Text) \ - []() noexcept -> String { \ - static constexpr u32 buffer_size = sizeof(Text); \ - static constexpr u32 length = buffer_size - 1; \ - static constexpr String::StringData data{const_cast(Text), length, buffer_size, static_cast(-1), \ - true}; \ - return String(const_cast(&data)); \ - }() - -// stack-allocated string -template -class StackString : public String -{ -public: - StackString() : String(&m_sStringData) { InitStackStringData(); } - - StackString(const char* Text) : String(&m_sStringData) - { - InitStackStringData(); - Assign(Text); - } - - StackString(const char* Text, u32 Count) : String(&m_sStringData) - { - InitStackStringData(); - AppendString(Text, Count); - } - - StackString(const String& copyString) : String(&m_sStringData) - { - // force a copy by passing it a string pointer, instead of a string object - InitStackStringData(); - Assign(copyString.GetCharArray()); - } - - StackString(const StackString& copyString) : String(&m_sStringData) - { - // force a copy by passing it a string pointer, instead of a string object - InitStackStringData(); - Assign(copyString.GetCharArray()); - } - - StackString(const std::string_view& sv) : String(&m_sStringData) - { - InitStackStringData(); - AppendString(sv.data(), static_cast(sv.size())); - } - - // Override the fromstring method - static StackString FromFormat(const char* FormatString, ...) printflike(1, 2) - { - va_list argPtr; - va_start(argPtr, FormatString); - - StackString returnValue; - returnValue.FormatVA(FormatString, argPtr); - - va_end(argPtr); - - return returnValue; - } - - template - static StackString FromFmt(fmt::format_string fmt, T&&... args) - { - StackString ret; - fmt::vformat_to(std::back_inserter(ret), fmt, fmt::make_format_args(args...)); - return ret; - } - - // Will use the string data provided. - StackString& operator=(const StackString& copyString) - { - Assign(copyString.GetCharArray()); - return *this; - } - StackString& operator=(const String& copyString) - { - Assign(copyString.GetCharArray()); - return *this; - } - - // Allocates own buffer and copies text. - StackString& operator=(const char* Text) - { - Assign(Text); - return *this; - } - StackString& operator=(const std::string& Text) - { - Assign(Text); - return *this; - } - StackString& operator=(const std::string_view& Text) - { - Assign(Text); - return *this; - } - -private: - StringData m_sStringData; - char m_strStackBuffer[L + 1]; - - inline void InitStackStringData() - { - m_sStringData.pBuffer = m_strStackBuffer; - m_sStringData.StringLength = 0; - m_sStringData.BufferSize = countof(m_strStackBuffer); - m_sStringData.ReadOnly = false; - m_sStringData.ReferenceCount = -1; - -#ifdef _DEBUG - std::memset(m_strStackBuffer, 0, sizeof(m_strStackBuffer)); -#else - m_strStackBuffer[0] = '\0'; -#endif - } -}; - -// stack string types -typedef StackString<64> TinyString; -typedef StackString<256> SmallString; -typedef StackString<512> LargeString; -typedef StackString<512> PathString; - -// empty string global -extern const String EmptyString; - -template -void String::AppendFmtString(fmt::format_string fmt, T&&... args) -{ - fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...)); -} - -template -void String::PrependFmtString(fmt::format_string fmt, T&&... args) -{ - TinyString str; - fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...)); - PrependString(str); -} - -template -void String::Fmt(fmt::format_string fmt, T&&... args) -{ - Clear(); - fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...)); -} diff --git a/src/core/achievements.cpp b/src/core/achievements.cpp index 26e7ddd65..843a9937a 100644 --- a/src/core/achievements.cpp +++ b/src/core/achievements.cpp @@ -25,7 +25,7 @@ #include "common/path.h" #include "common/platform.h" #include "common/scoped_guard.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "util/cd_image.h" @@ -253,7 +253,7 @@ void Achievements::ReportRCError(int err, fmt::format_string fmt, T&&... a { TinyString str; fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...)); - str.AppendFmtString("{} ({})", rc_error_str(err), err); + str.append_fmt("{} ({})", rc_error_str(err), err); ReportError(str); } @@ -1137,16 +1137,15 @@ void Achievements::HandleLeaderboardTrackerShowEvent(const rc_client_event_t* ev event->leaderboard_tracker->display); TinyString width_string; - width_string.AppendString(ICON_FA_STOPWATCH); + width_string.append(ICON_FA_STOPWATCH); const u32 display_len = static_cast(std::strlen(event->leaderboard_tracker->display)); for (u32 i = 0; i < display_len; i++) - width_string.AppendCharacter('0'); + width_string.append('0'); LeaderboardTrackerIndicator indicator; indicator.tracker_id = event->leaderboard_tracker->id; - indicator.size = ImGuiFullscreen::g_medium_font->CalcTextSizeA( - ImGuiFullscreen::g_medium_font->FontSize, FLT_MAX, 0.0f, width_string.GetCharArray(), - width_string.GetCharArray() + width_string.GetLength()); + indicator.size = ImGuiFullscreen::g_medium_font->CalcTextSizeA(ImGuiFullscreen::g_medium_font->FontSize, FLT_MAX, + 0.0f, width_string.c_str(), width_string.end_ptr()); indicator.text = fmt::format(ICON_FA_STOPWATCH " {}", event->leaderboard_tracker->display); indicator.active = true; s_active_leaderboard_trackers.push_back(std::move(indicator)); @@ -1495,8 +1494,8 @@ std::string Achievements::GetAchievementBadgePath(const rc_client_achievement_t* if (achievement->badge_name[0] == 0) return path; - path = Path::Combine(s_image_directory, TinyString::FromFmt("achievement_{}_{}_{}.png", s_game_id, achievement->id, - s_achievement_state_strings[state])); + path = Path::Combine(s_image_directory, TinyString::from_fmt("achievement_{}_{}_{}.png", s_game_id, achievement->id, + s_achievement_state_strings[state])); if (!FileSystem::FileExists(path.c_str())) { @@ -1517,7 +1516,7 @@ std::string Achievements::GetUserBadgePath(const std::string_view& username) std::string path; const std::string clean_username = Path::SanitizeFileName(username); if (!clean_username.empty()) - path = Path::Combine(s_image_directory, TinyString::FromFmt("user_{}.png", clean_username)); + path = Path::Combine(s_image_directory, TinyString::from_fmt("user_{}.png", clean_username)); return path; } @@ -2062,27 +2061,27 @@ void Achievements::DrawAchievementsWindow() } const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize)); - text = s_game_title; + text.assign(s_game_title); if (s_hardcore_mode) - text.AppendString(TRANSLATE_SV("Achievements", " (Hardcore Mode)")); + text.append(TRANSLATE_SV("Achievements", " (Hardcore Mode)")); top += g_large_font->FontSize + spacing; ImGui::PushFont(g_large_font); - ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), - nullptr, ImVec2(0.0f, 0.0f), &title_bb); + ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f), + &title_bb); ImGui::PopFont(); const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + g_medium_font->FontSize)); if (s_game_summary.num_unlocked_achievements == s_game_summary.num_core_achievements) { - text.Fmt(TRANSLATE_FS("Achievements", "You have unlocked all achievements and earned {} points!"), + text.fmt(TRANSLATE_FS("Achievements", "You have unlocked all achievements and earned {} points!"), s_game_summary.points_unlocked); } else { - text.Fmt( + text.fmt( TRANSLATE_FS("Achievements", "You have unlocked {} of {} achievements, earning {} of {} possible points."), s_game_summary.num_unlocked_achievements, s_game_summary.num_core_achievements, s_game_summary.points_unlocked, s_game_summary.points_core); @@ -2091,8 +2090,8 @@ void Achievements::DrawAchievementsWindow() top += g_medium_font->FontSize + spacing; ImGui::PushFont(g_medium_font); - ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.GetCharArray(), - text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &summary_bb); + ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.c_str(), text.end_ptr(), nullptr, + ImVec2(0.0f, 0.0f), &summary_bb); ImGui::PopFont(); const float progress_height = ImGuiFullscreen::LayoutScale(20.0f); @@ -2104,14 +2103,13 @@ void Achievements::DrawAchievementsWindow() ImVec2(progress_bb.Min.x + fraction * progress_bb.GetWidth(), progress_bb.Max.y), ImGui::GetColorU32(ImGuiFullscreen::UISecondaryColor)); - text.Fmt("{}%", static_cast(std::round(fraction * 100.0f))); - text_size = ImGui::CalcTextSize(text.GetCharArray(), text.GetCharArray() + text.GetLength()); + text.fmt("{}%", static_cast(std::round(fraction * 100.0f))); + text_size = ImGui::CalcTextSize(text.c_str(), text.end_ptr()); const ImVec2 text_pos(progress_bb.Min.x + ((progress_bb.Max.x - progress_bb.Min.x) / 2.0f) - (text_size.x / 2.0f), progress_bb.Min.y + ((progress_bb.Max.y - progress_bb.Min.y) / 2.0f) - (text_size.y / 2.0f)); dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, - ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryTextColor), text.GetCharArray(), - text.GetCharArray() + text.GetLength()); + ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryTextColor), text.c_str(), text.end_ptr()); top += progress_height + spacing; } } @@ -2183,7 +2181,7 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo) ImRect bb; bool visible, hovered; - ImGuiFullscreen::MenuButtonFrame(TinyString::FromFmt("chv_{}", cheevo->id), true, + ImGuiFullscreen::MenuButtonFrame(TinyString::from_fmt("chv_{}", cheevo->id), true, !is_measured ? ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT + unlock_size : ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT + progress_height_unscaled + progress_spacing_unscaled, @@ -2219,12 +2217,12 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo) SmallString text; const float midpoint = bb.Min.y + g_large_font->FontSize + spacing; - text.Fmt((cheevo->points != 1) ? TRANSLATE_FS("Achievements", "{} points") : TRANSLATE_FS("Achievements", "{} point"), + text.fmt((cheevo->points != 1) ? TRANSLATE_FS("Achievements", "{} points") : TRANSLATE_FS("Achievements", "{} point"), cheevo->points); const ImVec2 points_template_size( g_medium_font->CalcTextSizeA(g_medium_font->FontSize, FLT_MAX, 0.0f, TRANSLATE("Achievements", "XXX points"))); - const ImVec2 points_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, FLT_MAX, 0.0f, text.GetCharArray(), - text.GetCharArray() + text.GetLength())); + const ImVec2 points_size( + g_medium_font->CalcTextSizeA(g_medium_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.end_ptr())); const float points_template_start = bb.Max.x - points_template_size.x; const float points_start = points_template_start + ((points_template_size.x - points_size.x) * 0.5f); const char* lock_text = is_unlocked ? ICON_FA_LOCK_OPEN : ICON_FA_LOCK; @@ -2248,18 +2246,18 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo) ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, cheevo->description, nullptr, nullptr, ImVec2(0.0f, 0.0f), &summary_bb); } - ImGui::RenderTextClipped(points_bb.Min, points_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), - &points_size, ImVec2(0.0f, 0.0f), &points_bb); + ImGui::RenderTextClipped(points_bb.Min, points_bb.Max, text.c_str(), text.end_ptr(), &points_size, ImVec2(0.0f, 0.0f), + &points_bb); if (is_unlocked) { TinyString date; FullscreenUI::TimeToPrintableString(&date, cheevo->unlock_time); - text.Fmt(TRANSLATE_FS("Achievements", "Unlocked: {}"), date); + text.fmt(TRANSLATE_FS("Achievements", "Unlocked: {}"), date); const ImRect unlock_bb(summary_bb.Min.x, summary_bb.Max.y + spacing, summary_bb.Max.x, bb.Max.y); - ImGui::RenderTextClipped(unlock_bb.Min, unlock_bb.Max, text, text.GetCharArray() + text.GetLength(), nullptr, - ImVec2(0.0f, 0.0f), &unlock_bb); + ImGui::RenderTextClipped(unlock_bb.Min, unlock_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f), + &unlock_bb); } else if (is_measured) { @@ -2399,43 +2397,43 @@ void Achievements::DrawLeaderboardsWindow() } const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize)); - text.Assign(Achievements::GetGameTitle()); + text.assign(Achievements::GetGameTitle()); top += g_large_font->FontSize + spacing; ImGui::PushFont(g_large_font); - ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), - nullptr, ImVec2(0.0f, 0.0f), &title_bb); + ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f), + &title_bb); ImGui::PopFont(); if (is_leaderboard_open) { const ImRect subtitle_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize)); - text.Assign(s_open_leaderboard->title); + text.assign(s_open_leaderboard->title); top += g_large_font->FontSize + spacing_small; ImGui::PushFont(g_large_font); - ImGui::RenderTextClipped(subtitle_bb.Min, subtitle_bb.Max, text.GetCharArray(), - text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &subtitle_bb); + ImGui::RenderTextClipped(subtitle_bb.Min, subtitle_bb.Max, text.c_str(), text.end_ptr(), nullptr, + ImVec2(0.0f, 0.0f), &subtitle_bb); ImGui::PopFont(); - text.Assign(s_open_leaderboard->description); + text.assign(s_open_leaderboard->description); } else { u32 count = 0; for (u32 i = 0; i < s_leaderboard_list->num_buckets; i++) count += s_leaderboard_list->buckets[i].num_leaderboards; - text.Fmt(TRANSLATE_FS("Achievements", "This game has {} leaderboards."), count); + text.fmt(TRANSLATE_FS("Achievements", "This game has {} leaderboards."), count); } const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + g_medium_font->FontSize)); top += g_medium_font->FontSize + spacing_small; ImGui::PushFont(g_medium_font); - ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.GetCharArray(), - text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &summary_bb); + ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.c_str(), text.end_ptr(), nullptr, + ImVec2(0.0f, 0.0f), &summary_bb); if (!is_leaderboard_open && !Achievements::IsHardcoreModeActive()) { @@ -2646,7 +2644,7 @@ void Achievements::DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& ent float text_start_x = bb.Min.x + LayoutScale(15.0f); SmallString text; - text.Format("%u", entry.rank); + text.fmt("{}", entry.rank); ImGui::PushFont(g_large_font); @@ -2654,8 +2652,8 @@ void Achievements::DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& ent ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 242, 0, 255)); const ImRect rank_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); - ImGui::RenderTextClipped(rank_bb.Min, rank_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), - nullptr, ImVec2(0.0f, 0.0f), &rank_bb); + ImGui::RenderTextClipped(rank_bb.Min, rank_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f), + &rank_bb); text_start_x += rank_column_width + column_spacing; const float icon_size = bb.Max.y - bb.Min.y; @@ -2694,8 +2692,8 @@ void Achievements::DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& ent const ImRect time_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint)); SmallString submit_time; FullscreenUI::TimeToPrintableString(&submit_time, entry.submitted); - ImGui::RenderTextClipped(time_bb.Min, time_bb.Max, submit_time.GetCharArray(), - submit_time.GetCharArray() + submit_time.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &time_bb); + ImGui::RenderTextClipped(time_bb.Min, time_bb.Max, submit_time.c_str(), submit_time.end_ptr(), nullptr, + ImVec2(0.0f, 0.0f), &time_bb); if (is_self) ImGui::PopStyleColor(); @@ -2716,7 +2714,7 @@ void Achievements::DrawLeaderboardListEntry(const rc_client_leaderboard_t* lboar static constexpr float alpha = 0.8f; TinyString id_str; - id_str.Format("%u", lboard->id); + id_str.fmt("{}", lboard->id); ImRect bb; bool visible, hovered; diff --git a/src/core/achievements.h b/src/core/achievements.h index 75b8be487..f12ee95da 100644 --- a/src/core/achievements.h +++ b/src/core/achievements.h @@ -3,7 +3,7 @@ #pragma once -#include "common/string.h" +#include "common/small_string.h" #include "common/types.h" #include diff --git a/src/core/bios.cpp b/src/core/bios.cpp index b742e6ce9..8c9a21d2a 100644 --- a/src/core/bios.cpp +++ b/src/core/bios.cpp @@ -182,7 +182,7 @@ void BIOS::PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask CPU::DisassembleInstruction(&old_disasm, address, existing_value); CPU::DisassembleInstruction(&new_disasm, address, new_value); Log_DevPrintf("BIOS-Patch 0x%08X (+0x%X): 0x%08X %s -> %08X %s", address, offset, existing_value, - old_disasm.GetCharArray(), new_value, new_disasm.GetCharArray()); + old_disasm.c_str(), new_value, new_disasm.c_str()); } bool BIOS::PatchBIOSFastBoot(u8* image, u32 image_size) diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 6b65a0451..6568c0055 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -770,22 +770,22 @@ static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, P u32& value) { SmallString str; - str.AppendString("Invalid bus "); + str.append("Invalid bus "); if (size == MemoryAccessSize::Byte) - str.AppendString("byte"); + str.append("byte"); if (size == MemoryAccessSize::HalfWord) - str.AppendString("word"); + str.append("word"); if (size == MemoryAccessSize::Word) - str.AppendString("dword"); - str.AppendCharacter(' '); + str.append("dword"); + str.append(' '); if (type == MemoryAccessType::Read) - str.AppendString("read"); + str.append("read"); else - str.AppendString("write"); + str.append("write"); - str.AppendFormattedString(" at address 0x%08X", address); + str.append_fmt(" at address 0x{:08X}", address); if (type == MemoryAccessType::Write) - str.AppendFormattedString(" (value 0x%08X)", value); + str.append_fmt(" (value 0x{:08X})", value); Log_ErrorPrint(str); if (type == MemoryAccessType::Read) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 737637a91..43d962ce5 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -803,7 +803,7 @@ bool CDROM::PrecacheMedia() TinyString CDROM::LBAToMSFString(CDImage::LBA lba) { const auto pos = CDImage::Position::FromLBA(lba); - return TinyString::FromFmt("{:02d}:{:02d}:{:02d}", pos.minute, pos.second, pos.frame); + return TinyString::from_fmt("{:02d}:{:02d}:{:02d}", pos.minute, pos.second, pos.frame); } void CDROM::SetReadaheadSectors(u32 readahead_sectors) @@ -2436,7 +2436,7 @@ void CDROM::UpdatePhysicalPosition(bool update_logical) const CDImage::LBA new_physical_lba = base + new_offset; #ifdef _DEBUG Log_DevPrintf("Tick diff %u, sector diff %u, old pos %s, new pos %s", diff, sector_diff, - LBAToMSFString(s_physical_lba).GetCharArray(), LBAToMSFString(new_physical_lba).GetCharArray()); + LBAToMSFString(s_physical_lba).c_str(), LBAToMSFString(new_physical_lba).c_str()); #endif if (s_physical_lba != new_physical_lba) { @@ -2575,7 +2575,7 @@ void CDROM::DoSeekComplete(TickCount ticks_late) else { Log_WarningPrintf("%s seek to [%s] failed", logical ? "Logical" : "Physical", - LBAToMSFString(m_reader.GetLastReadSector()).GetCharArray()); + LBAToMSFString(m_reader.GetLastReadSector()).c_str()); s_secondary_status.ClearActiveBits(); SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04); s_last_sector_header_valid = false; @@ -2733,8 +2733,7 @@ void CDROM::DoSectorRead() } else { - Log_DevPrintf("Sector %u [%s] has invalid subchannel Q", s_current_lba, - LBAToMSFString(s_current_lba).GetCharArray()); + Log_DevPrintf("Sector %u [%s] has invalid subchannel Q", s_current_lba, LBAToMSFString(s_current_lba).c_str()); } if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER) @@ -2806,7 +2805,7 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& { const u32 sb_num = (s_current_write_sector_buffer + 1) % NUM_SECTOR_BUFFERS; Log_DevPrintf("Read sector %u [%s]: mode %u submode 0x%02X into buffer %u", s_current_lba, - LBAToMSFString(s_current_lba).GetCharArray(), ZeroExtend32(s_last_sector_header.sector_mode), + LBAToMSFString(s_current_lba).c_str(), ZeroExtend32(s_last_sector_header.sector_mode), ZeroExtend32(s_last_sector_subheader.submode.bits), sb_num); if (s_mode.xa_enable && s_last_sector_header.sector_mode == 2) diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index 185d795c6..0874a10cd 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -7,7 +7,7 @@ #include "common/byte_stream.h" #include "common/file_system.h" #include "common/log.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "controller.h" #include "cpu_code_cache.h" @@ -397,9 +397,9 @@ bool CheatList::LoadFromLibretroString(const std::string& str) for (u32 i = 0; i < num_cheats; i++) { - const std::string* desc = FindKey(kvp, TinyString::FromFormat("cheat%u_desc", i)); - const std::string* code = FindKey(kvp, TinyString::FromFormat("cheat%u_code", i)); - const std::string* enable = FindKey(kvp, TinyString::FromFormat("cheat%u_enable", i)); + const std::string* desc = FindKey(kvp, TinyString::from_fmt("cheat{}_desc", i)); + const std::string* code = FindKey(kvp, TinyString::from_fmt("cheat{}_code", i)); + const std::string* enable = FindKey(kvp, TinyString::from_fmt("cheat{}_enable", i)); if (!desc || !code || !enable) { Log_WarningPrintf("Missing desc/code/enable for cheat %u", i); diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index 7bc250486..1b33c5007 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -799,7 +799,7 @@ bool CompileBlock(CodeBlock* block, bool allow_flush) { CPU::DisassembleInstruction(&disasm, cbi.pc, cbi.instruction.bits); Log_DebugPrintf("[%s %s 0x%08X] %08X %s", cbi.is_branch_delay_slot ? "BD" : " ", - cbi.is_load_delay_slot ? "LD" : " ", cbi.pc, cbi.instruction.bits, disasm.GetCharArray()); + cbi.is_load_delay_slot ? "LD" : " ", cbi.pc, cbi.instruction.bits, disasm.c_str()); } #endif } diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 4f4386e07..dec75b469 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -571,15 +571,15 @@ static void TracePrintInstruction() TinyString comment; DisassembleInstruction(&instr, pc, bits); DisassembleInstructionComment(&comment, pc, bits, &g_state.regs); - if (!comment.IsEmpty()) + if (!comment.empty()) { - for (u32 i = instr.GetLength(); i < 30; i++) - instr.AppendCharacter(' '); - instr.AppendString("; "); - instr.AppendString(comment); + for (u32 i = instr.length(); i < 30; i++) + instr.append(' '); + instr.append("; "); + instr.append(comment); } - std::printf("%08x: %08x %s\n", pc, bits, instr.GetCharArray()); + std::printf("%08x: %08x %s\n", pc, bits, instr.c_str()); } #endif @@ -590,15 +590,15 @@ static void PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* pref TinyString comment; DisassembleInstruction(&instr, pc, bits); DisassembleInstructionComment(&comment, pc, bits, regs); - if (!comment.IsEmpty()) + if (!comment.empty()) { - for (u32 i = instr.GetLength(); i < 30; i++) - instr.AppendCharacter(' '); - instr.AppendString("; "); - instr.AppendString(comment); + for (u32 i = instr.length(); i < 30; i++) + instr.append(' '); + instr.append("; "); + instr.append(comment); } - Log_DevPrintf("%s%08x: %08x %s", prefix, pc, bits, instr.GetCharArray()); + Log_DevPrintf("%s%08x: %08x %s", prefix, pc, bits, instr.c_str()); } static void LogInstruction(u32 bits, u32 pc, Registers* regs) @@ -607,15 +607,15 @@ static void LogInstruction(u32 bits, u32 pc, Registers* regs) TinyString comment; DisassembleInstruction(&instr, pc, bits); DisassembleInstructionComment(&comment, pc, bits, regs); - if (!comment.IsEmpty()) + if (!comment.empty()) { - for (u32 i = instr.GetLength(); i < 30; i++) - instr.AppendCharacter(' '); - instr.AppendString("; "); - instr.AppendString(comment); + for (u32 i = instr.length(); i < 30; i++) + instr.append(' '); + instr.append("; "); + instr.append(comment); } - WriteToExecutionLog("%08x: %08x %s\n", pc, bits, instr.GetCharArray()); + WriteToExecutionLog("%08x: %08x %s\n", pc, bits, instr.c_str()); } static void HandleWriteSyscall() diff --git a/src/core/cpu_disasm.cpp b/src/core/cpu_disasm.cpp index dfeba641c..ff5252efb 100644 --- a/src/core/cpu_disasm.cpp +++ b/src/core/cpu_disasm.cpp @@ -1,9 +1,12 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "cpu_disasm.h" -#include "common/assert.h" #include "cpu_core.h" + +#include "common/assert.h" +#include "common/small_string.h" + #include namespace CPU { @@ -169,9 +172,9 @@ static const std::array, 4> s_cop_c static const std::array, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}}; -static void FormatInstruction(String* dest, const Instruction inst, u32 pc, const char* format) +static void FormatInstruction(SmallStringBase* dest, const Instruction inst, u32 pc, const char* format) { - dest->Clear(); + dest->clear(); const char* str = format; while (*str != '\0') @@ -179,77 +182,77 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons const char ch = *(str++); if (ch != '$') { - dest->AppendCharacter(ch); + dest->append(ch); continue; } if (std::strncmp(str, "rs", 2) == 0) { - dest->AppendString(GetRegName(inst.r.rs)); + dest->append(GetRegName(inst.r.rs)); str += 2; } else if (std::strncmp(str, "rt", 2) == 0) { - dest->AppendString(GetRegName(inst.r.rt)); + dest->append(GetRegName(inst.r.rt)); str += 2; } else if (std::strncmp(str, "rd", 2) == 0) { - dest->AppendString(GetRegName(inst.r.rd)); + dest->append(GetRegName(inst.r.rd)); str += 2; } else if (std::strncmp(str, "shamt", 5) == 0) { - dest->AppendFormattedString("%d", ZeroExtend32(inst.r.shamt.GetValue())); + dest->append_fmt("{}", ZeroExtend32(inst.r.shamt.GetValue())); str += 5; } else if (std::strncmp(str, "immu", 4) == 0) { - dest->AppendFormattedString("%u", inst.i.imm_zext32()); + dest->append_fmt("{}", inst.i.imm_zext32()); str += 4; } else if (std::strncmp(str, "imm", 3) == 0) { // dest->AppendFormattedString("%d", static_cast(inst.i.imm_sext32())); - dest->AppendFormattedString("%04x", inst.i.imm_zext32()); + dest->append_fmt("{:04x}", inst.i.imm_zext32()); str += 3; } else if (std::strncmp(str, "rel", 3) == 0) { const u32 target = (pc + UINT32_C(4)) + (inst.i.imm_sext32() << 2); - dest->AppendFormattedString("%08x", target); + dest->append_fmt("{:08x}", target); str += 3; } else if (std::strncmp(str, "offsetrs", 8) == 0) { const s32 offset = static_cast(inst.i.imm_sext32()); - dest->AppendFormattedString("%d(%s)", offset, GetRegName(inst.i.rs)); + dest->append_fmt("{}({})", offset, GetRegName(inst.i.rs)); str += 8; } else if (std::strncmp(str, "jt", 2) == 0) { const u32 target = ((pc + UINT32_C(4)) & UINT32_C(0xF0000000)) | (inst.j.target << 2); - dest->AppendFormattedString("%08x", target); + dest->append_fmt("{:08x}", target); str += 2; } else if (std::strncmp(str, "copcc", 5) == 0) { - dest->AppendCharacter(((inst.bits & (UINT32_C(1) << 24)) != 0) ? 't' : 'f'); + dest->append(((inst.bits & (UINT32_C(1) << 24)) != 0) ? 't' : 'f'); str += 5; } else if (std::strncmp(str, "coprd", 5) == 0) { - dest->AppendFormattedString("%u", ZeroExtend32(static_cast(inst.r.rd.GetValue()))); + dest->append_fmt("{}", ZeroExtend32(static_cast(inst.r.rd.GetValue()))); str += 5; } else if (std::strncmp(str, "coprt", 5) == 0) { - dest->AppendFormattedString("%u", ZeroExtend32(static_cast(inst.r.rt.GetValue()))); + dest->append_fmt("{}", ZeroExtend32(static_cast(inst.r.rt.GetValue()))); str += 5; } else if (std::strncmp(str, "cop", 3) == 0) { - dest->AppendFormattedString("%u", static_cast(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK); + dest->append_fmt("{}", static_cast(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK); str += 3; } else @@ -259,7 +262,7 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons } } -static void FormatComment(String* dest, const Instruction inst, u32 pc, Registers* regs, const char* format) +static void FormatComment(SmallStringBase* dest, const Instruction inst, u32 pc, Registers* regs, const char* format) { const char* str = format; while (*str != '\0') @@ -270,21 +273,21 @@ static void FormatComment(String* dest, const Instruction inst, u32 pc, Register if (std::strncmp(str, "rs", 2) == 0) { - dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rs), - regs->r[static_cast(inst.r.rs.GetValue())]); + dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rs), + regs->r[static_cast(inst.r.rs.GetValue())]); str += 2; } else if (std::strncmp(str, "rt", 2) == 0) { - dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rt), - regs->r[static_cast(inst.r.rt.GetValue())]); + dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rt), + regs->r[static_cast(inst.r.rt.GetValue())]); str += 2; } else if (std::strncmp(str, "rd", 2) == 0) { - dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rd), - regs->r[static_cast(inst.r.rd.GetValue())]); + dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rd), + regs->r[static_cast(inst.r.rd.GetValue())]); str += 2; } else if (std::strncmp(str, "shamt", 5) == 0) @@ -306,8 +309,8 @@ static void FormatComment(String* dest, const Instruction inst, u32 pc, Register else if (std::strncmp(str, "offsetrs", 8) == 0) { const s32 offset = static_cast(inst.i.imm_sext32()); - dest->AppendFormattedString("%saddr=0x%08X", dest->IsEmpty() ? "" : ", ", - regs->r[static_cast(inst.i.rs.GetValue())] + offset); + dest->append_fmt("{}addr={:08X}", dest->empty() ? "" : ", ", + regs->r[static_cast(inst.i.rs.GetValue())] + offset); str += 8; } else if (std::strncmp(str, "jt", 2) == 0) @@ -338,8 +341,8 @@ static void FormatComment(String* dest, const Instruction inst, u32 pc, Register } template -void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const std::pair* table, - size_t table_size, T table_key) +static void FormatCopInstruction(SmallStringBase* dest, u32 pc, const Instruction inst, + const std::pair* table, size_t table_size, T table_key) { for (size_t i = 0; i < table_size; i++) { @@ -350,12 +353,12 @@ void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const st } } - dest->Format("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); + dest->fmt("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); } template -void FormatCopComment(String* dest, u32 pc, Registers* regs, const Instruction inst, - const std::pair* table, size_t table_size, T table_key) +static void FormatCopComment(SmallStringBase* dest, u32 pc, Registers* regs, const Instruction inst, + const std::pair* table, size_t table_size, T table_key) { for (size_t i = 0; i < table_size; i++) { @@ -367,7 +370,7 @@ void FormatCopComment(String* dest, u32 pc, Registers* regs, const Instruction i } } -void DisassembleInstruction(String* dest, u32 pc, u32 bits) +void DisassembleInstruction(SmallStringBase* dest, u32 pc, u32 bits) { const Instruction inst{bits}; switch (inst.op) @@ -400,7 +403,7 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits) case InstructionOp::cop3: default: { - dest->Format("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); + dest->fmt("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); } break; } @@ -427,7 +430,7 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits) } } -void DisassembleInstructionComment(String* dest, u32 pc, u32 bits, Registers* regs) +void DisassembleInstructionComment(SmallStringBase* dest, u32 pc, u32 bits, Registers* regs) { const Instruction inst{bits}; switch (inst.op) @@ -461,7 +464,7 @@ void DisassembleInstructionComment(String* dest, u32 pc, u32 bits, Registers* re case InstructionOp::cop3: default: { - dest->Format("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); + dest->fmt("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); } break; } diff --git a/src/core/cpu_disasm.h b/src/core/cpu_disasm.h index d78a685a0..b3968bffa 100644 --- a/src/core/cpu_disasm.h +++ b/src/core/cpu_disasm.h @@ -1,11 +1,12 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "common/string.h" #include "cpu_types.h" +class SmallStringBase; + namespace CPU { -void DisassembleInstruction(String* dest, u32 pc, u32 bits); -void DisassembleInstructionComment(String* dest, u32 pc, u32 bits, Registers* regs); +void DisassembleInstruction(SmallStringBase* dest, u32 pc, u32 bits); +void DisassembleInstructionComment(SmallStringBase* dest, u32 pc, u32 bits, Registers* regs); } // namespace CPU diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index e4d3a70b4..e10b3ec2b 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -32,7 +32,7 @@ #include "common/log.h" #include "common/make_array.h" #include "common/path.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "common/threading.h" @@ -54,19 +54,23 @@ Log_SetChannel(FullscreenUI); #define TR_CONTEXT "FullscreenUI" -namespace FullscreenUI { +namespace { template -class IconStackString : public StackString +class IconStackString : public SmallStackString { public: ALWAYS_INLINE IconStackString(const char* icon, const char* str) { - StackString::Fmt("{} {}", icon, Host::TranslateToStringView(TR_CONTEXT, str)); + SmallStackString::fmt("{} {}", icon, Host::TranslateToStringView(TR_CONTEXT, str)); + } + ALWAYS_INLINE IconStackString(const char* icon, const char* str, const char* suffix) + { + SmallStackString::fmt("{} {}##{}", icon, Host::TranslateToStringView(TR_CONTEXT, str), suffix); } }; -} // namespace FullscreenUI +} // namespace -#define FSUI_ICONSTR(icon, str) FullscreenUI::IconStackString<128>(icon, str).GetCharArray() +#define FSUI_ICONSTR(icon, str) IconStackString<128>(icon, str).c_str() #define FSUI_STR(str) Host::TranslateToString(TR_CONTEXT, str) #define FSUI_CSTR(str) Host::TranslateToCString(TR_CONTEXT, str) #define FSUI_VSTR(str) Host::TranslateToStringView(TR_CONTEXT, str) @@ -472,7 +476,7 @@ static GameListPage s_game_list_page = GameListPage::Grid; // Utility ////////////////////////////////////////////////////////////////////////// -void FullscreenUI::TimeToPrintableString(String* str, time_t t) +void FullscreenUI::TimeToPrintableString(SmallStringBase* str, time_t t) { struct tm lt = {}; #ifdef _MSC_VER @@ -483,7 +487,7 @@ void FullscreenUI::TimeToPrintableString(String* str, time_t t) char buf[256]; std::strftime(buf, sizeof(buf), "%c", <); - str->Assign(buf); + str->assign(buf); } void FullscreenUI::StartAsyncOp(std::function callback, std::string name) @@ -1342,7 +1346,7 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn const char* name, const char* display_name, bool show_type) { TinyString title; - title.Fmt("{}/{}", section, name); + title.fmt("{}/{}", section, name); ImRect bb; bool visible, hovered, clicked; @@ -1360,17 +1364,17 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn switch (type) { case InputBindingInfo::Type::Button: - title = fmt::format(ICON_FA_DOT_CIRCLE "{}", display_name); + title.fmt(ICON_FA_DOT_CIRCLE "{}", display_name); break; case InputBindingInfo::Type::Axis: case InputBindingInfo::Type::HalfAxis: - title = fmt::format(ICON_FA_BULLSEYE "{}", display_name); + title.fmt(ICON_FA_BULLSEYE "{}", display_name); break; case InputBindingInfo::Type::Motor: - title = fmt::format(ICON_FA_BELL "{}", display_name); + title.fmt(ICON_FA_BELL "{}", display_name); break; case InputBindingInfo::Type::Macro: - title = fmt::format(ICON_FA_PIZZA_SLICE "{}", display_name); + title.fmt(ICON_FA_PIZZA_SLICE "{}", display_name); break; default: title = display_name; @@ -1379,8 +1383,8 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn } ImGui::PushFont(g_large_font); - ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.GetCharArray() : display_name, nullptr, - nullptr, ImVec2(0.0f, 0.0f), &title_bb); + ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.c_str() : display_name, nullptr, nullptr, + ImVec2(0.0f, 0.0f), &title_bb); ImGui::PopFont(); const std::string value(bsi->GetStringValue(section, name)); @@ -1521,12 +1525,12 @@ void FullscreenUI::DrawInputBindingWindow() if (ImGui::BeginPopupModal(title, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs)) { - ImGui::TextWrapped("%s", SmallString::FromFmt(FSUI_FSTR("Setting {} binding {}."), s_input_binding_section, - s_input_binding_display_name) - .GetCharArray()); + ImGui::TextWrapped("%s", SmallString::from_fmt(FSUI_FSTR("Setting {} binding {}."), s_input_binding_section, + s_input_binding_display_name) + .c_str()); ImGui::TextUnformatted(FSUI_CSTR("Push a controller button or axis now.")); ImGui::NewLine(); - ImGui::TextUnformatted(SmallString::FromFmt(FSUI_FSTR("Timing out in {:.0f} seconds..."), time_remaining)); + ImGui::TextUnformatted(SmallString::from_fmt(FSUI_FSTR("Timing out in {:.0f} seconds..."), time_remaining)); ImGui::EndPopup(); } @@ -2004,7 +2008,7 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); TinyString value_text; if (value.has_value()) - value_text.Format(format, value.value()); + value_text.format(format, value.value()); else value_text = FSUI_VSTR("Use Global Setting"); @@ -2821,14 +2825,14 @@ void FullscreenUI::DrawBIOSSettingsPage() continue; TinyString title; - title.Fmt(FSUI_FSTR("BIOS for {}"), Settings::GetConsoleRegionDisplayName(region)); + title.fmt(FSUI_FSTR("BIOS for {}"), Settings::GetConsoleRegionDisplayName(region)); const std::optional filename(bsi->GetOptionalStringValue( "BIOS", config_keys[i], game_settings ? std::nullopt : std::optional(""))); if (MenuButtonWithValue(title, - SmallString::FromFmt(FSUI_FSTR("BIOS to use when emulating {} consoles."), - Settings::GetConsoleRegionDisplayName(region)), + SmallString::from_fmt(FSUI_FSTR("BIOS to use when emulating {} consoles."), + Settings::GetConsoleRegionDisplayName(region)), filename.has_value() ? (filename->empty() ? FSUI_CSTR("Auto-Detect") : filename->c_str()) : FSUI_CSTR("Use Global Setting"))) { @@ -3052,7 +3056,7 @@ void FullscreenUI::DrawEmulationSettingsPage() u64 ram_usage, vram_usage; System::CalculateRewindMemoryUsage(rewind_save_slots, &ram_usage, &vram_usage); - rewind_summary.Fmt( + rewind_summary.fmt( FSUI_FSTR("Rewind for {0} frames, lasting {1:.2f} seconds will require up to {3} MB of RAM and {4} MB of VRAM."), rewind_save_slots, duration, ram_usage / 1048576, vram_usage / 1048576); } @@ -3277,18 +3281,18 @@ void FullscreenUI::DrawControllerSettingsPage() if (mtap_enabled[mtap_port]) { - MenuHeading(TinyString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}{}")), mtap_port + 1, - mtap_slot_names[mtap_slot])); + MenuHeading(TinyString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}{}")), mtap_port + 1, + mtap_slot_names[mtap_slot])); } else { - MenuHeading(TinyString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}")), mtap_port + 1)); + MenuHeading(TinyString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}")), mtap_port + 1)); } const std::string section(fmt::format("Pad{}", global_slot + 1)); const std::string type(bsi->GetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(global_slot))); const Controller::ControllerInfo* ci = Controller::GetControllerInfo(type); - if (MenuButton(TinyString::FromFmt("{}##type{}", FSUI_ICONSTR(ICON_FA_GAMEPAD, "Controller Type"), global_slot), + if (MenuButton(TinyString::from_fmt("{}##type{}", FSUI_ICONSTR(ICON_FA_GAMEPAD, "Controller Type"), global_slot), ci ? ci->display_name : FSUI_CSTR("Unknown"))) { std::vector> raw_options(Controller::GetControllerTypeNames()); @@ -3298,7 +3302,7 @@ void FullscreenUI::DrawControllerSettingsPage() { options.emplace_back(std::move(it.second), type == it.first); } - OpenChoiceDialog(TinyString::FromFmt(FSUI_FSTR("Port {} Controller Type"), global_slot + 1), false, + OpenChoiceDialog(TinyString::from_fmt(FSUI_FSTR("Port {} Controller Type"), global_slot + 1), false, std::move(options), [game_settings, section, raw_options = std::move(raw_options)](s32 index, const std::string& title, bool checked) { @@ -3327,25 +3331,25 @@ void FullscreenUI::DrawControllerSettingsPage() if (mtap_enabled[mtap_port]) { - MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {}{} Macros")), - mtap_port + 1, mtap_slot_names[mtap_slot])); + MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {}{} Macros")), + mtap_port + 1, mtap_slot_names[mtap_slot])); } else { - MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {} Macros")), - mtap_port + 1)); + MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {} Macros")), + mtap_port + 1)); } for (u32 macro_index = 0; macro_index < InputManager::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++) { DrawInputBindingButton(bsi, InputBindingInfo::Type::Macro, section.c_str(), - TinyString::FromFmt("Macro{}", macro_index + 1), - TinyString::FromFmt(FSUI_FSTR("Macro {} Trigger"), macro_index + 1)); + TinyString::from_fmt("Macro{}", macro_index + 1), + TinyString::from_fmt(FSUI_FSTR("Macro {} Trigger"), macro_index + 1)); std::string binds_string( bsi->GetStringValue(section.c_str(), fmt::format("Macro{}Binds", macro_index + 1).c_str())); if (MenuButton( - TinyString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_KEYBOARD, "Macro {} Buttons")), macro_index + 1), + TinyString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_KEYBOARD, "Macro {} Buttons")), macro_index + 1), binds_string.empty() ? FSUI_CSTR("No Buttons Selected") : binds_string.c_str())) { std::vector buttons_split(StringUtil::SplitString(binds_string, '&', true)); @@ -3363,7 +3367,7 @@ void FullscreenUI::DrawControllerSettingsPage() } OpenChoiceDialog( - TinyString::FromFmt(FSUI_FSTR("Select Macro {} Binds"), macro_index + 1), true, std::move(options), + TinyString::from_fmt(FSUI_FSTR("Select Macro {} Binds"), macro_index + 1), true, std::move(options), [game_settings, section, macro_index, ci](s32 index, const std::string& title, bool checked) { // convert display name back to bind name std::string_view to_modify; @@ -3409,13 +3413,13 @@ void FullscreenUI::DrawControllerSettingsPage() const std::string freq_key(fmt::format("Macro{}Frequency", macro_index + 1)); const SmallString freq_title = - SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Macro {} Frequency")), macro_index + 1); + SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Macro {} Frequency")), macro_index + 1); s32 frequency = bsi->GetIntValue(section.c_str(), freq_key.c_str(), 0); SmallString freq_summary; if (frequency == 0) freq_summary = FSUI_VSTR("Macro will not auto-toggle."); else - freq_summary.Fmt(FSUI_FSTR("Macro will toggle every {} frames."), frequency); + freq_summary.fmt(FSUI_FSTR("Macro will toggle every {} frames."), frequency); if (MenuButton(freq_title, freq_summary)) ImGui::OpenPopup(freq_title); @@ -3456,19 +3460,20 @@ void FullscreenUI::DrawControllerSettingsPage() { if (mtap_enabled[mtap_port]) { - MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {}{} Settings")), - mtap_port + 1, mtap_slot_names[mtap_slot])); + MenuHeading( + SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {}{} Settings")), + mtap_port + 1, mtap_slot_names[mtap_slot])); } else { - MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {} Settings")), - mtap_port + 1)); + MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {} Settings")), + mtap_port + 1)); } for (const SettingInfo& si : ci->settings) { TinyString title; - title.Fmt(ICON_FA_COG "{}", si.display_name); + title.fmt(ICON_FA_COG "{}", si.display_name); switch (si.type) { case SettingInfo::Type::Boolean: @@ -3583,13 +3588,13 @@ void FullscreenUI::DrawMemoryCardSettingsPage() for (u32 i = 0; i < 2; i++) { - MenuHeading(TinyString::FromFmt(FSUI_FSTR("Memory Card Port {}"), i + 1)); + MenuHeading(TinyString::from_fmt(FSUI_FSTR("Memory Card Port {}"), i + 1)); const MemoryCardType default_type = (i == 0) ? Settings::DEFAULT_MEMORY_CARD_1_TYPE : Settings::DEFAULT_MEMORY_CARD_2_TYPE; DrawEnumSetting( - bsi, TinyString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SD_CARD, "Memory Card {} Type")), i + 1), - SmallString::FromFmt(FSUI_FSTR("Sets which sort of memory card image will be used for slot {}."), i + 1), + bsi, TinyString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SD_CARD, "Memory Card {} Type")), i + 1), + SmallString::from_fmt(FSUI_FSTR("Sets which sort of memory card image will be used for slot {}."), i + 1), "MemoryCards", type_keys[i], default_type, &Settings::ParseMemoryCardTypeName, &Settings::GetMemoryCardTypeName, &Settings::GetMemoryCardTypeDisplayName, MemoryCardType::Count); @@ -3605,7 +3610,7 @@ void FullscreenUI::DrawMemoryCardSettingsPage() std::optional((i == 0) ? "shared_card_1.mcd" : "shared_card_2.mcd"))); TinyString title; - title.Fmt("{}##card_name_{}", FSUI_ICONSTR(ICON_FA_FILE, "Shared Card Name"), i); + title.fmt("{}##card_name_{}", FSUI_ICONSTR(ICON_FA_FILE, "Shared Card Name"), i); if (MenuButtonWithValue(title, FSUI_CSTR("The selected memory card image will be used in shared mode for this slot."), path_value.has_value() ? path_value->c_str() : "Use Global Setting", is_shared)) @@ -4075,7 +4080,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage() PostProcessingStageInfo& si = s_postprocessing_stages[stage_index]; ImGui::PushID(stage_index); - str.Fmt(FSUI_FSTR("Stage {}: {}"), stage_index + 1, si.name); + str.fmt(FSUI_FSTR("Stage {}: {}"), stage_index + 1, si.name); MenuHeading(str); if (MenuButton(FSUI_ICONSTR(ICON_FA_TIMES, "Remove From Chain"), FSUI_CSTR("Removes this shader from the chain."))) @@ -4109,7 +4114,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage() case PostProcessing::ShaderOption::Type::Bool: { bool value = (opt.value[0].int_value != 0); - tstr.Fmt(ICON_FA_COGS "{}", opt.ui_name); + tstr.fmt(ICON_FA_COGS "{}", opt.ui_name); if (ToggleButton(tstr, (opt.default_value[0].int_value != 0) ? FSUI_CSTR("Default: Enabled") : FSUI_CSTR("Default: Disabled"), @@ -4124,8 +4129,8 @@ void FullscreenUI::DrawPostProcessingSettingsPage() case PostProcessing::ShaderOption::Type::Float: { - tstr.Fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); - str.Fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].float_value, + tstr.fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); + str.fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].float_value, opt.default_value[0].float_value, opt.min_value[0].float_value, opt.max_value[0].float_value); if (MenuButton(tstr, str)) ImGui::OpenPopup(tstr); @@ -4223,8 +4228,8 @@ void FullscreenUI::DrawPostProcessingSettingsPage() case PostProcessing::ShaderOption::Type::Int: { - tstr.Fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); - str.Fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].int_value, + tstr.fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); + str.fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].int_value, opt.default_value[0].int_value, opt.min_value[0].int_value, opt.max_value[0].int_value); if (MenuButton(tstr, str)) ImGui::OpenPopup(tstr); @@ -4489,17 +4494,17 @@ void FullscreenUI::DrawAchievementsSettingsPage() if (bsi->ContainsValue("Cheevos", "Token")) { ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]); - ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")), - bsi->GetStringValue("Cheevos", "Username")), + ActiveButton(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")), + bsi->GetStringValue("Cheevos", "Username")), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); TinyString ts_string; - ts_string.AppendFmtString( + ts_string.fmt( "{:%Y-%m-%d %H:%M:%S}", fmt::localtime(StringUtil::FromChars(bsi->GetStringValue("Cheevos", "LoginTimestamp", "0")).value_or(0))); - ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_CLOCK, "Login token generated on {}")), - ts_string.GetCharArray()), - false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); + ActiveButton( + SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_CLOCK, "Login token generated on {}")), ts_string), + false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); ImGui::PopStyleColor(); if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Logout"), FSUI_CSTR("Logs out of RetroAchievements."))) @@ -4522,14 +4527,14 @@ void FullscreenUI::DrawAchievementsSettingsPage() const auto lock = Achievements::GetLock(); ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]); - ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_BOOKMARK, "Game: {} ({})")), - Achievements::GetGameID(), Achievements::GetGameTitle()), + ActiveButton(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_BOOKMARK, "Game: {} ({})")), + Achievements::GetGameID(), Achievements::GetGameTitle()), false, false, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); const std::string& rich_presence_string = Achievements::GetRichPresenceString(); if (!rich_presence_string.empty()) { - ActiveButton(SmallString::FromFmt(ICON_FA_MAP "{}", rich_presence_string), false, false, + ActiveButton(SmallString::from_fmt(ICON_FA_MAP "{}", rich_presence_string), false, false, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); } else @@ -4675,8 +4680,8 @@ void FullscreenUI::DrawPauseMenu() const std::string& serial = System::GetGameSerial(); if (!serial.empty()) - buffer.Format("%s - ", serial.c_str()); - buffer.AppendString(Path::GetFileName(System::GetDiscPath())); + buffer.fmt("{} - ", serial); + buffer.append(Path::GetFileName(System::GetDiscPath())); const ImVec2 title_size( g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits::max(), -1.0f, title.c_str())); @@ -4712,8 +4717,8 @@ void FullscreenUI::DrawPauseMenu() } } - DrawShadowedText(dl, g_large_font, title_pos, text_color, title.c_str()); - DrawShadowedText(dl, g_medium_font, subtitle_pos, text_color, buffer); + DrawShadowedText(dl, g_large_font, title_pos, text_color, title.c_str(), title.c_str() + title.length()); + DrawShadowedText(dl, g_medium_font, subtitle_pos, text_color, buffer.c_str(), buffer.end_ptr()); const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height, display_size.y - LayoutScale(20.0f + 50.0f) - rp_height); @@ -4723,14 +4728,12 @@ void FullscreenUI::DrawPauseMenu() // current time / play time { - buffer.Fmt("{:%X}", fmt::localtime(std::time(nullptr))); + buffer.fmt("{:%X}", fmt::localtime(std::time(nullptr))); const ImVec2 time_size(g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits::max(), -1.0f, - buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength())); + buffer.c_str(), buffer.end_ptr())); const ImVec2 time_pos(display_size.x - LayoutScale(10.0f) - time_size.x, LayoutScale(10.0f)); - DrawShadowedText(dl, g_large_font, time_pos, text_color, buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength()); + DrawShadowedText(dl, g_large_font, time_pos, text_color, buffer.c_str(), buffer.end_ptr()); const std::string& serial = System::GetGameSerial(); if (!serial.empty()) @@ -4738,24 +4741,19 @@ void FullscreenUI::DrawPauseMenu() const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial); const std::time_t session_time = static_cast(System::GetSessionPlayedTime()); - buffer.Fmt(FSUI_FSTR("Session: {}"), GameList::FormatTimespan(session_time, true).GetStringView()); + buffer.fmt(FSUI_FSTR("Session: {}"), GameList::FormatTimespan(session_time, true)); const ImVec2 session_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits::max(), - -1.0f, buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength())); + -1.0f, buffer.c_str(), buffer.end_ptr())); const ImVec2 session_pos(display_size.x - LayoutScale(10.0f) - session_size.x, time_pos.y + g_large_font->FontSize + LayoutScale(4.0f)); - DrawShadowedText(dl, g_medium_font, session_pos, text_color, buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength()); + DrawShadowedText(dl, g_medium_font, session_pos, text_color, buffer.c_str(), buffer.end_ptr()); - buffer.Fmt(FSUI_FSTR("All Time: {}"), - GameList::FormatTimespan(cached_played_time + session_time, true).GetStringView()); + buffer.fmt(FSUI_FSTR("All Time: {}"), GameList::FormatTimespan(cached_played_time + session_time, true)); const ImVec2 total_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits::max(), - -1.0f, buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength())); + -1.0f, buffer.c_str(), buffer.end_ptr())); const ImVec2 total_pos(display_size.x - LayoutScale(10.0f) - total_size.x, session_pos.y + g_medium_font->FontSize + LayoutScale(4.0f)); - DrawShadowedText(dl, g_medium_font, total_pos, text_color, buffer.GetCharArray(), - buffer.GetCharArray() + buffer.GetLength()); + DrawShadowedText(dl, g_medium_font, total_pos, text_color, buffer.c_str(), buffer.end_ptr()); } } @@ -5413,7 +5411,7 @@ void FullscreenUI::DrawResumeStateSelector() TimeToPrintableString(&time, entry.timestamp); ImGui::TextWrapped( FSUI_CSTR("A resume save state created at %s was found.\n\nDo you want to load this save and continue?"), - time.GetCharArray()); + time.c_str()); const GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get(); const float image_height = LayoutScale(250.0f); @@ -5692,16 +5690,11 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) GPUTexture* cover_texture = GetGameListCover(entry); if (entry->serial.empty()) - { - summary.Fmt("{} - ", Settings::GetDiscRegionDisplayName(entry->region)); - } + summary.fmt("{} - ", Settings::GetDiscRegionDisplayName(entry->region)); else - { - summary.Fmt("{} - {} - ", entry->serial, Settings::GetDiscRegionDisplayName(entry->region)); - } + summary.fmt("{} - {} - ", entry->serial, Settings::GetDiscRegionDisplayName(entry->region)); - const std::string_view filename(Path::GetFileName(entry->path)); - summary.AppendString(filename); + summary.append(Path::GetFileName(entry->path)); const ImRect image_rect( CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast(cover_texture->GetWidth()), @@ -5720,12 +5713,11 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) entry->title.c_str() + entry->title.size(), nullptr, ImVec2(0.0f, 0.0f), &title_bb); ImGui::PopFont(); - if (!summary.IsEmpty()) + if (!summary.empty()) { ImGui::PushFont(g_medium_font); - ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, summary.GetCharArray(), - summary.GetCharArray() + summary.GetLength(), nullptr, ImVec2(0.0f, 0.0f), - &summary_bb); + ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, summary.c_str(), summary.end_ptr(), nullptr, + ImVec2(0.0f, 0.0f), &summary_bb); ImGui::PopFont(); } @@ -5832,10 +5824,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size) ImGui::Text(" (%s)", GameDatabase::GetCompatibilityRatingDisplayName(selected_entry->compatibility)); // play time - ImGui::Text(FSUI_CSTR("Time Played: %s"), - GameList::FormatTimespan(selected_entry->total_played_time).GetCharArray()); - ImGui::Text(FSUI_CSTR("Last Played: %s"), - GameList::FormatTimestamp(selected_entry->last_played_time).GetCharArray()); + ImGui::Text(FSUI_CSTR("Time Played: %s"), GameList::FormatTimespan(selected_entry->total_played_time).c_str()); + ImGui::Text(FSUI_CSTR("Last Played: %s"), GameList::FormatTimestamp(selected_entry->last_played_time).c_str()); // size ImGui::Text(FSUI_CSTR("Size: %.2f MB"), static_cast(selected_entry->total_size) / 1048576.0f); @@ -5941,11 +5931,10 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size) const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max); const std::string_view title( std::string_view(entry->title).substr(0, (entry->title.length() > 31) ? 31 : std::string_view::npos)); - draw_title.Fmt("{}{}", title, (title.length() == entry->title.length()) ? "" : "..."); + draw_title.fmt("{}{}", title, (title.length() == entry->title.length()) ? "" : "..."); ImGui::PushFont(g_medium_font); - ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, draw_title.GetCharArray(), - draw_title.GetCharArray() + draw_title.GetLength(), nullptr, ImVec2(0.5f, 0.0f), - &title_bb); + ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, draw_title.c_str(), draw_title.end_ptr(), nullptr, + ImVec2(0.5f, 0.0f), &title_bb); ImGui::PopFont(); if (pressed) @@ -6073,7 +6062,7 @@ void FullscreenUI::DrawGameListSettingsPage(const ImVec2& heading_size) for (const auto& it : s_game_list_directories_cache) { - if (MenuButton(SmallString::FromFmt(ICON_FA_FOLDER "{}", it.first), + if (MenuButton(SmallString::from_fmt(ICON_FA_FOLDER "{}", it.first), it.second ? FSUI_CSTR("Scanning Subdirectories") : FSUI_CSTR("Not Scanning Subdirectories"))) { ImGuiFullscreen::ChoiceDialogOptions options = { @@ -6609,8 +6598,7 @@ void FullscreenUI::ProgressCallback::Redraw(bool force) return; m_last_progress_percent = percent; - ImGuiFullscreen::UpdateBackgroundProgressDialog( - m_name.c_str(), std::string(m_status_text.GetCharArray(), m_status_text.GetLength()), 0, 100, percent); + ImGuiFullscreen::UpdateBackgroundProgressDialog(m_name.c_str(), m_status_text, 0, 100, percent); } void FullscreenUI::ProgressCallback::DisplayError(const char* message) diff --git a/src/core/fullscreen_ui.h b/src/core/fullscreen_ui.h index 64897d920..f3b896341 100644 --- a/src/core/fullscreen_ui.h +++ b/src/core/fullscreen_ui.h @@ -7,7 +7,7 @@ #include #include -class String; +class SmallStringBase; struct Settings; @@ -32,7 +32,7 @@ void ReturnToPreviousWindow(); void Shutdown(); void Render(); void InvalidateCoverCache(); -void TimeToPrintableString(String* str, time_t t); +void TimeToPrintableString(SmallStringBase* str, time_t t); // Returns true if the message has been dismissed. bool DrawErrorWindow(const char* message); diff --git a/src/core/game_database.cpp b/src/core/game_database.cpp index 18f5b02e9..6ec4d6584 100644 --- a/src/core/game_database.cpp +++ b/src/core/game_database.cpp @@ -463,18 +463,19 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes if ((supported_controllers & BIT_FOR(supported_ctype)) == 0) continue; - if (!supported_controller_string.IsEmpty()) - supported_controller_string.AppendString(", "); + if (!supported_controller_string.empty()) + supported_controller_string.append(", "); - supported_controller_string.AppendString(Settings::GetControllerTypeDisplayName(supported_ctype)); + supported_controller_string.append(Settings::GetControllerTypeDisplayName(supported_ctype)); } - Host::AddKeyedFormattedOSDMessage( - "gamedb_controller_unsupported", 30.0f, - TRANSLATE("OSDMessage", "Controller in port %u (%s) is not supported for %s.\nSupported controllers: " - "%s\nPlease configure a supported controller from the list above."), - i + 1u, Settings::GetControllerTypeDisplayName(ctype), System::GetGameTitle().c_str(), - supported_controller_string.GetCharArray()); + Host::AddKeyedOSDMessage( + "gamedb_controller_unsupported", + fmt::format( + TRANSLATE_FS("OSDMessage", "Controller in port {0} ({1}) is not supported for {2}.\nSupported controllers: " + "{3}\nPlease configure a supported controller from the list above."), + i + 1u, Settings::GetControllerTypeDisplayName(ctype), System::GetGameTitle(), supported_controller_string), + Host::OSD_CRITICAL_ERROR_DURATION); } } } diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 533c3be12..d6f9334c7 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -994,7 +994,7 @@ TinyString GameList::FormatTimestamp(std::time_t timestamp) { char buf[128]; std::strftime(buf, std::size(buf), "%x", &ttime); - ret.Assign(buf); + ret.assign(buf); } } @@ -1011,22 +1011,22 @@ TinyString GameList::FormatTimespan(std::time_t timespan, bool long_format) if (!long_format) { if (hours >= 100) - ret.Fmt(TRANSLATE_FS("GameList", "{}h {}m"), hours, minutes); + ret.fmt(TRANSLATE_FS("GameList", "{}h {}m"), hours, minutes); else if (hours > 0) - ret.Fmt(TRANSLATE_FS("GameList", "{}h {}m {}s"), hours, minutes, seconds); + ret.fmt(TRANSLATE_FS("GameList", "{}h {}m {}s"), hours, minutes, seconds); else if (minutes > 0) - ret.Fmt(TRANSLATE_FS("GameList", "{}m {}s"), minutes, seconds); + ret.fmt(TRANSLATE_FS("GameList", "{}m {}s"), minutes, seconds); else if (seconds > 0) - ret.Fmt(TRANSLATE_FS("GameList", "{}s"), seconds); + ret.fmt(TRANSLATE_FS("GameList", "{}s"), seconds); else ret = TRANSLATE_SV("GameList", "None"); } else { if (hours > 0) - ret = fmt::format(TRANSLATE_FS("GameList", "{} hours"), hours); + ret.fmt(TRANSLATE_FS("GameList", "{} hours"), hours); else - ret = fmt::format(TRANSLATE_FS("GameList", "{} minutes"), minutes); + ret.fmt(TRANSLATE_FS("GameList", "{} minutes"), minutes); } return ret; diff --git a/src/core/game_list.h b/src/core/game_list.h index 1d1a7d98d..93fdcdbd3 100644 --- a/src/core/game_list.h +++ b/src/core/game_list.h @@ -8,7 +8,7 @@ #include "util/cd_image.h" -#include "common/string.h" +#include "common/small_string.h" #include #include diff --git a/src/core/gpu_commands.cpp b/src/core/gpu_commands.cpp index 7187b3fd5..767f1f4d9 100644 --- a/src/core/gpu_commands.cpp +++ b/src/core/gpu_commands.cpp @@ -180,8 +180,8 @@ bool GPU::HandleUnknownGP0Command() SmallString dump; for (u32 i = 0; i < m_fifo.GetSize(); i++) - dump.AppendFormattedString("%s0x%08X", (i > 0) ? " " : "", FifoPeek(i)); - Log_ErrorPrintf("FIFO: %s", dump.GetCharArray()); + dump.append_fmt("{}{:08X}", (i > 0) ? " " : "", FifoPeek(i)); + Log_ErrorPrintf("FIFO: %s", dump.c_str()); m_fifo.RemoveOne(); EndCommand(); diff --git a/src/core/host.h b/src/core/host.h index b7031b416..ccde4c78d 100644 --- a/src/core/host.h +++ b/src/core/host.h @@ -5,7 +5,7 @@ #include "util/host.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/types.h" #include diff --git a/src/core/host_interface_progress_callback.cpp b/src/core/host_interface_progress_callback.cpp index 57246cc83..d53a097c9 100644 --- a/src/core/host_interface_progress_callback.cpp +++ b/src/core/host_interface_progress_callback.cpp @@ -6,7 +6,9 @@ #include "host.h" Log_SetChannel(HostInterfaceProgressCallback); -HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() {} +HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() +{ +} void HostInterfaceProgressCallback::PushState() { @@ -64,7 +66,8 @@ void HostInterfaceProgressCallback::Redraw(bool force) return; m_last_progress_percent = percent; - Host::DisplayLoadingScreen(m_status_text, 0, static_cast(m_progress_range), static_cast(m_progress_value)); + Host::DisplayLoadingScreen(m_status_text.c_str(), 0, static_cast(m_progress_range), + static_cast(m_progress_value)); } void HostInterfaceProgressCallback::DisplayError(const char* message) diff --git a/src/core/imgui_overlays.cpp b/src/core/imgui_overlays.cpp index df9e740ef..59698829f 100644 --- a/src/core/imgui_overlays.cpp +++ b/src/core/imgui_overlays.cpp @@ -54,7 +54,7 @@ Log_SetChannel(ImGuiManager); namespace ImGuiManager { -static void FormatProcessorStat(String& text, double usage, double time); +static void FormatProcessorStat(SmallStringBase& text, double usage, double time); static void DrawPerformanceOverlay(); static void DrawEnhancementsOverlay(); static void DrawInputsOverlay(); @@ -179,12 +179,12 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, ImGui::TextUnformatted(message); TinyString buf; - buf.Fmt("{}/{}", progress_value, progress_max); + buf.fmt("{}/{}", progress_value, progress_max); - const ImVec2 prog_size = ImGui::CalcTextSize(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength()); + const ImVec2 prog_size = ImGui::CalcTextSize(buf.c_str(), buf.end_ptr()); ImGui::SameLine(); ImGui::SetCursorPosX(width - padding_and_rounding - prog_size.x); - ImGui::TextUnformatted(buf.GetCharArray(), buf.GetCharArray() + buf.GetLength()); + ImGui::TextUnformatted(buf.c_str(), buf.end_ptr()); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f); ImGui::ProgressBar(static_cast(progress_value) / static_cast(progress_max - progress_min), @@ -259,15 +259,15 @@ void ImGuiManager::RenderOverlayWindows() } } -void ImGuiManager::FormatProcessorStat(String& text, double usage, double time) +void ImGuiManager::FormatProcessorStat(SmallStringBase& text, double usage, double time) { // Some values, such as GPU (and even CPU to some extent) can be out of phase with the wall clock, // which the processor time is divided by to get a utilization percentage. Let's clamp it at 100%, // so that people don't get confused, and remove the decimal places when it's there while we're at it. if (usage >= 99.95) - text.AppendFmtString("100% ({:.2f}ms)", time); + text.append_fmt("100% ({:.2f}ms)", time); else - text.AppendFmtString("{:.1f}% ({:.2f}ms)", usage, time); + text.append_fmt("{:.1f}% ({:.2f}ms)", usage, time); } void ImGuiManager::DrawPerformanceOverlay() @@ -301,7 +301,7 @@ void ImGuiManager::DrawPerformanceOverlay() dl->AddText( \ font, font->FontSize, \ ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x + shadow_offset, position_y + shadow_offset), \ - IM_COL32(0, 0, 0, 100), text, text.GetCharArray() + text.GetLength()); \ + IM_COL32(0, 0, 0, 100), text.c_str(), text.end_ptr()); \ dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), color, \ (text)); \ position_y += text_size.y + spacing; \ @@ -313,22 +313,22 @@ void ImGuiManager::DrawPerformanceOverlay() const float speed = System::GetEmulationSpeed(); if (g_settings.display_show_fps) { - text.AppendFmtString("G: {:.2f} | V: {:.2f}", System::GetFPS(), System::GetVPS()); + text.append_fmt("G: {:.2f} | V: {:.2f}", System::GetFPS(), System::GetVPS()); first = false; } if (g_settings.display_show_speed) { - text.AppendFmtString("{}{}%", first ? "" : " | ", static_cast(std::round(speed))); + text.append_fmt("{}{}%", first ? "" : " | ", static_cast(std::round(speed))); const float target_speed = System::GetTargetSpeed(); if (target_speed <= 0.0f) - text.AppendString(" (Max)"); + text.append(" (Max)"); else - text.AppendFmtString(" ({:.0f}%)", target_speed * 100.0f); + text.append_fmt(" ({:.0f}%)", target_speed * 100.0f); first = false; } - if (!text.IsEmpty()) + if (!text.empty()) { ImU32 color; if (speed < 95.0f) @@ -347,65 +347,63 @@ void ImGuiManager::DrawPerformanceOverlay() const auto [effective_width, effective_height] = g_gpu->GetEffectiveDisplayResolution(); const bool interlaced = g_gpu->IsInterlacedDisplayEnabled(); const bool pal = g_gpu->IsInPALMode(); - text.Fmt("{}x{} {} {}", effective_width, effective_height, pal ? "PAL" : "NTSC", + text.fmt("{}x{} {} {}", effective_width, effective_height, pal ? "PAL" : "NTSC", interlaced ? "Interlaced" : "Progressive"); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); } if (g_settings.display_show_cpu) { - text.Clear(); - text.AppendFmtString("{:.2f}ms | {:.2f}ms | {:.2f}ms", System::GetMinimumFrameTime(), - System::GetAverageFrameTime(), System::GetMaximumFrameTime()); + text.fmt("{:.2f}ms | {:.2f}ms | {:.2f}ms", System::GetMinimumFrameTime(), System::GetAverageFrameTime(), + System::GetMaximumFrameTime()); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); - text.Clear(); if (g_settings.cpu_overclock_active || (!g_settings.IsUsingRecompiler() || g_settings.cpu_recompiler_icache || g_settings.cpu_recompiler_memory_exceptions)) { first = true; - text.AppendString("CPU["); + text.assign("CPU["); if (g_settings.cpu_overclock_active) { - text.AppendFmtString("{}", g_settings.GetCPUOverclockPercent()); + text.append_fmt("{}", g_settings.GetCPUOverclockPercent()); first = false; } if (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter) { - text.AppendFmtString("{}{}", first ? "" : "/", "I"); + text.append_fmt("{}{}", first ? "" : "/", "I"); first = false; } else if (g_settings.cpu_execution_mode == CPUExecutionMode::CachedInterpreter) { - text.AppendFmtString("{}{}", first ? "" : "/", "CI"); + text.append_fmt("{}{}", first ? "" : "/", "CI"); first = false; } else { if (g_settings.cpu_recompiler_icache) { - text.AppendFmtString("{}{}", first ? "" : "/", "IC"); + text.append_fmt("{}{}", first ? "" : "/", "IC"); first = false; } if (g_settings.cpu_recompiler_memory_exceptions) { - text.AppendFmtString("{}{}", first ? "" : "/", "ME"); + text.append_fmt("{}{}", first ? "" : "/", "ME"); first = false; } } - text.AppendString("]: "); + text.append("]: "); } else { - text.Assign("CPU: "); + text.assign("CPU: "); } FormatProcessorStat(text, System::GetCPUThreadUsage(), System::GetCPUThreadAverageTime()); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); if (g_gpu->GetSWThread()) { - text.Assign("SW: "); + text.assign("SW: "); FormatProcessorStat(text, System::GetSWThreadUsage(), System::GetSWThreadAverageTime()); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); } @@ -414,8 +412,7 @@ void ImGuiManager::DrawPerformanceOverlay() { AudioStream* stream = g_spu.GetOutputStream(); const u32 frames = stream->GetBufferedFramesRelaxed(); - text.Clear(); - text.Fmt("Audio: {:<4u}f/{:<3u}ms", frames, AudioStream::GetMSForBufferSize(stream->GetSampleRate(), frames)); + text.fmt("Audio: {:<4u}f/{:<3u}ms", frames, AudioStream::GetMSForBufferSize(stream->GetSampleRate(), frames)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); } #endif @@ -423,7 +420,7 @@ void ImGuiManager::DrawPerformanceOverlay() if (g_settings.display_show_gpu && g_gpu_device->IsGPUTimingEnabled()) { - text.Assign("GPU: "); + text.assign("GPU: "); FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime()); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); } @@ -433,7 +430,7 @@ void ImGuiManager::DrawPerformanceOverlay() const bool rewinding = System::IsRewinding(); if (rewinding || System::IsFastForwardEnabled() || System::IsTurboEnabled()) { - text.Assign(rewinding ? ICON_FA_FAST_BACKWARD : ICON_FA_FAST_FORWARD); + text.assign(rewinding ? ICON_FA_FAST_BACKWARD : ICON_FA_FAST_FORWARD); DRAW_LINE(standard_font, text, IM_COL32(255, 255, 255, 255)); } } @@ -477,25 +474,21 @@ void ImGuiManager::DrawPerformanceOverlay() ImDrawList* win_dl = ImGui::GetCurrentWindow()->DrawList; const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos); - text.Clear(); - text.AppendFmtString("{:.1f} ms", max); - text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.GetCharArray(), - text.GetCharArray() + text.GetLength()); + text.fmt("{:.1f} ms", max); + text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.end_ptr()); win_dl->AddText(ImVec2(wpos.x + history_size.x - text_size.x - spacing + shadow_offset, wpos.y + shadow_offset), - IM_COL32(0, 0, 0, 100), text.GetCharArray(), text.GetCharArray() + text.GetLength()); + IM_COL32(0, 0, 0, 100), text.c_str(), text.end_ptr()); win_dl->AddText(ImVec2(wpos.x + history_size.x - text_size.x - spacing, wpos.y), IM_COL32(255, 255, 255, 255), - text.GetCharArray(), text.GetCharArray() + text.GetLength()); + text.c_str(), text.end_ptr()); - text.Clear(); - text.AppendFmtString("{:.1f} ms", min); - text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.GetCharArray(), - text.GetCharArray() + text.GetLength()); + text.fmt("{:.1f} ms", min); + text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.end_ptr()); win_dl->AddText(ImVec2(wpos.x + history_size.x - text_size.x - spacing + shadow_offset, wpos.y + history_size.y - fixed_font->FontSize + shadow_offset), - IM_COL32(0, 0, 0, 100), text.GetCharArray(), text.GetCharArray() + text.GetLength()); + IM_COL32(0, 0, 0, 100), text.c_str(), text.end_ptr()); win_dl->AddText( ImVec2(wpos.x + history_size.x - text_size.x - spacing, wpos.y + history_size.y - fixed_font->FontSize), - IM_COL32(255, 255, 255, 255), text.GetCharArray(), text.GetCharArray() + text.GetLength()); + IM_COL32(255, 255, 255, 255), text.c_str(), text.end_ptr()); ImGui::PopFont(); } ImGui::End(); @@ -506,7 +499,7 @@ void ImGuiManager::DrawPerformanceOverlay() else if (g_settings.display_show_status_indicators && state == System::State::Paused && !FullscreenUI::HasActiveWindow()) { - text.Assign(ICON_FA_PAUSE); + text.assign(ICON_FA_PAUSE); DRAW_LINE(standard_font, text, IM_COL32(255, 255, 255, 255)); } @@ -516,58 +509,57 @@ void ImGuiManager::DrawPerformanceOverlay() void ImGuiManager::DrawEnhancementsOverlay() { LargeString text; - text.AppendFmtString("{} {}-{}", Settings::GetConsoleRegionName(System::GetRegion()), - GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()), - g_gpu->IsHardwareRenderer() ? "HW" : "SW"); + text.append_fmt("{} {}-{}", Settings::GetConsoleRegionName(System::GetRegion()), + GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()), + g_gpu->IsHardwareRenderer() ? "HW" : "SW"); if (g_settings.rewind_enable) - text.AppendFormattedString(" RW=%g/%u", g_settings.rewind_save_frequency, g_settings.rewind_save_slots); + text.append_fmt(" RW={}/{}", g_settings.rewind_save_frequency, g_settings.rewind_save_slots); if (g_settings.IsRunaheadEnabled()) - text.AppendFormattedString(" RA=%u", g_settings.runahead_frames); + text.append_fmt(" RA={}", g_settings.runahead_frames); if (g_settings.cpu_overclock_active) - text.AppendFormattedString(" CPU=%u%%", g_settings.GetCPUOverclockPercent()); + text.append_fmt(" CPU={}%", g_settings.GetCPUOverclockPercent()); if (g_settings.enable_8mb_ram) - text.AppendString(" 8MB"); + text.append(" 8MB"); if (g_settings.cdrom_read_speedup != 1) - text.AppendFormattedString(" CDR=%ux", g_settings.cdrom_read_speedup); + text.append_fmt(" CDR={}x", g_settings.cdrom_read_speedup); if (g_settings.cdrom_seek_speedup != 1) - text.AppendFormattedString(" CDS=%ux", g_settings.cdrom_seek_speedup); + text.append_fmt(" CDS={}x", g_settings.cdrom_seek_speedup); if (g_settings.gpu_resolution_scale != 1) - text.AppendFormattedString(" IR=%ux", g_settings.gpu_resolution_scale); + text.append_fmt(" IR={}x", g_settings.gpu_resolution_scale); if (g_settings.gpu_multisamples != 1) { - text.AppendFormattedString(" %ux%s", g_settings.gpu_multisamples, - g_settings.gpu_per_sample_shading ? "SSAA" : "MSAA"); + text.append_fmt(" {}x{}", g_settings.gpu_multisamples, g_settings.gpu_per_sample_shading ? "SSAA" : "MSAA"); } if (g_settings.gpu_true_color) - text.AppendString(" TrueCol"); + text.append(" TrueCol"); if (g_settings.gpu_disable_interlacing) - text.AppendString(" ForceProg"); + text.append(" ForceProg"); if (g_settings.gpu_force_ntsc_timings && System::GetRegion() == ConsoleRegion::PAL) - text.AppendString(" PAL60"); + text.append(" PAL60"); if (g_settings.gpu_texture_filter != GPUTextureFilter::Nearest) - text.AppendFormattedString(" %s", Settings::GetTextureFilterName(g_settings.gpu_texture_filter)); + text.append_fmt(" {}", Settings::GetTextureFilterName(g_settings.gpu_texture_filter)); if (g_settings.gpu_widescreen_hack && g_settings.display_aspect_ratio != DisplayAspectRatio::Auto && g_settings.display_aspect_ratio != DisplayAspectRatio::R4_3) { - text.AppendString(" WSHack"); + text.append(" WSHack"); } if (g_settings.gpu_pgxp_enable) { - text.AppendString(" PGXP"); + text.append(" PGXP"); if (g_settings.gpu_pgxp_culling) - text.AppendString("/Cull"); + text.append("/Cull"); if (g_settings.gpu_pgxp_texture_correction) - text.AppendString("/Tex"); + text.append("/Tex"); if (g_settings.gpu_pgxp_color_correction) - text.AppendString("/Col"); + text.append("/Col"); if (g_settings.gpu_pgxp_vertex_cache) - text.AppendString("/VC"); + text.append("/VC"); if (g_settings.gpu_pgxp_cpu) - text.AppendString("/CPU"); + text.append("/CPU"); if (g_settings.gpu_pgxp_depth_buffer) - text.AppendString("/Depth"); + text.append("/Depth"); } const float scale = ImGuiManager::GetGlobalScale(); @@ -577,13 +569,13 @@ void ImGuiManager::DrawEnhancementsOverlay() const float position_y = ImGui::GetIO().DisplaySize.y - margin - font->FontSize; ImDrawList* dl = ImGui::GetBackgroundDrawList(); - ImVec2 text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits::max(), -1.0f, text, - text.GetCharArray() + text.GetLength(), nullptr); + ImVec2 text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits::max(), -1.0f, text.c_str(), + text.end_ptr(), nullptr); dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x + shadow_offset, position_y + shadow_offset), - IM_COL32(0, 0, 0, 100), text, text.GetCharArray() + text.GetLength()); + IM_COL32(0, 0, 0, 100), text.c_str(), text.end_ptr()); dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), - IM_COL32(255, 255, 255, 255), text, text.GetCharArray() + text.GetLength()); + IM_COL32(255, 255, 255, 255), text.c_str(), text.end_ptr()); } void ImGuiManager::DrawInputsOverlay() @@ -612,7 +604,7 @@ void ImGuiManager::DrawInputsOverlay() const ImVec4 clip_rect(current_x, current_y, display_size.x - margin, display_size.y - margin); - LargeString text; + SmallString text; for (u32 port = 0; port < NUM_CONTROLLER_AND_CARD_PORTS; port++) { @@ -625,7 +617,7 @@ void ImGuiManager::DrawInputsOverlay() if (!cinfo) continue; - text.Fmt("P{} |", port + 1u); + text.fmt("P{} |", port + 1u); for (const Controller::ControllerBindingInfo& bi : cinfo->bindings) { @@ -637,9 +629,9 @@ void ImGuiManager::DrawInputsOverlay() // axes are always shown const float value = controller->GetBindState(bi.bind_index); if (value >= (254.0f / 255.0f)) - text.AppendFmtString(" {}", bi.name); + text.append_fmt(" {}", bi.name); else if (value > (1.0f / 255.0f)) - text.AppendFmtString(" {}: {:.2f}", bi.name, value); + text.append_fmt(" {}: {:.2f}", bi.name, value); } break; @@ -648,7 +640,7 @@ void ImGuiManager::DrawInputsOverlay() // buttons only shown when active const float value = controller->GetBindState(bi.bind_index); if (value >= 0.5f) - text.AppendFmtString(" {}", bi.name); + text.append_fmt(" {}", bi.name); } break; @@ -662,9 +654,9 @@ void ImGuiManager::DrawInputsOverlay() } dl->AddText(font, font->FontSize, ImVec2(current_x + shadow_offset, current_y + shadow_offset), shadow_color, - text.GetCharArray(), text.GetCharArray() + text.GetLength(), 0.0f, &clip_rect); - dl->AddText(font, font->FontSize, ImVec2(current_x, current_y), text_color, text.GetCharArray(), - text.GetCharArray() + text.GetLength(), 0.0f, &clip_rect); + text.c_str(), text.end_ptr(), 0.0f, &clip_rect); + dl->AddText(font, font->FontSize, ImVec2(current_x, current_y), text_color, text.c_str(), text.end_ptr(), 0.0f, + &clip_rect); current_y += font->FontSize + spacing; } diff --git a/src/core/psf_loader.cpp b/src/core/psf_loader.cpp index 93d326ead..675efff40 100644 --- a/src/core/psf_loader.cpp +++ b/src/core/psf_loader.cpp @@ -214,7 +214,7 @@ static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0) u32 lib_counter = 2; for (;;) { - lib_name = file.GetTagString(TinyString::FromFormat("_lib%u", lib_counter++)); + lib_name = file.GetTagString(TinyString::from_fmt("_lib{}", lib_counter++)); if (!lib_name.has_value()) break; diff --git a/src/core/settings.cpp b/src/core/settings.cpp index e493a0acd..0daa204e1 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -101,34 +101,6 @@ bool Settings::HasAnyPerGameMemoryCards() const }); } -std::array Settings::GeneratePortLabels() const -{ - static constexpr std::array, static_cast(MultitapMode::Count)> - multitap_enabled_on_port = {{{false, false}, {true, false}, {false, true}, {true, true}}}; - - std::array labels; - - u32 logical_port = 0; - for (u32 physical_port = 0; physical_port < NUM_MULTITAPS; physical_port++) - { - if (multitap_enabled_on_port[static_cast(multitap_mode)][physical_port]) - { - for (u32 i = 0; i < 4; i++) - { - labels[logical_port] = TinyString::FromFormat("Port %u%c", physical_port + 1u, 'A' + i); - logical_port++; - } - } - else - { - labels[logical_port] = TinyString::FromFormat("Port %u", physical_port + 1u); - logical_port++; - } - } - - return labels; -} - void Settings::CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator) { const u32 percent_gcd = std::gcd(percent, 100); diff --git a/src/core/settings.h b/src/core/settings.h index 95a574a31..6c55a3c85 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -4,7 +4,7 @@ #pragma once #include "common/log.h" #include "common/settings_interface.h" -#include "common/string.h" +#include "common/small_string.h" #include "types.h" #include "util/audio_stream.h" #include @@ -246,8 +246,6 @@ struct Settings std::string pcdrv_root; bool pcdrv_enable_writes = false; - std::array GeneratePortLabels() const; - LOGLEVEL log_level = DEFAULT_LOG_LEVEL; std::string log_filter; bool log_to_console = DEFAULT_LOG_TO_CONSOLE; diff --git a/src/core/system.cpp b/src/core/system.cpp index b786dd2c0..09f2b3c71 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -237,7 +237,7 @@ static bool s_discord_presence_active = false; static TinyString GetTimestampStringForFileName() { - return TinyString::FromFmt("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr))); + return TinyString::from_fmt("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr))); } void System::Internal::ProcessStartup() @@ -3341,25 +3341,21 @@ bool System::CheckForSBIFile(CDImage* image) { return Host::ConfirmMessage( "Confirm Unsupported Configuration", - StringUtil::StdStringFromFormat( - TRANSLATE( - "System", - "You are attempting to run a libcrypt protected game without an SBI file:\n\n%s: %s\n\nThe game will " - "likely not run properly.\n\nPlease check the README for instructions on how to add an SBI file.\n\nDo " - "you wish to continue?"), - s_running_game_serial.c_str(), s_running_game_title.c_str()) - .c_str()); + LargeString::from_fmt( + TRANSLATE_FS("System", "You are attempting to run a libcrypt protected game without an SBI file:\n\n{0}: " + "{1}\n\nThe game will likely not run properly.\n\nPlease check the README for " + "instructions on how to add an SBI file.\n\nDo you wish to continue?"), + s_running_game_serial, s_running_game_title)); } else { Host::ReportErrorAsync( TRANSLATE("System", "Error"), - SmallString::FromFormat( - TRANSLATE("System", - "You are attempting to run a libcrypt protected game without an SBI file:\n\n%s: %s\n\nYour dump is " - "incomplete, you must add the SBI file to run this game. \n\n" - "The name of the SBI file must match the name of the disc image."), - s_running_game_serial.c_str(), s_running_game_title.c_str())); + LargeString::from_fmt( + TRANSLATE_FS("System", "You are attempting to run a libcrypt protected game without an SBI file:\n\n{0}: " + "{1}\n\nYour dump is incomplete, you must add the SBI file to run this game. \n\nThe " + "name of the SBI file must match the name of the disc image."), + s_running_game_serial, s_running_game_title)); return false; } } diff --git a/src/duckstation-qt/autoupdaterdialog.cpp b/src/duckstation-qt/autoupdaterdialog.cpp index b9a7a195a..3d5e96356 100644 --- a/src/duckstation-qt/autoupdaterdialog.cpp +++ b/src/duckstation-qt/autoupdaterdialog.cpp @@ -147,7 +147,7 @@ void AutoUpdaterDialog::queueGetLatestRelease() connect(m_network_access_mgr, &QNetworkAccessManager::finished, this, &AutoUpdaterDialog::getLatestReleaseComplete); SmallString url_string; - url_string.Format(LATEST_RELEASE_URL, getCurrentUpdateTag().c_str()); + url_string.format(LATEST_RELEASE_URL, getCurrentUpdateTag().c_str()); QUrl url(QUrl::fromEncoded(QByteArray(url_string))); QNetworkRequest request(url); diff --git a/src/duckstation-qt/controllerbindingwidgets.cpp b/src/duckstation-qt/controllerbindingwidgets.cpp index 365342483..a325c7503 100644 --- a/src/duckstation-qt/controllerbindingwidgets.cpp +++ b/src/duckstation-qt/controllerbindingwidgets.cpp @@ -402,11 +402,11 @@ QString ControllerMacroEditWidget::getSummary() const SmallString str; for (const Controller::ControllerBindingInfo* bi : m_binds) { - if (!str.IsEmpty()) - str.AppendCharacter('/'); - str.AppendString(bi->name); + if (!str.empty()) + str.append('/'); + str.append(bi->name); } - return str.IsEmpty() ? tr("Not Configured") : QString::fromUtf8(str.GetCharArray(), str.GetLength()); + return str.empty() ? tr("Not Configured") : QString::fromUtf8(str.c_str(), static_cast(str.length())); } void ControllerMacroEditWidget::onSetFrequencyClicked() diff --git a/src/duckstation-qt/debuggermodels.cpp b/src/duckstation-qt/debuggermodels.cpp index 56038b179..592508fbe 100644 --- a/src/duckstation-qt/debuggermodels.cpp +++ b/src/duckstation-qt/debuggermodels.cpp @@ -2,9 +2,13 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "debuggermodels.h" + #include "core/cpu_core.h" #include "core/cpu_core_private.h" #include "core/cpu_disasm.h" + +#include "common/small_string.h" + #include #include #include @@ -21,7 +25,9 @@ DebuggerCodeModel::DebuggerCodeModel(QObject* parent /*= nullptr*/) : QAbstractT m_breakpoint_pixmap = QIcon(QStringLiteral(":/icons/media-record.png")).pixmap(QSize(12, 12)); } -DebuggerCodeModel::~DebuggerCodeModel() {} +DebuggerCodeModel::~DebuggerCodeModel() +{ +} int DebuggerCodeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { @@ -92,7 +98,7 @@ QVariant DebuggerCodeModel::data(const QModelIndex& index, int role /*= Qt::Disp SmallString str; CPU::DisassembleInstruction(&str, address, instruction_bits); - return QString::fromUtf8(str.GetCharArray(), static_cast(str.GetLength())); + return QString::fromUtf8(str.c_str(), static_cast(str.length())); } case 4: @@ -107,7 +113,7 @@ QVariant DebuggerCodeModel::data(const QModelIndex& index, int role /*= Qt::Disp TinyString str; CPU::DisassembleInstructionComment(&str, address, instruction_bits, &CPU::g_state.regs); - return QString::fromUtf8(str.GetCharArray(), static_cast(str.GetLength())); + return QString::fromUtf8(str.c_str(), static_cast(str.length())); } default: @@ -287,9 +293,13 @@ void DebuggerCodeModel::setBreakpointState(VirtualMemoryAddress address, bool en } } -DebuggerRegistersModel::DebuggerRegistersModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) {} +DebuggerRegistersModel::DebuggerRegistersModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) +{ +} -DebuggerRegistersModel::~DebuggerRegistersModel() {} +DebuggerRegistersModel::~DebuggerRegistersModel() +{ +} int DebuggerRegistersModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { @@ -314,8 +324,8 @@ QVariant DebuggerRegistersModel::data(const QModelIndex& index, int role /*= Qt: { case 0: // address { - if (role == Qt::DisplayRole) - return QString::fromUtf8(CPU::g_debugger_register_list[reg_index].name); + if (role == Qt::DisplayRole) + return QString::fromUtf8(CPU::g_debugger_register_list[reg_index].name); } break; @@ -372,9 +382,13 @@ void DebuggerRegistersModel::saveCurrentValues() m_old_reg_values[i] = CPU::g_state.regs.r[i]; } -DebuggerStackModel::DebuggerStackModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) {} +DebuggerStackModel::DebuggerStackModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) +{ +} -DebuggerStackModel::~DebuggerStackModel() {} +DebuggerStackModel::~DebuggerStackModel() +{ +} int DebuggerStackModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const { diff --git a/src/duckstation-qt/gamelistwidget.cpp b/src/duckstation-qt/gamelistwidget.cpp index fc1613cd8..c21e983e1 100644 --- a/src/duckstation-qt/gamelistwidget.cpp +++ b/src/duckstation-qt/gamelistwidget.cpp @@ -481,7 +481,7 @@ void GameListWidget::resizeTableViewColumnsToFit() static TinyString getColumnVisibilitySettingsKeyName(int column) { - return TinyString::FromFormat("Show%s", GameListModel::getColumnName(static_cast(column))); + return TinyString::from_fmt("Show{}", GameListModel::getColumnName(static_cast(column))); } void GameListWidget::loadTableViewColumnVisibilitySettings() diff --git a/src/duckstation-qt/memorycardsettingswidget.cpp b/src/duckstation-qt/memorycardsettingswidget.cpp index aaada2533..bddd675e3 100644 --- a/src/duckstation-qt/memorycardsettingswidget.cpp +++ b/src/duckstation-qt/memorycardsettingswidget.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "memorycardsettingswidget.h" -#include "common/string_util.h" + #include "core/controller.h" #include "core/settings.h" #include "inputbindingwidgets.h" @@ -11,6 +11,10 @@ #include "qtutils.h" #include "settingsdialog.h" #include "settingwidgetbinder.h" + +#include "common/small_string.h" +#include "common/string_util.h" + #include #include #include @@ -168,7 +172,7 @@ void MemoryCardSettingsWidget::onBrowseMemoryCardPathClicked(int index) void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index) { - const auto key = TinyString::FromFormat("Card%dPath", index + 1); + const auto key = TinyString::from_fmt("Card{}Path", index + 1); std::string relative_path( Path::MakeRelative(m_port_ui[index].memory_card_path->text().toStdString(), EmuFolders::MemoryCards)); m_dialog->setStringSettingValue("MemoryCards", key, relative_path.c_str()); @@ -176,7 +180,7 @@ void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index) void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index) { - const auto key = TinyString::FromFormat("Card%dPath", index + 1); + const auto key = TinyString::from_fmt("Card{}Path", index + 1); if (m_dialog->isPerGameSettings()) m_dialog->removeSettingValue("MemoryCards", key); else @@ -187,7 +191,7 @@ void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index) void MemoryCardSettingsWidget::updateMemoryCardPath(int index) { - const auto key = TinyString::FromFormat("Card%dPath", index + 1); + const auto key = TinyString::from_fmt("Card{}Path", index + 1); std::string path( m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str())); if (!Path::IsAbsolute(path)) diff --git a/src/duckstation-qt/memorycardsettingswidget.h b/src/duckstation-qt/memorycardsettingswidget.h index 3fe6daa25..c03223c58 100644 --- a/src/duckstation-qt/memorycardsettingswidget.h +++ b/src/duckstation-qt/memorycardsettingswidget.h @@ -3,6 +3,7 @@ #pragma once #include "core/types.h" + #include #include #include diff --git a/src/updater/win32_progress_callback.cpp b/src/updater/win32_progress_callback.cpp index cd61d22d7..5943462c5 100644 --- a/src/updater/win32_progress_callback.cpp +++ b/src/updater/win32_progress_callback.cpp @@ -128,7 +128,7 @@ void Win32ProgressCallback::Redraw(bool force) SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range)); SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast(m_progress_value), 0); - SetWindowTextA(m_text_hwnd, m_status_text); + SetWindowTextA(m_text_hwnd, m_status_text.c_str()); RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE); PumpMessages(); } diff --git a/src/util/cd_image_pbp.cpp b/src/util/cd_image_pbp.cpp index 7aa4c7837..4dcfe5e49 100644 --- a/src/util/cd_image_pbp.cpp +++ b/src/util/cd_image_pbp.cpp @@ -666,7 +666,7 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error) if (m_disc_offsets.size() > 1) { std::string sbi_path(Path::StripExtension(m_filename)); - sbi_path += TinyString::FromFormat("_%u.sbi", index + 1); + sbi_path += TinyString::from_fmt("_%u.sbi", index + 1).view(); m_sbi.LoadSBI(sbi_path.c_str()); } else diff --git a/src/util/cue_parser.cpp b/src/util/cue_parser.cpp index 39a0be6b6..945068814 100644 --- a/src/util/cue_parser.cpp +++ b/src/util/cue_parser.cpp @@ -71,10 +71,10 @@ void File::SetError(u32 line_number, Error* error, const char* format, ...) std::va_list ap; SmallString str; va_start(ap, format); - str.FormatVA(format, ap); + str.format_va(format, ap); va_end(ap); - Log_ErrorPrintf("Cue parse error at line %u: %s", line_number, str.GetCharArray()); + Log_ErrorPrintf("Cue parse error at line %u: %s", line_number, str.c_str()); Error::SetString(error, fmt::format("Cue parse error at line {}: {}", line_number, str)); } diff --git a/src/util/d3d12_device.cpp b/src/util/d3d12_device.cpp index 24c3203ad..b940161f5 100644 --- a/src/util/d3d12_device.cpp +++ b/src/util/d3d12_device.cpp @@ -17,7 +17,7 @@ #include "common/log.h" #include "common/path.h" #include "common/scoped_guard.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "D3D12MemAlloc.h" diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index ecb2ef401..38e64451a 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -265,7 +265,7 @@ void GPUDevice::OpenShaderCache(const std::string_view& base_path, u32 version) if (m_features.pipeline_cache) { const std::string pc_filename = - Path::Combine(base_path, TinyString::FromFmt("{}.bin", GetShaderCacheBaseName("pipelines"))); + Path::Combine(base_path, TinyString::from_fmt("{}.bin", GetShaderCacheBaseName("pipelines"))); if (FileSystem::FileExists(pc_filename.c_str())) { Log_InfoPrintf("Removing old pipeline cache '%s'", pc_filename.c_str()); @@ -284,7 +284,7 @@ void GPUDevice::OpenShaderCache(const std::string_view& base_path, u32 version) if (m_features.pipeline_cache && !base_path.empty()) { const std::string basename = GetShaderCacheBaseName("pipelines"); - const std::string filename = Path::Combine(base_path, TinyString::FromFmt("{}.bin", basename)); + const std::string filename = Path::Combine(base_path, TinyString::from_fmt("{}.bin", basename)); if (ReadPipelineCache(filename)) s_pipeline_cache_path = std::move(filename); else diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index 9cb460472..f0e57fcac 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -2375,12 +2375,12 @@ void ImGuiFullscreen::DrawBackgroundProgressDialogs(ImVec2& position, float spac dl->AddRectFilled(pos, ImVec2(pos.x + fraction * (box_end.x - pos.x), box_end.y), ImGui::GetColorU32(UISecondaryColor)); - const auto text = TinyString::FromFmt("{}%", static_cast(std::round(fraction * 100.0f))); + const auto text = TinyString::from_fmt("{}%", static_cast(std::round(fraction * 100.0f))); const ImVec2 text_size(ImGui::CalcTextSize(text)); const ImVec2 text_pos(pos.x + ((box_end.x - pos.x) / 2.0f) - (text_size.x / 2.0f), pos.y + ((box_end.y - pos.y) / 2.0f) - (text_size.y / 2.0f)); dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, ImGui::GetColorU32(UIPrimaryTextColor), - text.GetCharArray(), text.GetCharArray() + text.GetLength()); + text.c_str(), text.end_ptr()); } else { diff --git a/src/util/input_manager.cpp b/src/util/input_manager.cpp index b125e8ed7..4a22b42fc 100644 --- a/src/util/input_manager.cpp +++ b/src/util/input_manager.cpp @@ -1714,9 +1714,9 @@ bool InputManager::MigrateBindings(SettingsInterface& si) if (bnum >= std::size(button_mapping)) continue; - new_bind.Fmt("SDL-{}/{}", cnum, button_mapping[bnum]); + new_bind.fmt("SDL-{}/{}", cnum, button_mapping[bnum]); si.SetStringValue(new_section.c_str(), new_key, new_bind); - Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); + Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str()); num_changes++; } else if (std::sscanf(old_bind.c_str(), "Controller%u/%cAxis%u", &cnum, &dir, &bnum) == 3) @@ -1724,16 +1724,16 @@ bool InputManager::MigrateBindings(SettingsInterface& si) if (bnum >= std::size(axis_mapping)) continue; - new_bind.Fmt("SDL-{}/{}{}", cnum, dir, axis_mapping[bnum]); + new_bind.fmt("SDL-{}/{}{}", cnum, dir, axis_mapping[bnum]); si.SetStringValue(new_section.c_str(), new_key, new_bind); - Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); + Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str()); num_changes++; } else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/Keypad+")) { - new_bind.Fmt("Keyboard/Numpad{}", old_bind.substr(16)); + new_bind.fmt("Keyboard/Numpad{}", old_bind.substr(16)); si.SetStringValue(new_section.c_str(), new_key, new_bind); - Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); + Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str()); num_changes++; } else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/")) @@ -1764,12 +1764,12 @@ bool InputManager::MigrateBindings(SettingsInterface& si) if (bnum >= std::size(axis_mapping)) continue; - new_bind.Fmt("SDL-{}/-{}", cnum, axis_mapping[bnum]); + new_bind.fmt("SDL-{}/-{}", cnum, axis_mapping[bnum]); si.SetStringValue(new_section.c_str(), new_neg_key, new_bind); - new_bind.Fmt("SDL-{}/+{}", cnum, axis_mapping[bnum]); + new_bind.fmt("SDL-{}/+{}", cnum, axis_mapping[bnum]); si.SetStringValue(new_section.c_str(), new_pos_key, new_bind); - Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); + Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str()); num_changes++; } } @@ -1780,9 +1780,9 @@ bool InputManager::MigrateBindings(SettingsInterface& si) unsigned cnum; if (std::sscanf(rumble_source.c_str(), "Controller%u", &cnum) == 1) { - new_bind.Fmt("SDL-{}/LargeMotor", cnum); + new_bind.fmt("SDL-{}/LargeMotor", cnum); si.SetStringValue(new_section.c_str(), "LargeMotor", new_bind); - new_bind.Fmt("SDL-{}/SmallMotor", cnum); + new_bind.fmt("SDL-{}/SmallMotor", cnum); si.SetStringValue(new_section.c_str(), "SmallMotor", new_bind); num_changes++; } diff --git a/src/util/opengl_pipeline.cpp b/src/util/opengl_pipeline.cpp index 7734fa5cb..040a1ea2e 100644 --- a/src/util/opengl_pipeline.cpp +++ b/src/util/opengl_pipeline.cpp @@ -12,7 +12,7 @@ #include "common/log.h" #include "common/path.h" #include "common/scoped_guard.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "fmt/format.h" @@ -358,7 +358,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig) { glBindAttribLocation( program_id, i, - TinyString::FromFmt("{}{}", semantic_vars[static_cast(va.semantic.GetValue())], va.semantic_index)); + TinyString::from_fmt("{}{}", semantic_vars[static_cast(va.semantic.GetValue())], va.semantic_index)); } } @@ -418,7 +418,7 @@ void OpenGLDevice::PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig, const u32 num_textures = std::max(GetActiveTexturesForLayout(plconfig.layout), 1); for (u32 i = 0; i < num_textures; i++) { - location = glGetUniformLocation(program_id, TinyString::FromFmt("samp{}", i)); + location = glGetUniformLocation(program_id, TinyString::from_fmt("samp{}", i)); if (location >= 0) glUniform1i(location, i); } diff --git a/src/util/pch.h b/src/util/pch.h index 4d1f0bb5f..022c1bc10 100644 --- a/src/util/pch.h +++ b/src/util/pch.h @@ -5,6 +5,7 @@ #include "common/types.h" +#include "fmt/core.h" #include "fmt/format.h" #include diff --git a/src/util/platform_misc_mac.mm b/src/util/platform_misc_mac.mm index d1cf6ba68..e83fc5992 100644 --- a/src/util/platform_misc_mac.mm +++ b/src/util/platform_misc_mac.mm @@ -6,7 +6,7 @@ #include "cocoa_tools.h" #include "common/log.h" -#include "common/string.h" +#include "common/small_string.h" #include #include diff --git a/src/util/platform_misc_unix.cpp b/src/util/platform_misc_unix.cpp index d43ed6019..ccd103d87 100644 --- a/src/util/platform_misc_unix.cpp +++ b/src/util/platform_misc_unix.cpp @@ -6,7 +6,7 @@ #include "common/log.h" #include "common/scoped_guard.h" -#include "common/string.h" +#include "common/small_string.h" #include #include diff --git a/src/util/platform_misc_win32.cpp b/src/util/platform_misc_win32.cpp index 495d34107..145b284f6 100644 --- a/src/util/platform_misc_win32.cpp +++ b/src/util/platform_misc_win32.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "common/log.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "platform_misc.h" #include diff --git a/src/util/postprocessing.cpp b/src/util/postprocessing.cpp index 637644732..fd4a002aa 100644 --- a/src/util/postprocessing.cpp +++ b/src/util/postprocessing.cpp @@ -19,7 +19,7 @@ #include "common/file_system.h" #include "common/log.h" #include "common/path.h" -#include "common/string.h" +#include "common/small_string.h" #include "common/string_util.h" #include "common/timer.h" #include "fmt/format.h" @@ -120,20 +120,20 @@ TinyString PostProcessing::ValueToString(ShaderOption::Type type, u32 vector_siz for (u32 i = 0; i < vector_size; i++) { if (i > 0) - ret.AppendCharacter(','); + ret.append(','); switch (type) { case ShaderOption::Type::Bool: - ret.AppendString((value[i].int_value != 0) ? "true" : "false"); + ret.append((value[i].int_value != 0) ? "true" : "false"); break; case ShaderOption::Type::Int: - ret.AppendFmtString("{}", value[i].int_value); + ret.append_fmt("{}", value[i].int_value); break; case ShaderOption::Type::Float: - ret.AppendFmtString("{}", value[i].float_value); + ret.append_fmt("{}", value[i].float_value); break; default: @@ -207,7 +207,7 @@ std::vector> PostProcessing::GetAvailableSha TinyString PostProcessing::GetStageConfigSection(u32 index) { - return TinyString::FromFmt("PostProcessing/Stage{}", index + 1); + return TinyString::from_fmt("PostProcessing/Stage{}", index + 1); } void PostProcessing::CopyStageConfig(SettingsInterface& si, u32 old_index, u32 new_index) diff --git a/src/util/state_wrapper.cpp b/src/util/state_wrapper.cpp index 9e4ec032c..819565f4d 100644 --- a/src/util/state_wrapper.cpp +++ b/src/util/state_wrapper.cpp @@ -3,7 +3,7 @@ #include "state_wrapper.h" #include "common/log.h" -#include "common/string.h" +#include "common/small_string.h" #include #include Log_SetChannel(StateWrapper); @@ -67,14 +67,14 @@ void StateWrapper::Do(std::string* value_ptr) value_ptr->resize(std::strlen(&(*value_ptr)[0])); } -void StateWrapper::Do(String* value_ptr) +void StateWrapper::Do(SmallStringBase* value_ptr) { - u32 length = static_cast(value_ptr->GetLength()); + u32 length = static_cast(value_ptr->length()); Do(&length); if (m_mode == Mode::Read) - value_ptr->Resize(length); - DoBytes(value_ptr->GetWriteableCharArray(), length); - value_ptr->UpdateSize(); + value_ptr->resize(length); + DoBytes(value_ptr->data(), length); + value_ptr->update_size(); } bool StateWrapper::DoMarker(const char* marker) @@ -84,11 +84,11 @@ bool StateWrapper::DoMarker(const char* marker) if (m_error) return false; - if (m_mode == Mode::Write || file_value.Compare(marker)) + if (m_mode == Mode::Write || file_value.equals(marker)) return true; Log_ErrorPrintf("Marker mismatch at offset %" PRIu64 ": found '%s' expected '%s'", m_stream->GetPosition(), - file_value.GetCharArray(), marker); + file_value.c_str(), marker); return false; } diff --git a/src/util/state_wrapper.h b/src/util/state_wrapper.h index ed4d2ef52..13d919138 100644 --- a/src/util/state_wrapper.h +++ b/src/util/state_wrapper.h @@ -12,7 +12,7 @@ #include #include -class String; +class SmallStringBase; class StateWrapper { @@ -108,7 +108,7 @@ public: void Do(bool* value_ptr); void Do(std::string* value_ptr); - void Do(String* value_ptr); + void Do(SmallStringBase* value_ptr); template void Do(std::array* data) diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 93db7d479..f1b598cf8 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -17,7 +17,7 @@ #include "common/log.h" #include "common/path.h" #include "common/scoped_guard.h" -#include "common/string.h" +#include "common/small_string.h" #include "fmt/format.h" @@ -662,7 +662,7 @@ bool VulkanDevice::CreateCommandBuffers() LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: "); return false; } - Vulkan::SetObjectName(m_device, resources.command_pool, TinyString::FromFmt("Frame Command Pool {}", frame_index)); + Vulkan::SetObjectName(m_device, resources.command_pool, TinyString::from_fmt("Frame Command Pool {}", frame_index)); VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, @@ -677,7 +677,7 @@ bool VulkanDevice::CreateCommandBuffers() for (u32 i = 0; i < resources.command_buffers.size(); i++) { Vulkan::SetObjectName(m_device, resources.command_buffers[i], - TinyString::FromFmt("Frame {} {}Command Buffer", frame_index, (i == 0) ? "Init" : "")); + TinyString::from_fmt("Frame {} {}Command Buffer", frame_index, (i == 0) ? "Init" : "")); } VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT}; @@ -688,7 +688,7 @@ bool VulkanDevice::CreateCommandBuffers() LOG_VULKAN_ERROR(res, "vkCreateFence failed: "); return false; } - Vulkan::SetObjectName(m_device, resources.fence, TinyString::FromFmt("Frame Fence {}", frame_index)); + Vulkan::SetObjectName(m_device, resources.fence, TinyString::from_fmt("Frame Fence {}", frame_index)); if (!m_optional_extensions.vk_khr_push_descriptor) { @@ -707,7 +707,7 @@ bool VulkanDevice::CreateCommandBuffers() return false; } Vulkan::SetObjectName(m_device, resources.descriptor_pool, - TinyString::FromFmt("Frame Descriptor Pool {}", frame_index)); + TinyString::from_fmt("Frame Descriptor Pool {}", frame_index)); } ++frame_index;