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