Common: Drop String, add SmallString

This commit is contained in:
Stenzek 2023-09-20 23:49:14 +10:00
parent 3c68543491
commit ac0601f408
55 changed files with 1500 additions and 2062 deletions

View file

@ -46,8 +46,8 @@ add_library(common
settings_interface.h settings_interface.h
sha1_digest.cpp sha1_digest.cpp
sha1_digest.h sha1_digest.h
string.cpp small_string.cpp
string.h small_string.h
string_util.cpp string_util.cpp
string_util.h string_util.h
thirdparty/thread_pool.cpp thirdparty/thread_pool.cpp

View file

@ -34,7 +34,7 @@
<ClInclude Include="scoped_guard.h" /> <ClInclude Include="scoped_guard.h" />
<ClInclude Include="settings_interface.h" /> <ClInclude Include="settings_interface.h" />
<ClInclude Include="sha1_digest.h" /> <ClInclude Include="sha1_digest.h" />
<ClInclude Include="string.h" /> <ClInclude Include="small_string.h" />
<ClInclude Include="heterogeneous_containers.h" /> <ClInclude Include="heterogeneous_containers.h" />
<ClInclude Include="string_util.h" /> <ClInclude Include="string_util.h" />
<ClInclude Include="thirdparty\StackWalker.h" /> <ClInclude Include="thirdparty\StackWalker.h" />
@ -62,7 +62,7 @@
<ClCompile Include="minizip_helpers.cpp" /> <ClCompile Include="minizip_helpers.cpp" />
<ClCompile Include="progress_callback.cpp" /> <ClCompile Include="progress_callback.cpp" />
<ClCompile Include="sha1_digest.cpp" /> <ClCompile Include="sha1_digest.cpp" />
<ClCompile Include="string.cpp" /> <ClCompile Include="small_string.cpp" />
<ClCompile Include="string_util.cpp" /> <ClCompile Include="string_util.cpp" />
<ClCompile Include="thirdparty\StackWalker.cpp" /> <ClCompile Include="thirdparty\StackWalker.cpp" />
<ClCompile Include="threading.cpp" /> <ClCompile Include="threading.cpp" />

View file

@ -7,7 +7,7 @@
<ClInclude Include="heap_array.h" /> <ClInclude Include="heap_array.h" />
<ClInclude Include="rectangle.h" /> <ClInclude Include="rectangle.h" />
<ClInclude Include="log.h" /> <ClInclude Include="log.h" />
<ClInclude Include="string.h" /> <ClInclude Include="small_string.h" />
<ClInclude Include="byte_stream.h" /> <ClInclude Include="byte_stream.h" />
<ClInclude Include="timer.h" /> <ClInclude Include="timer.h" />
<ClInclude Include="assert.h" /> <ClInclude Include="assert.h" />
@ -46,7 +46,7 @@
<ClInclude Include="memmap.h" /> <ClInclude Include="memmap.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="string.cpp" /> <ClCompile Include="small_string.cpp" />
<ClCompile Include="byte_stream.cpp" /> <ClCompile Include="byte_stream.cpp" />
<ClCompile Include="log.cpp" /> <ClCompile Include="log.cpp" />
<ClCompile Include="timer.cpp" /> <ClCompile Include="timer.cpp" />

View file

@ -4,7 +4,7 @@
#include "log.h" #include "log.h"
#include "assert.h" #include "assert.h"
#include "file_system.h" #include "file_system.h"
#include "string.h" #include "small_string.h"
#include "timer.h" #include "timer.h"
#include <cstdio> #include <cstdio>
#include <mutex> #include <mutex>
@ -36,7 +36,7 @@ static LOGLEVEL s_filter_level = LOGLEVEL_TRACE;
static Common::Timer::Value s_startTimeStamp = Common::Timer::GetCurrentValue(); static Common::Timer::Value s_startTimeStamp = Common::Timer::GetCurrentValue();
static bool s_console_output_enabled = false; 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; static LOGLEVEL s_console_output_level_filter = LOGLEVEL_TRACE;
#ifdef _WIN32 #ifdef _WIN32
@ -46,12 +46,12 @@ static HANDLE s_hConsoleStdErr = NULL;
#endif #endif
static bool s_debug_output_enabled = false; 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 LOGLEVEL s_debug_output_level_filter = LOGLEVEL_TRACE;
static bool s_file_output_enabled = false; static bool s_file_output_enabled = false;
static bool s_file_output_timestamp = 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; static LOGLEVEL s_file_output_level_filter = LOGLEVEL_TRACE;
std::unique_ptr<std::FILE, void (*)(std::FILE*)> s_fileOutputHandle(nullptr, [](std::FILE* fp) { std::unique_ptr<std::FILE, void (*)(std::FILE*)> s_fileOutputHandle(nullptr, [](std::FILE* fp) {
if (fp) if (fp)
@ -242,7 +242,7 @@ static void ConsoleOutputLogCallback(void* pUserParam, const char* channelName,
LOGLEVEL level, const char* message) LOGLEVEL level, const char* message)
{ {
if (!s_console_output_enabled || level > s_console_output_level_filter || 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; return;
} }
@ -267,7 +267,7 @@ static void DebugOutputLogCallback(void* pUserParam, const char* channelName, co
const char* message) const char* message)
{ {
if (!s_debug_output_enabled || level > s_debug_output_level_filter || 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; 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, static void FileOutputLogCallback(void* pUserParam, const char* channelName, const char* functionName, LOGLEVEL level,
const char* message) 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; return;
FormatLogMessageAndPrint( FormatLogMessageAndPrint(

View file

@ -18,7 +18,7 @@ void ProgressCallback::SetFormattedStatusText(const char* Format, ...)
va_list ap; va_list ap;
va_start(ap, Format); va_start(ap, Format);
str.FormatVA(Format, ap); str.format_va(Format, ap);
va_end(ap); va_end(ap);
SetStatusText(str); SetStatusText(str);
@ -30,7 +30,7 @@ void ProgressCallback::DisplayFormattedError(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
DisplayError(str); DisplayError(str);
@ -42,7 +42,7 @@ void ProgressCallback::DisplayFormattedWarning(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
DisplayWarning(str); DisplayWarning(str);
@ -54,7 +54,7 @@ void ProgressCallback::DisplayFormattedInformation(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
DisplayInformation(str); DisplayInformation(str);
@ -66,7 +66,7 @@ void ProgressCallback::DisplayFormattedDebugMessage(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
DisplayDebugMessage(str); DisplayDebugMessage(str);
@ -78,7 +78,7 @@ void ProgressCallback::DisplayFormattedModalError(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
ModalError(str); ModalError(str);
@ -90,7 +90,7 @@ bool ProgressCallback::DisplayFormattedModalConfirmation(const char* format, ...
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
return ModalConfirmation(str); return ModalConfirmation(str);
@ -102,7 +102,7 @@ void ProgressCallback::DisplayFormattedModalInformation(const char* format, ...)
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
ModalInformation(str); ModalInformation(str);
@ -312,10 +312,10 @@ void ConsoleProgressCallback::Clear()
{ {
SmallString message; SmallString message;
for (u32 i = 0; i < COLUMNS; i++) for (u32 i = 0; i < COLUMNS; i++)
message.AppendCharacter(' '); 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); std::fflush(stderr);
} }
@ -325,7 +325,7 @@ void ConsoleProgressCallback::Redraw(bool update_value_only)
if (percent_complete > 100.0f) if (percent_complete > 100.0f)
percent_complete = 100.0f; percent_complete = 100.0f;
const u32 current_length = m_status_text.GetLength() + 14; const u32 current_length = static_cast<u32>(m_status_text.length()) + 14;
const u32 max_bar_length = (current_length < COLUMNS) ? COLUMNS - current_length : 0; const u32 max_bar_length = (current_length < COLUMNS) ? COLUMNS - current_length : 0;
const u32 current_bar_length = const u32 current_bar_length =
(max_bar_length > 0) ? (static_cast<u32>(percent_complete / 100.0f * (float)max_bar_length)) : 0; (max_bar_length > 0) ? (static_cast<u32>(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; m_last_percent_complete = percent_complete;
SmallString message; SmallString message;
message.AppendString(m_status_text); message.append(m_status_text);
message.AppendFormattedString(" [%.2f%%]", percent_complete); message.append_fmt(" [{:.2f}%]", percent_complete);
if (max_bar_length > 0) if (max_bar_length > 0)
{ {
message.AppendString(" |"); message.append(" |");
u32 i; u32 i;
for (i = 0; i < current_bar_length; i++) for (i = 0; i < current_bar_length; i++)
message.AppendCharacter('='); message.append('=');
for (; i < max_bar_length; i++) 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); std::fflush(stderr);
} }

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
#include "string.h" #include "small_string.h"
#include "types.h" #include "types.h"
class ByteStream; class ByteStream;
@ -73,7 +73,7 @@ protected:
struct State struct State
{ {
State* next_saved_state; State* next_saved_state;
String status_text; std::string status_text;
u32 progress_range; u32 progress_range;
u32 progress_value; u32 progress_value;
u32 base_progress_value; u32 base_progress_value;
@ -82,7 +82,7 @@ protected:
bool m_cancellable; bool m_cancellable;
bool m_cancelled; bool m_cancelled;
String m_status_text; std::string m_status_text;
u32 m_progress_range; u32 m_progress_range;
u32 m_progress_value; u32 m_progress_value;

699
src/common/small_string.cpp Normal file
View file

@ -0,0 +1,699 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "small_string.h"
#include "assert.h"
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#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<char*>(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<char*>(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<char*>(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<u32>(std::strlen(str)));
}
void SmallStringBase::append(const std::string& str)
{
append(str.c_str(), static_cast<u32>(str.length()));
}
void SmallStringBase::append(const std::string_view& str)
{
append(str.data(), static_cast<u32>(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<u32>(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<char*>(std::realloc(heap_buffer, buffer_size));
continue;
}
written = static_cast<u32>(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<u32>(std::strlen(str)));
}
void SmallStringBase::prepend(const std::string& str)
{
prepend(str.c_str(), static_cast<u32>(str.length()));
}
void SmallStringBase::prepend(const std::string_view& str)
{
prepend(str.data(), static_cast<u32>(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<u32>(std::size(stack_buffer));
u32 written;
for (;;)
{
int ret = std::vsnprintf(buffer, buffer_size, format, ArgPtr);
if (ret < 0 || (static_cast<u32>(ret) >= (buffer_size - 1)))
{
buffer_size *= 2;
buffer = heap_buffer = reinterpret_cast<char*>(std::realloc(heap_buffer, buffer_size));
continue;
}
written = static_cast<u32>(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<u32>(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<u32>(std::max<s32>(0, static_cast<s32>(m_length) + offset));
else
real_offset = std::min(static_cast<u32>(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<u32>(str.size()));
}
void SmallStringBase::insert(s32 offset, const std::string_view& str)
{
insert(offset, str.data(), static_cast<u32>(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<u32>(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<u32>(str.size()));
}
void SmallStringBase::assign(const std::string_view& str)
{
clear();
append(str.data(), static_cast<u32>(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<u32>(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<u32>(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<u32>(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<u32>(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<u32>(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<u32>(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<s32>(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<s32>(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<s32>(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<u32>(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<u32>(std::max<s32>(0, static_cast<s32>(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<u32>(std::max<s32>(0, static_cast<s32>(m_length) + count)));
}
else
{
real_count = std::min(m_length - real_offset, static_cast<u32>(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<u32>(std::max<s32>(0, static_cast<s32>(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<u32>(std::max<s32>(0, static_cast<s32>(m_length) + count)));
}
else
{
real_count = std::min(m_length - real_offset, static_cast<u32>(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
}
}

343
src/common/small_string.h Normal file
View file

@ -0,0 +1,343 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "types.h"
#include "fmt/core.h"
#include <algorithm>
#include <cstdarg>
#include <cstring>
#include <limits>
#include <string>
#include <string_view>
//
// 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<typename... T>
void append_fmt(fmt::format_string<T...> 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<typename... T>
void prepend_fmt(fmt::format_string<T...> 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<typename... T>
void fmt(fmt::format_string<T...> 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<s32>::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<u32 L>
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<typename... T>
static SmallStackString from_fmt(fmt::format_string<T...> 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<u32 L>
ALWAYS_INLINE SmallStackString<L> SmallStackString<L>::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<u32 L>
template<typename... T>
ALWAYS_INLINE SmallStackString<L> SmallStackString<L>::from_fmt(fmt::format_string<T...> fmt, T&&... args)
{
SmallStackString<L> 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<typename... T>
ALWAYS_INLINE void SmallStringBase::append_fmt(fmt::format_string<T...> fmt, T&&... args)
{
fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...));
}
template<typename... T>
ALWAYS_INLINE void SmallStringBase::prepend_fmt(fmt::format_string<T...> fmt, T&&... args)
{
TinyString str;
fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...));
prepend(str);
}
template<typename... T>
ALWAYS_INLINE void SmallStringBase::fmt(fmt::format_string<T...> 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<SmallStringBase>
{
template<typename ParseContext>
constexpr auto parse(ParseContext& ctx)
{
return ctx.begin();
}
template<typename FormatContext>
auto format(const SmallStringBase& str, FormatContext& ctx)
{
return fmt::format_to(ctx.out(), "{}", str.view());
}
};

File diff suppressed because it is too large Load diff

View file

@ -1,472 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include "fmt/core.h"
#include "types.h"
#include <algorithm>
#include <cstdarg>
#include <cstring>
#include <limits>
#include <string>
#include <string_view>
#include <utility>
//
// 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<s32>::max());
void AppendSubString(const char* appendText, s32 Offset = 0, s32 Count = std::numeric_limits<s32>::max());
// append formatted string to this string
void AppendFormattedString(const char* FormatString, ...) printflike(2, 3);
void AppendFormattedStringVA(const char* FormatString, va_list ArgPtr);
template<typename... T>
void AppendFmtString(fmt::format_string<T...> 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<s32>::max());
void PrependSubString(const char* appendText, s32 Offset = 0, s32 Count = std::numeric_limits<s32>::max());
// append formatted string to this string
void PrependFormattedString(const char* FormatString, ...) printflike(2, 3);
void PrependFormattedStringVA(const char* FormatString, va_list ArgPtr);
template<typename... T>
void PrependFmtString(fmt::format_string<T...> 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<typename... T>
void Fmt(fmt::format_string<T...> 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<s32>::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<s32>::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<char*>(Text), length, buffer_size, static_cast<s32>(-1), \
true}; \
return String(const_cast<String::StringData*>(&data)); \
}()
// stack-allocated string
template<u32 L>
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<u32>(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<typename... T>
static StackString FromFmt(fmt::format_string<T...> 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<typename... T>
void String::AppendFmtString(fmt::format_string<T...> fmt, T&&... args)
{
fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...));
}
template<typename... T>
void String::PrependFmtString(fmt::format_string<T...> fmt, T&&... args)
{
TinyString str;
fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...));
PrependString(str);
}
template<typename... T>
void String::Fmt(fmt::format_string<T...> fmt, T&&... args)
{
Clear();
fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...));
}

View file

@ -25,7 +25,7 @@
#include "common/path.h" #include "common/path.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "util/cd_image.h" #include "util/cd_image.h"
@ -253,7 +253,7 @@ void Achievements::ReportRCError(int err, fmt::format_string<T...> fmt, T&&... a
{ {
TinyString str; TinyString str;
fmt::vformat_to(std::back_inserter(str), fmt, fmt::make_format_args(args...)); 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); ReportError(str);
} }
@ -1137,16 +1137,15 @@ void Achievements::HandleLeaderboardTrackerShowEvent(const rc_client_event_t* ev
event->leaderboard_tracker->display); event->leaderboard_tracker->display);
TinyString width_string; TinyString width_string;
width_string.AppendString(ICON_FA_STOPWATCH); width_string.append(ICON_FA_STOPWATCH);
const u32 display_len = static_cast<u32>(std::strlen(event->leaderboard_tracker->display)); const u32 display_len = static_cast<u32>(std::strlen(event->leaderboard_tracker->display));
for (u32 i = 0; i < display_len; i++) for (u32 i = 0; i < display_len; i++)
width_string.AppendCharacter('0'); width_string.append('0');
LeaderboardTrackerIndicator indicator; LeaderboardTrackerIndicator indicator;
indicator.tracker_id = event->leaderboard_tracker->id; indicator.tracker_id = event->leaderboard_tracker->id;
indicator.size = ImGuiFullscreen::g_medium_font->CalcTextSizeA( indicator.size = ImGuiFullscreen::g_medium_font->CalcTextSizeA(ImGuiFullscreen::g_medium_font->FontSize, FLT_MAX,
ImGuiFullscreen::g_medium_font->FontSize, FLT_MAX, 0.0f, width_string.GetCharArray(), 0.0f, width_string.c_str(), width_string.end_ptr());
width_string.GetCharArray() + width_string.GetLength());
indicator.text = fmt::format(ICON_FA_STOPWATCH " {}", event->leaderboard_tracker->display); indicator.text = fmt::format(ICON_FA_STOPWATCH " {}", event->leaderboard_tracker->display);
indicator.active = true; indicator.active = true;
s_active_leaderboard_trackers.push_back(std::move(indicator)); 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) if (achievement->badge_name[0] == 0)
return path; return path;
path = Path::Combine(s_image_directory, TinyString::FromFmt("achievement_{}_{}_{}.png", s_game_id, achievement->id, path = Path::Combine(s_image_directory, TinyString::from_fmt("achievement_{}_{}_{}.png", s_game_id, achievement->id,
s_achievement_state_strings[state])); s_achievement_state_strings[state]));
if (!FileSystem::FileExists(path.c_str())) if (!FileSystem::FileExists(path.c_str()))
{ {
@ -1517,7 +1516,7 @@ std::string Achievements::GetUserBadgePath(const std::string_view& username)
std::string path; std::string path;
const std::string clean_username = Path::SanitizeFileName(username); const std::string clean_username = Path::SanitizeFileName(username);
if (!clean_username.empty()) 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; return path;
} }
@ -2062,27 +2061,27 @@ void Achievements::DrawAchievementsWindow()
} }
const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize)); 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) if (s_hardcore_mode)
text.AppendString(TRANSLATE_SV("Achievements", " (Hardcore Mode)")); text.append(TRANSLATE_SV("Achievements", " (Hardcore Mode)"));
top += g_large_font->FontSize + spacing; top += g_large_font->FontSize + spacing;
ImGui::PushFont(g_large_font); ImGui::PushFont(g_large_font);
ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f),
nullptr, ImVec2(0.0f, 0.0f), &title_bb); &title_bb);
ImGui::PopFont(); ImGui::PopFont();
const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + g_medium_font->FontSize)); 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) 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); s_game_summary.points_unlocked);
} }
else else
{ {
text.Fmt( text.fmt(
TRANSLATE_FS("Achievements", "You have unlocked {} of {} achievements, earning {} of {} possible points."), 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.num_unlocked_achievements, s_game_summary.num_core_achievements,
s_game_summary.points_unlocked, s_game_summary.points_core); s_game_summary.points_unlocked, s_game_summary.points_core);
@ -2091,8 +2090,8 @@ void Achievements::DrawAchievementsWindow()
top += g_medium_font->FontSize + spacing; top += g_medium_font->FontSize + spacing;
ImGui::PushFont(g_medium_font); ImGui::PushFont(g_medium_font);
ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.GetCharArray(), ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.c_str(), text.end_ptr(), nullptr,
text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &summary_bb); ImVec2(0.0f, 0.0f), &summary_bb);
ImGui::PopFont(); ImGui::PopFont();
const float progress_height = ImGuiFullscreen::LayoutScale(20.0f); 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), ImVec2(progress_bb.Min.x + fraction * progress_bb.GetWidth(), progress_bb.Max.y),
ImGui::GetColorU32(ImGuiFullscreen::UISecondaryColor)); ImGui::GetColorU32(ImGuiFullscreen::UISecondaryColor));
text.Fmt("{}%", static_cast<int>(std::round(fraction * 100.0f))); text.fmt("{}%", static_cast<int>(std::round(fraction * 100.0f)));
text_size = ImGui::CalcTextSize(text.GetCharArray(), text.GetCharArray() + text.GetLength()); 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), 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) - progress_bb.Min.y + ((progress_bb.Max.y - progress_bb.Min.y) / 2.0f) -
(text_size.y / 2.0f)); (text_size.y / 2.0f));
dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos,
ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryTextColor), text.GetCharArray(), ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryTextColor), text.c_str(), text.end_ptr());
text.GetCharArray() + text.GetLength());
top += progress_height + spacing; top += progress_height + spacing;
} }
} }
@ -2183,7 +2181,7 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
ImRect bb; ImRect bb;
bool visible, hovered; 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 : !is_measured ? ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT + unlock_size :
ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT + ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT +
progress_height_unscaled + progress_spacing_unscaled, progress_height_unscaled + progress_spacing_unscaled,
@ -2219,12 +2217,12 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
SmallString text; SmallString text;
const float midpoint = bb.Min.y + g_large_font->FontSize + spacing; 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); cheevo->points);
const ImVec2 points_template_size( const ImVec2 points_template_size(
g_medium_font->CalcTextSizeA(g_medium_font->FontSize, FLT_MAX, 0.0f, TRANSLATE("Achievements", "XXX points"))); 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(), const ImVec2 points_size(
text.GetCharArray() + text.GetLength())); 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_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 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; 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), ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, cheevo->description, nullptr, nullptr, ImVec2(0.0f, 0.0f),
&summary_bb); &summary_bb);
} }
ImGui::RenderTextClipped(points_bb.Min, points_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), ImGui::RenderTextClipped(points_bb.Min, points_bb.Max, text.c_str(), text.end_ptr(), &points_size, ImVec2(0.0f, 0.0f),
&points_size, ImVec2(0.0f, 0.0f), &points_bb); &points_bb);
if (is_unlocked) if (is_unlocked)
{ {
TinyString date; TinyString date;
FullscreenUI::TimeToPrintableString(&date, cheevo->unlock_time); 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); 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, ImGui::RenderTextClipped(unlock_bb.Min, unlock_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f),
ImVec2(0.0f, 0.0f), &unlock_bb); &unlock_bb);
} }
else if (is_measured) 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)); 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; top += g_large_font->FontSize + spacing;
ImGui::PushFont(g_large_font); ImGui::PushFont(g_large_font);
ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.GetCharArray(), text.GetCharArray() + text.GetLength(), ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f),
nullptr, ImVec2(0.0f, 0.0f), &title_bb); &title_bb);
ImGui::PopFont(); ImGui::PopFont();
if (is_leaderboard_open) if (is_leaderboard_open)
{ {
const ImRect subtitle_bb(ImVec2(left, top), ImVec2(right, top + g_large_font->FontSize)); 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; top += g_large_font->FontSize + spacing_small;
ImGui::PushFont(g_large_font); ImGui::PushFont(g_large_font);
ImGui::RenderTextClipped(subtitle_bb.Min, subtitle_bb.Max, text.GetCharArray(), ImGui::RenderTextClipped(subtitle_bb.Min, subtitle_bb.Max, text.c_str(), text.end_ptr(), nullptr,
text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &subtitle_bb); ImVec2(0.0f, 0.0f), &subtitle_bb);
ImGui::PopFont(); ImGui::PopFont();
text.Assign(s_open_leaderboard->description); text.assign(s_open_leaderboard->description);
} }
else else
{ {
u32 count = 0; u32 count = 0;
for (u32 i = 0; i < s_leaderboard_list->num_buckets; i++) for (u32 i = 0; i < s_leaderboard_list->num_buckets; i++)
count += s_leaderboard_list->buckets[i].num_leaderboards; 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)); const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + g_medium_font->FontSize));
top += g_medium_font->FontSize + spacing_small; top += g_medium_font->FontSize + spacing_small;
ImGui::PushFont(g_medium_font); ImGui::PushFont(g_medium_font);
ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.GetCharArray(), ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, text.c_str(), text.end_ptr(), nullptr,
text.GetCharArray() + text.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &summary_bb); ImVec2(0.0f, 0.0f), &summary_bb);
if (!is_leaderboard_open && !Achievements::IsHardcoreModeActive()) 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); float text_start_x = bb.Min.x + LayoutScale(15.0f);
SmallString text; SmallString text;
text.Format("%u", entry.rank); text.fmt("{}", entry.rank);
ImGui::PushFont(g_large_font); 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)); 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)); 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(), ImGui::RenderTextClipped(rank_bb.Min, rank_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f),
nullptr, ImVec2(0.0f, 0.0f), &rank_bb); &rank_bb);
text_start_x += rank_column_width + column_spacing; text_start_x += rank_column_width + column_spacing;
const float icon_size = bb.Max.y - bb.Min.y; 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)); const ImRect time_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(bb.Max.x, midpoint));
SmallString submit_time; SmallString submit_time;
FullscreenUI::TimeToPrintableString(&submit_time, entry.submitted); FullscreenUI::TimeToPrintableString(&submit_time, entry.submitted);
ImGui::RenderTextClipped(time_bb.Min, time_bb.Max, submit_time.GetCharArray(), ImGui::RenderTextClipped(time_bb.Min, time_bb.Max, submit_time.c_str(), submit_time.end_ptr(), nullptr,
submit_time.GetCharArray() + submit_time.GetLength(), nullptr, ImVec2(0.0f, 0.0f), &time_bb); ImVec2(0.0f, 0.0f), &time_bb);
if (is_self) if (is_self)
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@ -2716,7 +2714,7 @@ void Achievements::DrawLeaderboardListEntry(const rc_client_leaderboard_t* lboar
static constexpr float alpha = 0.8f; static constexpr float alpha = 0.8f;
TinyString id_str; TinyString id_str;
id_str.Format("%u", lboard->id); id_str.fmt("{}", lboard->id);
ImRect bb; ImRect bb;
bool visible, hovered; bool visible, hovered;

View file

@ -3,7 +3,7 @@
#pragma once #pragma once
#include "common/string.h" #include "common/small_string.h"
#include "common/types.h" #include "common/types.h"
#include <string> #include <string>

View file

@ -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(&old_disasm, address, existing_value);
CPU::DisassembleInstruction(&new_disasm, address, new_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, 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) bool BIOS::PatchBIOSFastBoot(u8* image, u32 image_size)

View file

@ -770,22 +770,22 @@ static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, P
u32& value) u32& value)
{ {
SmallString str; SmallString str;
str.AppendString("Invalid bus "); str.append("Invalid bus ");
if (size == MemoryAccessSize::Byte) if (size == MemoryAccessSize::Byte)
str.AppendString("byte"); str.append("byte");
if (size == MemoryAccessSize::HalfWord) if (size == MemoryAccessSize::HalfWord)
str.AppendString("word"); str.append("word");
if (size == MemoryAccessSize::Word) if (size == MemoryAccessSize::Word)
str.AppendString("dword"); str.append("dword");
str.AppendCharacter(' '); str.append(' ');
if (type == MemoryAccessType::Read) if (type == MemoryAccessType::Read)
str.AppendString("read"); str.append("read");
else 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) if (type == MemoryAccessType::Write)
str.AppendFormattedString(" (value 0x%08X)", value); str.append_fmt(" (value 0x{:08X})", value);
Log_ErrorPrint(str); Log_ErrorPrint(str);
if (type == MemoryAccessType::Read) if (type == MemoryAccessType::Read)

View file

@ -803,7 +803,7 @@ bool CDROM::PrecacheMedia()
TinyString CDROM::LBAToMSFString(CDImage::LBA lba) TinyString CDROM::LBAToMSFString(CDImage::LBA lba)
{ {
const auto pos = CDImage::Position::FromLBA(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) 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; const CDImage::LBA new_physical_lba = base + new_offset;
#ifdef _DEBUG #ifdef _DEBUG
Log_DevPrintf("Tick diff %u, sector diff %u, old pos %s, new pos %s", diff, sector_diff, 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 #endif
if (s_physical_lba != new_physical_lba) if (s_physical_lba != new_physical_lba)
{ {
@ -2575,7 +2575,7 @@ void CDROM::DoSeekComplete(TickCount ticks_late)
else else
{ {
Log_WarningPrintf("%s seek to [%s] failed", logical ? "Logical" : "Physical", 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(); s_secondary_status.ClearActiveBits();
SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04); SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04);
s_last_sector_header_valid = false; s_last_sector_header_valid = false;
@ -2733,8 +2733,7 @@ void CDROM::DoSectorRead()
} }
else else
{ {
Log_DevPrintf("Sector %u [%s] has invalid subchannel Q", s_current_lba, Log_DevPrintf("Sector %u [%s] has invalid subchannel Q", s_current_lba, LBAToMSFString(s_current_lba).c_str());
LBAToMSFString(s_current_lba).GetCharArray());
} }
if (subq.track_number_bcd == CDImage::LEAD_OUT_TRACK_NUMBER) 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; 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, 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); ZeroExtend32(s_last_sector_subheader.submode.bits), sb_num);
if (s_mode.xa_enable && s_last_sector_header.sector_mode == 2) if (s_mode.xa_enable && s_last_sector_header.sector_mode == 2)

View file

@ -7,7 +7,7 @@
#include "common/byte_stream.h" #include "common/byte_stream.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "controller.h" #include "controller.h"
#include "cpu_code_cache.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++) for (u32 i = 0; i < num_cheats; i++)
{ {
const std::string* desc = FindKey(kvp, TinyString::FromFormat("cheat%u_desc", i)); const std::string* desc = FindKey(kvp, TinyString::from_fmt("cheat{}_desc", i));
const std::string* code = FindKey(kvp, TinyString::FromFormat("cheat%u_code", i)); const std::string* code = FindKey(kvp, TinyString::from_fmt("cheat{}_code", i));
const std::string* enable = FindKey(kvp, TinyString::FromFormat("cheat%u_enable", i)); const std::string* enable = FindKey(kvp, TinyString::from_fmt("cheat{}_enable", i));
if (!desc || !code || !enable) if (!desc || !code || !enable)
{ {
Log_WarningPrintf("Missing desc/code/enable for cheat %u", i); Log_WarningPrintf("Missing desc/code/enable for cheat %u", i);

View file

@ -799,7 +799,7 @@ bool CompileBlock(CodeBlock* block, bool allow_flush)
{ {
CPU::DisassembleInstruction(&disasm, cbi.pc, cbi.instruction.bits); CPU::DisassembleInstruction(&disasm, cbi.pc, cbi.instruction.bits);
Log_DebugPrintf("[%s %s 0x%08X] %08X %s", cbi.is_branch_delay_slot ? "BD" : " ", 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 #endif
} }

View file

@ -571,15 +571,15 @@ static void TracePrintInstruction()
TinyString comment; TinyString comment;
DisassembleInstruction(&instr, pc, bits); DisassembleInstruction(&instr, pc, bits);
DisassembleInstructionComment(&comment, pc, bits, &g_state.regs); DisassembleInstructionComment(&comment, pc, bits, &g_state.regs);
if (!comment.IsEmpty()) if (!comment.empty())
{ {
for (u32 i = instr.GetLength(); i < 30; i++) for (u32 i = instr.length(); i < 30; i++)
instr.AppendCharacter(' '); instr.append(' ');
instr.AppendString("; "); instr.append("; ");
instr.AppendString(comment); 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 #endif
@ -590,15 +590,15 @@ static void PrintInstruction(u32 bits, u32 pc, Registers* regs, const char* pref
TinyString comment; TinyString comment;
DisassembleInstruction(&instr, pc, bits); DisassembleInstruction(&instr, pc, bits);
DisassembleInstructionComment(&comment, pc, bits, regs); DisassembleInstructionComment(&comment, pc, bits, regs);
if (!comment.IsEmpty()) if (!comment.empty())
{ {
for (u32 i = instr.GetLength(); i < 30; i++) for (u32 i = instr.length(); i < 30; i++)
instr.AppendCharacter(' '); instr.append(' ');
instr.AppendString("; "); instr.append("; ");
instr.AppendString(comment); 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) static void LogInstruction(u32 bits, u32 pc, Registers* regs)
@ -607,15 +607,15 @@ static void LogInstruction(u32 bits, u32 pc, Registers* regs)
TinyString comment; TinyString comment;
DisassembleInstruction(&instr, pc, bits); DisassembleInstruction(&instr, pc, bits);
DisassembleInstructionComment(&comment, pc, bits, regs); DisassembleInstructionComment(&comment, pc, bits, regs);
if (!comment.IsEmpty()) if (!comment.empty())
{ {
for (u32 i = instr.GetLength(); i < 30; i++) for (u32 i = instr.length(); i < 30; i++)
instr.AppendCharacter(' '); instr.append(' ');
instr.AppendString("; "); instr.append("; ");
instr.AppendString(comment); 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() static void HandleWriteSyscall()

View file

@ -1,9 +1,12 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "common/assert.h"
#include "cpu_core.h" #include "cpu_core.h"
#include "common/assert.h"
#include "common/small_string.h"
#include <array> #include <array>
namespace CPU { namespace CPU {
@ -169,9 +172,9 @@ static const std::array<std::pair<CopCommonInstruction, const char*>, 4> s_cop_c
static const std::array<std::pair<Cop0Instruction, const char*>, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}}; static const std::array<std::pair<Cop0Instruction, const char*>, 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; const char* str = format;
while (*str != '\0') while (*str != '\0')
@ -179,77 +182,77 @@ static void FormatInstruction(String* dest, const Instruction inst, u32 pc, cons
const char ch = *(str++); const char ch = *(str++);
if (ch != '$') if (ch != '$')
{ {
dest->AppendCharacter(ch); dest->append(ch);
continue; continue;
} }
if (std::strncmp(str, "rs", 2) == 0) if (std::strncmp(str, "rs", 2) == 0)
{ {
dest->AppendString(GetRegName(inst.r.rs)); dest->append(GetRegName(inst.r.rs));
str += 2; str += 2;
} }
else if (std::strncmp(str, "rt", 2) == 0) else if (std::strncmp(str, "rt", 2) == 0)
{ {
dest->AppendString(GetRegName(inst.r.rt)); dest->append(GetRegName(inst.r.rt));
str += 2; str += 2;
} }
else if (std::strncmp(str, "rd", 2) == 0) else if (std::strncmp(str, "rd", 2) == 0)
{ {
dest->AppendString(GetRegName(inst.r.rd)); dest->append(GetRegName(inst.r.rd));
str += 2; str += 2;
} }
else if (std::strncmp(str, "shamt", 5) == 0) 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; str += 5;
} }
else if (std::strncmp(str, "immu", 4) == 0) else if (std::strncmp(str, "immu", 4) == 0)
{ {
dest->AppendFormattedString("%u", inst.i.imm_zext32()); dest->append_fmt("{}", inst.i.imm_zext32());
str += 4; str += 4;
} }
else if (std::strncmp(str, "imm", 3) == 0) else if (std::strncmp(str, "imm", 3) == 0)
{ {
// dest->AppendFormattedString("%d", static_cast<int>(inst.i.imm_sext32())); // dest->AppendFormattedString("%d", static_cast<int>(inst.i.imm_sext32()));
dest->AppendFormattedString("%04x", inst.i.imm_zext32()); dest->append_fmt("{:04x}", inst.i.imm_zext32());
str += 3; str += 3;
} }
else if (std::strncmp(str, "rel", 3) == 0) else if (std::strncmp(str, "rel", 3) == 0)
{ {
const u32 target = (pc + UINT32_C(4)) + (inst.i.imm_sext32() << 2); const u32 target = (pc + UINT32_C(4)) + (inst.i.imm_sext32() << 2);
dest->AppendFormattedString("%08x", target); dest->append_fmt("{:08x}", target);
str += 3; str += 3;
} }
else if (std::strncmp(str, "offsetrs", 8) == 0) else if (std::strncmp(str, "offsetrs", 8) == 0)
{ {
const s32 offset = static_cast<s32>(inst.i.imm_sext32()); const s32 offset = static_cast<s32>(inst.i.imm_sext32());
dest->AppendFormattedString("%d(%s)", offset, GetRegName(inst.i.rs)); dest->append_fmt("{}({})", offset, GetRegName(inst.i.rs));
str += 8; str += 8;
} }
else if (std::strncmp(str, "jt", 2) == 0) else if (std::strncmp(str, "jt", 2) == 0)
{ {
const u32 target = ((pc + UINT32_C(4)) & UINT32_C(0xF0000000)) | (inst.j.target << 2); 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; str += 2;
} }
else if (std::strncmp(str, "copcc", 5) == 0) 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; str += 5;
} }
else if (std::strncmp(str, "coprd", 5) == 0) else if (std::strncmp(str, "coprd", 5) == 0)
{ {
dest->AppendFormattedString("%u", ZeroExtend32(static_cast<u8>(inst.r.rd.GetValue()))); dest->append_fmt("{}", ZeroExtend32(static_cast<u8>(inst.r.rd.GetValue())));
str += 5; str += 5;
} }
else if (std::strncmp(str, "coprt", 5) == 0) else if (std::strncmp(str, "coprt", 5) == 0)
{ {
dest->AppendFormattedString("%u", ZeroExtend32(static_cast<u8>(inst.r.rt.GetValue()))); dest->append_fmt("{}", ZeroExtend32(static_cast<u8>(inst.r.rt.GetValue())));
str += 5; str += 5;
} }
else if (std::strncmp(str, "cop", 3) == 0) else if (std::strncmp(str, "cop", 3) == 0)
{ {
dest->AppendFormattedString("%u", static_cast<u8>(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK); dest->append_fmt("{}", static_cast<u8>(inst.op.GetValue()) & INSTRUCTION_COP_N_MASK);
str += 3; str += 3;
} }
else 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; const char* str = format;
while (*str != '\0') 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) if (std::strncmp(str, "rs", 2) == 0)
{ {
dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rs), dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rs),
regs->r[static_cast<u8>(inst.r.rs.GetValue())]); regs->r[static_cast<u8>(inst.r.rs.GetValue())]);
str += 2; str += 2;
} }
else if (std::strncmp(str, "rt", 2) == 0) else if (std::strncmp(str, "rt", 2) == 0)
{ {
dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rt), dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rt),
regs->r[static_cast<u8>(inst.r.rt.GetValue())]); regs->r[static_cast<u8>(inst.r.rt.GetValue())]);
str += 2; str += 2;
} }
else if (std::strncmp(str, "rd", 2) == 0) else if (std::strncmp(str, "rd", 2) == 0)
{ {
dest->AppendFormattedString("%s%s=0x%08X", dest->IsEmpty() ? "" : ", ", GetRegName(inst.r.rd), dest->append_fmt("{}{}=0x{:08X}", dest->empty() ? "" : ", ", GetRegName(inst.r.rd),
regs->r[static_cast<u8>(inst.r.rd.GetValue())]); regs->r[static_cast<u8>(inst.r.rd.GetValue())]);
str += 2; str += 2;
} }
else if (std::strncmp(str, "shamt", 5) == 0) 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) else if (std::strncmp(str, "offsetrs", 8) == 0)
{ {
const s32 offset = static_cast<s32>(inst.i.imm_sext32()); const s32 offset = static_cast<s32>(inst.i.imm_sext32());
dest->AppendFormattedString("%saddr=0x%08X", dest->IsEmpty() ? "" : ", ", dest->append_fmt("{}addr={:08X}", dest->empty() ? "" : ", ",
regs->r[static_cast<u8>(inst.i.rs.GetValue())] + offset); regs->r[static_cast<u8>(inst.i.rs.GetValue())] + offset);
str += 8; str += 8;
} }
else if (std::strncmp(str, "jt", 2) == 0) else if (std::strncmp(str, "jt", 2) == 0)
@ -338,8 +341,8 @@ static void FormatComment(String* dest, const Instruction inst, u32 pc, Register
} }
template<typename T> template<typename T>
void FormatCopInstruction(String* dest, u32 pc, const Instruction inst, const std::pair<T, const char*>* table, static void FormatCopInstruction(SmallStringBase* dest, u32 pc, const Instruction inst,
size_t table_size, T table_key) const std::pair<T, const char*>* table, size_t table_size, T table_key)
{ {
for (size_t i = 0; i < table_size; i++) 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("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); dest->fmt("<cop{} 0x{:08X}>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
} }
template<typename T> template<typename T>
void FormatCopComment(String* dest, u32 pc, Registers* regs, const Instruction inst, static void FormatCopComment(SmallStringBase* dest, u32 pc, Registers* regs, const Instruction inst,
const std::pair<T, const char*>* table, size_t table_size, T table_key) const std::pair<T, const char*>* table, size_t table_size, T table_key)
{ {
for (size_t i = 0; i < table_size; i++) 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}; const Instruction inst{bits};
switch (inst.op) switch (inst.op)
@ -400,7 +403,7 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
case InstructionOp::cop3: case InstructionOp::cop3:
default: default:
{ {
dest->Format("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); dest->fmt("<cop{} 0x{:08X}>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
} }
break; 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}; const Instruction inst{bits};
switch (inst.op) switch (inst.op)
@ -461,7 +464,7 @@ void DisassembleInstructionComment(String* dest, u32 pc, u32 bits, Registers* re
case InstructionOp::cop3: case InstructionOp::cop3:
default: default:
{ {
dest->Format("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); dest->fmt("<cop{} 0x{:08X}>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
} }
break; break;
} }

View file

@ -1,11 +1,12 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once #pragma once
#include "common/string.h"
#include "cpu_types.h" #include "cpu_types.h"
class SmallStringBase;
namespace CPU { namespace CPU {
void DisassembleInstruction(String* dest, u32 pc, u32 bits); void DisassembleInstruction(SmallStringBase* 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);
} // namespace CPU } // namespace CPU

View file

@ -32,7 +32,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/make_array.h" #include "common/make_array.h"
#include "common/path.h" #include "common/path.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/threading.h" #include "common/threading.h"
@ -54,19 +54,23 @@ Log_SetChannel(FullscreenUI);
#define TR_CONTEXT "FullscreenUI" #define TR_CONTEXT "FullscreenUI"
namespace FullscreenUI { namespace {
template<size_t L> template<size_t L>
class IconStackString : public StackString<L> class IconStackString : public SmallStackString<L>
{ {
public: public:
ALWAYS_INLINE IconStackString(const char* icon, const char* str) ALWAYS_INLINE IconStackString(const char* icon, const char* str)
{ {
StackString<L>::Fmt("{} {}", icon, Host::TranslateToStringView(TR_CONTEXT, str)); SmallStackString<L>::fmt("{} {}", icon, Host::TranslateToStringView(TR_CONTEXT, str));
}
ALWAYS_INLINE IconStackString(const char* icon, const char* str, const char* suffix)
{
SmallStackString<L>::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_STR(str) Host::TranslateToString(TR_CONTEXT, str)
#define FSUI_CSTR(str) Host::TranslateToCString(TR_CONTEXT, str) #define FSUI_CSTR(str) Host::TranslateToCString(TR_CONTEXT, str)
#define FSUI_VSTR(str) Host::TranslateToStringView(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 // Utility
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void FullscreenUI::TimeToPrintableString(String* str, time_t t) void FullscreenUI::TimeToPrintableString(SmallStringBase* str, time_t t)
{ {
struct tm lt = {}; struct tm lt = {};
#ifdef _MSC_VER #ifdef _MSC_VER
@ -483,7 +487,7 @@ void FullscreenUI::TimeToPrintableString(String* str, time_t t)
char buf[256]; char buf[256];
std::strftime(buf, sizeof(buf), "%c", &lt); std::strftime(buf, sizeof(buf), "%c", &lt);
str->Assign(buf); str->assign(buf);
} }
void FullscreenUI::StartAsyncOp(std::function<void(::ProgressCallback*)> callback, std::string name) void FullscreenUI::StartAsyncOp(std::function<void(::ProgressCallback*)> callback, std::string name)
@ -1342,7 +1346,7 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn
const char* name, const char* display_name, bool show_type) const char* name, const char* display_name, bool show_type)
{ {
TinyString title; TinyString title;
title.Fmt("{}/{}", section, name); title.fmt("{}/{}", section, name);
ImRect bb; ImRect bb;
bool visible, hovered, clicked; bool visible, hovered, clicked;
@ -1360,17 +1364,17 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn
switch (type) switch (type)
{ {
case InputBindingInfo::Type::Button: case InputBindingInfo::Type::Button:
title = fmt::format(ICON_FA_DOT_CIRCLE "{}", display_name); title.fmt(ICON_FA_DOT_CIRCLE "{}", display_name);
break; break;
case InputBindingInfo::Type::Axis: case InputBindingInfo::Type::Axis:
case InputBindingInfo::Type::HalfAxis: case InputBindingInfo::Type::HalfAxis:
title = fmt::format(ICON_FA_BULLSEYE "{}", display_name); title.fmt(ICON_FA_BULLSEYE "{}", display_name);
break; break;
case InputBindingInfo::Type::Motor: case InputBindingInfo::Type::Motor:
title = fmt::format(ICON_FA_BELL "{}", display_name); title.fmt(ICON_FA_BELL "{}", display_name);
break; break;
case InputBindingInfo::Type::Macro: case InputBindingInfo::Type::Macro:
title = fmt::format(ICON_FA_PIZZA_SLICE "{}", display_name); title.fmt(ICON_FA_PIZZA_SLICE "{}", display_name);
break; break;
default: default:
title = display_name; title = display_name;
@ -1379,8 +1383,8 @@ void FullscreenUI::DrawInputBindingButton(SettingsInterface* bsi, InputBindingIn
} }
ImGui::PushFont(g_large_font); ImGui::PushFont(g_large_font);
ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.GetCharArray() : display_name, nullptr, ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.c_str() : display_name, nullptr, nullptr,
nullptr, ImVec2(0.0f, 0.0f), &title_bb); ImVec2(0.0f, 0.0f), &title_bb);
ImGui::PopFont(); ImGui::PopFont();
const std::string value(bsi->GetStringValue(section, name)); const std::string value(bsi->GetStringValue(section, name));
@ -1521,12 +1525,12 @@ void FullscreenUI::DrawInputBindingWindow()
if (ImGui::BeginPopupModal(title, nullptr, if (ImGui::BeginPopupModal(title, nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs)) ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs))
{ {
ImGui::TextWrapped("%s", SmallString::FromFmt(FSUI_FSTR("Setting {} binding {}."), s_input_binding_section, ImGui::TextWrapped("%s", SmallString::from_fmt(FSUI_FSTR("Setting {} binding {}."), s_input_binding_section,
s_input_binding_display_name) s_input_binding_display_name)
.GetCharArray()); .c_str());
ImGui::TextUnformatted(FSUI_CSTR("Push a controller button or axis now.")); ImGui::TextUnformatted(FSUI_CSTR("Push a controller button or axis now."));
ImGui::NewLine(); 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(); ImGui::EndPopup();
} }
@ -2004,7 +2008,7 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit
bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional<int>(default_value)); bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional<int>(default_value));
TinyString value_text; TinyString value_text;
if (value.has_value()) if (value.has_value())
value_text.Format(format, value.value()); value_text.format(format, value.value());
else else
value_text = FSUI_VSTR("Use Global Setting"); value_text = FSUI_VSTR("Use Global Setting");
@ -2821,14 +2825,14 @@ void FullscreenUI::DrawBIOSSettingsPage()
continue; continue;
TinyString title; TinyString title;
title.Fmt(FSUI_FSTR("BIOS for {}"), Settings::GetConsoleRegionDisplayName(region)); title.fmt(FSUI_FSTR("BIOS for {}"), Settings::GetConsoleRegionDisplayName(region));
const std::optional<std::string> filename(bsi->GetOptionalStringValue( const std::optional<std::string> filename(bsi->GetOptionalStringValue(
"BIOS", config_keys[i], game_settings ? std::nullopt : std::optional<const char*>(""))); "BIOS", config_keys[i], game_settings ? std::nullopt : std::optional<const char*>("")));
if (MenuButtonWithValue(title, if (MenuButtonWithValue(title,
SmallString::FromFmt(FSUI_FSTR("BIOS to use when emulating {} consoles."), SmallString::from_fmt(FSUI_FSTR("BIOS to use when emulating {} consoles."),
Settings::GetConsoleRegionDisplayName(region)), Settings::GetConsoleRegionDisplayName(region)),
filename.has_value() ? (filename->empty() ? FSUI_CSTR("Auto-Detect") : filename->c_str()) : filename.has_value() ? (filename->empty() ? FSUI_CSTR("Auto-Detect") : filename->c_str()) :
FSUI_CSTR("Use Global Setting"))) FSUI_CSTR("Use Global Setting")))
{ {
@ -3052,7 +3056,7 @@ void FullscreenUI::DrawEmulationSettingsPage()
u64 ram_usage, vram_usage; u64 ram_usage, vram_usage;
System::CalculateRewindMemoryUsage(rewind_save_slots, &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."), 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); rewind_save_slots, duration, ram_usage / 1048576, vram_usage / 1048576);
} }
@ -3277,18 +3281,18 @@ void FullscreenUI::DrawControllerSettingsPage()
if (mtap_enabled[mtap_port]) if (mtap_enabled[mtap_port])
{ {
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,
mtap_slot_names[mtap_slot])); mtap_slot_names[mtap_slot]));
} }
else 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 section(fmt::format("Pad{}", global_slot + 1));
const std::string type(bsi->GetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(global_slot))); const std::string type(bsi->GetStringValue(section.c_str(), "Type", Controller::GetDefaultPadType(global_slot)));
const Controller::ControllerInfo* ci = Controller::GetControllerInfo(type); 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"))) ci ? ci->display_name : FSUI_CSTR("Unknown")))
{ {
std::vector<std::pair<std::string, std::string>> raw_options(Controller::GetControllerTypeNames()); std::vector<std::pair<std::string, std::string>> raw_options(Controller::GetControllerTypeNames());
@ -3298,7 +3302,7 @@ void FullscreenUI::DrawControllerSettingsPage()
{ {
options.emplace_back(std::move(it.second), type == it.first); 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), std::move(options),
[game_settings, section, [game_settings, section,
raw_options = std::move(raw_options)](s32 index, const std::string& title, bool checked) { 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]) if (mtap_enabled[mtap_port])
{ {
MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {}{} Macros")), MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {}{} Macros")),
mtap_port + 1, mtap_slot_names[mtap_slot])); mtap_port + 1, mtap_slot_names[mtap_slot]));
} }
else else
{ {
MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {} Macros")), MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_MICROCHIP, "Controller Port {} Macros")),
mtap_port + 1)); mtap_port + 1));
} }
for (u32 macro_index = 0; macro_index < InputManager::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++) for (u32 macro_index = 0; macro_index < InputManager::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++)
{ {
DrawInputBindingButton(bsi, InputBindingInfo::Type::Macro, section.c_str(), DrawInputBindingButton(bsi, InputBindingInfo::Type::Macro, section.c_str(),
TinyString::FromFmt("Macro{}", macro_index + 1), TinyString::from_fmt("Macro{}", macro_index + 1),
TinyString::FromFmt(FSUI_FSTR("Macro {} Trigger"), macro_index + 1)); TinyString::from_fmt(FSUI_FSTR("Macro {} Trigger"), macro_index + 1));
std::string binds_string( std::string binds_string(
bsi->GetStringValue(section.c_str(), fmt::format("Macro{}Binds", macro_index + 1).c_str())); bsi->GetStringValue(section.c_str(), fmt::format("Macro{}Binds", macro_index + 1).c_str()));
if (MenuButton( 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())) binds_string.empty() ? FSUI_CSTR("No Buttons Selected") : binds_string.c_str()))
{ {
std::vector<std::string_view> buttons_split(StringUtil::SplitString(binds_string, '&', true)); std::vector<std::string_view> buttons_split(StringUtil::SplitString(binds_string, '&', true));
@ -3363,7 +3367,7 @@ void FullscreenUI::DrawControllerSettingsPage()
} }
OpenChoiceDialog( 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) { [game_settings, section, macro_index, ci](s32 index, const std::string& title, bool checked) {
// convert display name back to bind name // convert display name back to bind name
std::string_view to_modify; 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 std::string freq_key(fmt::format("Macro{}Frequency", macro_index + 1));
const SmallString freq_title = 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); s32 frequency = bsi->GetIntValue(section.c_str(), freq_key.c_str(), 0);
SmallString freq_summary; SmallString freq_summary;
if (frequency == 0) if (frequency == 0)
freq_summary = FSUI_VSTR("Macro will not auto-toggle."); freq_summary = FSUI_VSTR("Macro will not auto-toggle.");
else 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)) if (MenuButton(freq_title, freq_summary))
ImGui::OpenPopup(freq_title); ImGui::OpenPopup(freq_title);
@ -3456,19 +3460,20 @@ void FullscreenUI::DrawControllerSettingsPage()
{ {
if (mtap_enabled[mtap_port]) if (mtap_enabled[mtap_port])
{ {
MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {}{} Settings")), MenuHeading(
mtap_port + 1, mtap_slot_names[mtap_slot])); SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {}{} Settings")),
mtap_port + 1, mtap_slot_names[mtap_slot]));
} }
else else
{ {
MenuHeading(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {} Settings")), MenuHeading(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS_H, "Controller Port {} Settings")),
mtap_port + 1)); mtap_port + 1));
} }
for (const SettingInfo& si : ci->settings) for (const SettingInfo& si : ci->settings)
{ {
TinyString title; TinyString title;
title.Fmt(ICON_FA_COG "{}", si.display_name); title.fmt(ICON_FA_COG "{}", si.display_name);
switch (si.type) switch (si.type)
{ {
case SettingInfo::Type::Boolean: case SettingInfo::Type::Boolean:
@ -3583,13 +3588,13 @@ void FullscreenUI::DrawMemoryCardSettingsPage()
for (u32 i = 0; i < 2; i++) 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 = const MemoryCardType default_type =
(i == 0) ? Settings::DEFAULT_MEMORY_CARD_1_TYPE : Settings::DEFAULT_MEMORY_CARD_2_TYPE; (i == 0) ? Settings::DEFAULT_MEMORY_CARD_1_TYPE : Settings::DEFAULT_MEMORY_CARD_2_TYPE;
DrawEnumSetting( DrawEnumSetting(
bsi, TinyString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_SD_CARD, "Memory Card {} Type")), i + 1), bsi, TinyString::from_fmt(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), 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, "MemoryCards", type_keys[i], default_type, &Settings::ParseMemoryCardTypeName, &Settings::GetMemoryCardTypeName,
&Settings::GetMemoryCardTypeDisplayName, MemoryCardType::Count); &Settings::GetMemoryCardTypeDisplayName, MemoryCardType::Count);
@ -3605,7 +3610,7 @@ void FullscreenUI::DrawMemoryCardSettingsPage()
std::optional<const char*>((i == 0) ? "shared_card_1.mcd" : "shared_card_2.mcd"))); std::optional<const char*>((i == 0) ? "shared_card_1.mcd" : "shared_card_2.mcd")));
TinyString title; 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, if (MenuButtonWithValue(title,
FSUI_CSTR("The selected memory card image will be used in shared mode for this slot."), 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)) 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]; PostProcessingStageInfo& si = s_postprocessing_stages[stage_index];
ImGui::PushID(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); MenuHeading(str);
if (MenuButton(FSUI_ICONSTR(ICON_FA_TIMES, "Remove From Chain"), FSUI_CSTR("Removes this shader from the chain."))) 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: case PostProcessing::ShaderOption::Type::Bool:
{ {
bool value = (opt.value[0].int_value != 0); 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, if (ToggleButton(tstr,
(opt.default_value[0].int_value != 0) ? FSUI_CSTR("Default: Enabled") : (opt.default_value[0].int_value != 0) ? FSUI_CSTR("Default: Enabled") :
FSUI_CSTR("Default: Disabled"), FSUI_CSTR("Default: Disabled"),
@ -4124,8 +4129,8 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
case PostProcessing::ShaderOption::Type::Float: case PostProcessing::ShaderOption::Type::Float:
{ {
tstr.Fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); tstr.fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name);
str.Fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].float_value, 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); opt.default_value[0].float_value, opt.min_value[0].float_value, opt.max_value[0].float_value);
if (MenuButton(tstr, str)) if (MenuButton(tstr, str))
ImGui::OpenPopup(tstr); ImGui::OpenPopup(tstr);
@ -4223,8 +4228,8 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
case PostProcessing::ShaderOption::Type::Int: case PostProcessing::ShaderOption::Type::Int:
{ {
tstr.Fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name); tstr.fmt(ICON_FA_RULER_VERTICAL "{}##{}", opt.ui_name, opt.name);
str.Fmt(FSUI_FSTR("Value: {} | Default: {} | Minimum: {} | Maximum: {}"), opt.value[0].int_value, 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); opt.default_value[0].int_value, opt.min_value[0].int_value, opt.max_value[0].int_value);
if (MenuButton(tstr, str)) if (MenuButton(tstr, str))
ImGui::OpenPopup(tstr); ImGui::OpenPopup(tstr);
@ -4489,17 +4494,17 @@ void FullscreenUI::DrawAchievementsSettingsPage()
if (bsi->ContainsValue("Cheevos", "Token")) if (bsi->ContainsValue("Cheevos", "Token"))
{ {
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]); ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")), ActiveButton(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")),
bsi->GetStringValue("Cheevos", "Username")), bsi->GetStringValue("Cheevos", "Username")),
false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
TinyString ts_string; TinyString ts_string;
ts_string.AppendFmtString( ts_string.fmt(
"{:%Y-%m-%d %H:%M:%S}", "{:%Y-%m-%d %H:%M:%S}",
fmt::localtime(StringUtil::FromChars<u64>(bsi->GetStringValue("Cheevos", "LoginTimestamp", "0")).value_or(0))); fmt::localtime(StringUtil::FromChars<u64>(bsi->GetStringValue("Cheevos", "LoginTimestamp", "0")).value_or(0)));
ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_CLOCK, "Login token generated on {}")), ActiveButton(
ts_string.GetCharArray()), 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); false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Logout"), FSUI_CSTR("Logs out of RetroAchievements."))) 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(); const auto lock = Achievements::GetLock();
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]); ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
ActiveButton(SmallString::FromFmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_BOOKMARK, "Game: {} ({})")), ActiveButton(SmallString::from_fmt(fmt::runtime(FSUI_ICONSTR(ICON_FA_BOOKMARK, "Game: {} ({})")),
Achievements::GetGameID(), Achievements::GetGameTitle()), Achievements::GetGameID(), Achievements::GetGameTitle()),
false, false, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); false, false, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
const std::string& rich_presence_string = Achievements::GetRichPresenceString(); const std::string& rich_presence_string = Achievements::GetRichPresenceString();
if (!rich_presence_string.empty()) 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); LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
} }
else else
@ -4675,8 +4680,8 @@ void FullscreenUI::DrawPauseMenu()
const std::string& serial = System::GetGameSerial(); const std::string& serial = System::GetGameSerial();
if (!serial.empty()) if (!serial.empty())
buffer.Format("%s - ", serial.c_str()); buffer.fmt("{} - ", serial);
buffer.AppendString(Path::GetFileName(System::GetDiscPath())); buffer.append(Path::GetFileName(System::GetDiscPath()));
const ImVec2 title_size( const ImVec2 title_size(
g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f, title.c_str())); g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::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_large_font, title_pos, text_color, title.c_str(), title.c_str() + title.length());
DrawShadowedText(dl, g_medium_font, subtitle_pos, text_color, buffer); 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, const ImVec2 image_min(display_size.x - LayoutScale(20.0f + 50.0f) - rp_height,
display_size.y - 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 // 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<float>::max(), -1.0f, const ImVec2 time_size(g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f,
buffer.GetCharArray(), buffer.c_str(), buffer.end_ptr()));
buffer.GetCharArray() + buffer.GetLength()));
const ImVec2 time_pos(display_size.x - LayoutScale(10.0f) - time_size.x, LayoutScale(10.0f)); 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(), DrawShadowedText(dl, g_large_font, time_pos, text_color, buffer.c_str(), buffer.end_ptr());
buffer.GetCharArray() + buffer.GetLength());
const std::string& serial = System::GetGameSerial(); const std::string& serial = System::GetGameSerial();
if (!serial.empty()) if (!serial.empty())
@ -4738,24 +4741,19 @@ void FullscreenUI::DrawPauseMenu()
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial); const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
const std::time_t session_time = static_cast<std::time_t>(System::GetSessionPlayedTime()); const std::time_t session_time = static_cast<std::time_t>(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<float>::max(), const ImVec2 session_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits<float>::max(),
-1.0f, buffer.GetCharArray(), -1.0f, buffer.c_str(), buffer.end_ptr()));
buffer.GetCharArray() + buffer.GetLength()));
const ImVec2 session_pos(display_size.x - LayoutScale(10.0f) - session_size.x, const ImVec2 session_pos(display_size.x - LayoutScale(10.0f) - session_size.x,
time_pos.y + g_large_font->FontSize + LayoutScale(4.0f)); time_pos.y + g_large_font->FontSize + LayoutScale(4.0f));
DrawShadowedText(dl, g_medium_font, session_pos, text_color, buffer.GetCharArray(), DrawShadowedText(dl, g_medium_font, session_pos, text_color, buffer.c_str(), buffer.end_ptr());
buffer.GetCharArray() + buffer.GetLength());
buffer.Fmt(FSUI_FSTR("All Time: {}"), buffer.fmt(FSUI_FSTR("All Time: {}"), GameList::FormatTimespan(cached_played_time + session_time, true));
GameList::FormatTimespan(cached_played_time + session_time, true).GetStringView());
const ImVec2 total_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits<float>::max(), const ImVec2 total_size(g_medium_font->CalcTextSizeA(g_medium_font->FontSize, std::numeric_limits<float>::max(),
-1.0f, buffer.GetCharArray(), -1.0f, buffer.c_str(), buffer.end_ptr()));
buffer.GetCharArray() + buffer.GetLength()));
const ImVec2 total_pos(display_size.x - LayoutScale(10.0f) - total_size.x, const ImVec2 total_pos(display_size.x - LayoutScale(10.0f) - total_size.x,
session_pos.y + g_medium_font->FontSize + LayoutScale(4.0f)); session_pos.y + g_medium_font->FontSize + LayoutScale(4.0f));
DrawShadowedText(dl, g_medium_font, total_pos, text_color, buffer.GetCharArray(), DrawShadowedText(dl, g_medium_font, total_pos, text_color, buffer.c_str(), buffer.end_ptr());
buffer.GetCharArray() + buffer.GetLength());
} }
} }
@ -5413,7 +5411,7 @@ void FullscreenUI::DrawResumeStateSelector()
TimeToPrintableString(&time, entry.timestamp); TimeToPrintableString(&time, entry.timestamp);
ImGui::TextWrapped( ImGui::TextWrapped(
FSUI_CSTR("A resume save state created at %s was found.\n\nDo you want to load this save and continue?"), 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 GPUTexture* image = entry.preview_texture ? entry.preview_texture.get() : GetPlaceholderTexture().get();
const float image_height = LayoutScale(250.0f); const float image_height = LayoutScale(250.0f);
@ -5692,16 +5690,11 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
GPUTexture* cover_texture = GetGameListCover(entry); GPUTexture* cover_texture = GetGameListCover(entry);
if (entry->serial.empty()) if (entry->serial.empty())
{ summary.fmt("{} - ", Settings::GetDiscRegionDisplayName(entry->region));
summary.Fmt("{} - ", Settings::GetDiscRegionDisplayName(entry->region));
}
else 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.append(Path::GetFileName(entry->path));
summary.AppendString(filename);
const ImRect image_rect( const ImRect image_rect(
CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(cover_texture->GetWidth()), CenterImage(ImRect(bb.Min, bb.Min + image_size), ImVec2(static_cast<float>(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); entry->title.c_str() + entry->title.size(), nullptr, ImVec2(0.0f, 0.0f), &title_bb);
ImGui::PopFont(); ImGui::PopFont();
if (!summary.IsEmpty()) if (!summary.empty())
{ {
ImGui::PushFont(g_medium_font); ImGui::PushFont(g_medium_font);
ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, summary.GetCharArray(), ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, summary.c_str(), summary.end_ptr(), nullptr,
summary.GetCharArray() + summary.GetLength(), nullptr, ImVec2(0.0f, 0.0f), ImVec2(0.0f, 0.0f), &summary_bb);
&summary_bb);
ImGui::PopFont(); ImGui::PopFont();
} }
@ -5832,10 +5824,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
ImGui::Text(" (%s)", GameDatabase::GetCompatibilityRatingDisplayName(selected_entry->compatibility)); ImGui::Text(" (%s)", GameDatabase::GetCompatibilityRatingDisplayName(selected_entry->compatibility));
// play time // play time
ImGui::Text(FSUI_CSTR("Time Played: %s"), ImGui::Text(FSUI_CSTR("Time Played: %s"), GameList::FormatTimespan(selected_entry->total_played_time).c_str());
GameList::FormatTimespan(selected_entry->total_played_time).GetCharArray()); ImGui::Text(FSUI_CSTR("Last Played: %s"), GameList::FormatTimestamp(selected_entry->last_played_time).c_str());
ImGui::Text(FSUI_CSTR("Last Played: %s"),
GameList::FormatTimestamp(selected_entry->last_played_time).GetCharArray());
// size // size
ImGui::Text(FSUI_CSTR("Size: %.2f MB"), static_cast<float>(selected_entry->total_size) / 1048576.0f); ImGui::Text(FSUI_CSTR("Size: %.2f MB"), static_cast<float>(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 ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
const std::string_view title( const std::string_view title(
std::string_view(entry->title).substr(0, (entry->title.length() > 31) ? 31 : std::string_view::npos)); 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::PushFont(g_medium_font);
ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, draw_title.GetCharArray(), ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, draw_title.c_str(), draw_title.end_ptr(), nullptr,
draw_title.GetCharArray() + draw_title.GetLength(), nullptr, ImVec2(0.5f, 0.0f), ImVec2(0.5f, 0.0f), &title_bb);
&title_bb);
ImGui::PopFont(); ImGui::PopFont();
if (pressed) if (pressed)
@ -6073,7 +6062,7 @@ void FullscreenUI::DrawGameListSettingsPage(const ImVec2& heading_size)
for (const auto& it : s_game_list_directories_cache) 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"))) it.second ? FSUI_CSTR("Scanning Subdirectories") : FSUI_CSTR("Not Scanning Subdirectories")))
{ {
ImGuiFullscreen::ChoiceDialogOptions options = { ImGuiFullscreen::ChoiceDialogOptions options = {
@ -6609,8 +6598,7 @@ void FullscreenUI::ProgressCallback::Redraw(bool force)
return; return;
m_last_progress_percent = percent; m_last_progress_percent = percent;
ImGuiFullscreen::UpdateBackgroundProgressDialog( ImGuiFullscreen::UpdateBackgroundProgressDialog(m_name.c_str(), m_status_text, 0, 100, percent);
m_name.c_str(), std::string(m_status_text.GetCharArray(), m_status_text.GetLength()), 0, 100, percent);
} }
void FullscreenUI::ProgressCallback::DisplayError(const char* message) void FullscreenUI::ProgressCallback::DisplayError(const char* message)

View file

@ -7,7 +7,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
class String; class SmallStringBase;
struct Settings; struct Settings;
@ -32,7 +32,7 @@ void ReturnToPreviousWindow();
void Shutdown(); void Shutdown();
void Render(); void Render();
void InvalidateCoverCache(); void InvalidateCoverCache();
void TimeToPrintableString(String* str, time_t t); void TimeToPrintableString(SmallStringBase* str, time_t t);
// Returns true if the message has been dismissed. // Returns true if the message has been dismissed.
bool DrawErrorWindow(const char* message); bool DrawErrorWindow(const char* message);

View file

@ -463,18 +463,19 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
if ((supported_controllers & BIT_FOR(supported_ctype)) == 0) if ((supported_controllers & BIT_FOR(supported_ctype)) == 0)
continue; continue;
if (!supported_controller_string.IsEmpty()) if (!supported_controller_string.empty())
supported_controller_string.AppendString(", "); supported_controller_string.append(", ");
supported_controller_string.AppendString(Settings::GetControllerTypeDisplayName(supported_ctype)); supported_controller_string.append(Settings::GetControllerTypeDisplayName(supported_ctype));
} }
Host::AddKeyedFormattedOSDMessage( Host::AddKeyedOSDMessage(
"gamedb_controller_unsupported", 30.0f, "gamedb_controller_unsupported",
TRANSLATE("OSDMessage", "Controller in port %u (%s) is not supported for %s.\nSupported controllers: " fmt::format(
"%s\nPlease configure a supported controller from the list above."), TRANSLATE_FS("OSDMessage", "Controller in port {0} ({1}) is not supported for {2}.\nSupported controllers: "
i + 1u, Settings::GetControllerTypeDisplayName(ctype), System::GetGameTitle().c_str(), "{3}\nPlease configure a supported controller from the list above."),
supported_controller_string.GetCharArray()); i + 1u, Settings::GetControllerTypeDisplayName(ctype), System::GetGameTitle(), supported_controller_string),
Host::OSD_CRITICAL_ERROR_DURATION);
} }
} }
} }

View file

@ -994,7 +994,7 @@ TinyString GameList::FormatTimestamp(std::time_t timestamp)
{ {
char buf[128]; char buf[128];
std::strftime(buf, std::size(buf), "%x", &ttime); 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 (!long_format)
{ {
if (hours >= 100) 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) 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) 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) else if (seconds > 0)
ret.Fmt(TRANSLATE_FS("GameList", "{}s"), seconds); ret.fmt(TRANSLATE_FS("GameList", "{}s"), seconds);
else else
ret = TRANSLATE_SV("GameList", "None"); ret = TRANSLATE_SV("GameList", "None");
} }
else else
{ {
if (hours > 0) if (hours > 0)
ret = fmt::format(TRANSLATE_FS("GameList", "{} hours"), hours); ret.fmt(TRANSLATE_FS("GameList", "{} hours"), hours);
else else
ret = fmt::format(TRANSLATE_FS("GameList", "{} minutes"), minutes); ret.fmt(TRANSLATE_FS("GameList", "{} minutes"), minutes);
} }
return ret; return ret;

View file

@ -8,7 +8,7 @@
#include "util/cd_image.h" #include "util/cd_image.h"
#include "common/string.h" #include "common/small_string.h"
#include <ctime> #include <ctime>
#include <functional> #include <functional>

View file

@ -180,8 +180,8 @@ bool GPU::HandleUnknownGP0Command()
SmallString dump; SmallString dump;
for (u32 i = 0; i < m_fifo.GetSize(); i++) for (u32 i = 0; i < m_fifo.GetSize(); i++)
dump.AppendFormattedString("%s0x%08X", (i > 0) ? " " : "", FifoPeek(i)); dump.append_fmt("{}{:08X}", (i > 0) ? " " : "", FifoPeek(i));
Log_ErrorPrintf("FIFO: %s", dump.GetCharArray()); Log_ErrorPrintf("FIFO: %s", dump.c_str());
m_fifo.RemoveOne(); m_fifo.RemoveOne();
EndCommand(); EndCommand();

View file

@ -5,7 +5,7 @@
#include "util/host.h" #include "util/host.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/types.h" #include "common/types.h"
#include <ctime> #include <ctime>

View file

@ -6,7 +6,9 @@
#include "host.h" #include "host.h"
Log_SetChannel(HostInterfaceProgressCallback); Log_SetChannel(HostInterfaceProgressCallback);
HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback() {} HostInterfaceProgressCallback::HostInterfaceProgressCallback() : BaseProgressCallback()
{
}
void HostInterfaceProgressCallback::PushState() void HostInterfaceProgressCallback::PushState()
{ {
@ -64,7 +66,8 @@ void HostInterfaceProgressCallback::Redraw(bool force)
return; return;
m_last_progress_percent = percent; m_last_progress_percent = percent;
Host::DisplayLoadingScreen(m_status_text, 0, static_cast<int>(m_progress_range), static_cast<int>(m_progress_value)); Host::DisplayLoadingScreen(m_status_text.c_str(), 0, static_cast<int>(m_progress_range),
static_cast<int>(m_progress_value));
} }
void HostInterfaceProgressCallback::DisplayError(const char* message) void HostInterfaceProgressCallback::DisplayError(const char* message)

View file

@ -54,7 +54,7 @@
Log_SetChannel(ImGuiManager); Log_SetChannel(ImGuiManager);
namespace 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 DrawPerformanceOverlay();
static void DrawEnhancementsOverlay(); static void DrawEnhancementsOverlay();
static void DrawInputsOverlay(); static void DrawInputsOverlay();
@ -179,12 +179,12 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/,
ImGui::TextUnformatted(message); ImGui::TextUnformatted(message);
TinyString buf; 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::SameLine();
ImGui::SetCursorPosX(width - padding_and_rounding - prog_size.x); 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::SetCursorPosY(ImGui::GetCursorPosY() + 5.0f);
ImGui::ProgressBar(static_cast<float>(progress_value) / static_cast<float>(progress_max - progress_min), ImGui::ProgressBar(static_cast<float>(progress_value) / static_cast<float>(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, // 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%, // 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. // 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) if (usage >= 99.95)
text.AppendFmtString("100% ({:.2f}ms)", time); text.append_fmt("100% ({:.2f}ms)", time);
else else
text.AppendFmtString("{:.1f}% ({:.2f}ms)", usage, time); text.append_fmt("{:.1f}% ({:.2f}ms)", usage, time);
} }
void ImGuiManager::DrawPerformanceOverlay() void ImGuiManager::DrawPerformanceOverlay()
@ -301,7 +301,7 @@ void ImGuiManager::DrawPerformanceOverlay()
dl->AddText( \ dl->AddText( \
font, font->FontSize, \ font, font->FontSize, \
ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x + shadow_offset, position_y + shadow_offset), \ 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, \ dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), color, \
(text)); \ (text)); \
position_y += text_size.y + spacing; \ position_y += text_size.y + spacing; \
@ -313,22 +313,22 @@ void ImGuiManager::DrawPerformanceOverlay()
const float speed = System::GetEmulationSpeed(); const float speed = System::GetEmulationSpeed();
if (g_settings.display_show_fps) 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; first = false;
} }
if (g_settings.display_show_speed) if (g_settings.display_show_speed)
{ {
text.AppendFmtString("{}{}%", first ? "" : " | ", static_cast<u32>(std::round(speed))); text.append_fmt("{}{}%", first ? "" : " | ", static_cast<u32>(std::round(speed)));
const float target_speed = System::GetTargetSpeed(); const float target_speed = System::GetTargetSpeed();
if (target_speed <= 0.0f) if (target_speed <= 0.0f)
text.AppendString(" (Max)"); text.append(" (Max)");
else else
text.AppendFmtString(" ({:.0f}%)", target_speed * 100.0f); text.append_fmt(" ({:.0f}%)", target_speed * 100.0f);
first = false; first = false;
} }
if (!text.IsEmpty()) if (!text.empty())
{ {
ImU32 color; ImU32 color;
if (speed < 95.0f) if (speed < 95.0f)
@ -347,65 +347,63 @@ void ImGuiManager::DrawPerformanceOverlay()
const auto [effective_width, effective_height] = g_gpu->GetEffectiveDisplayResolution(); const auto [effective_width, effective_height] = g_gpu->GetEffectiveDisplayResolution();
const bool interlaced = g_gpu->IsInterlacedDisplayEnabled(); const bool interlaced = g_gpu->IsInterlacedDisplayEnabled();
const bool pal = g_gpu->IsInPALMode(); 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"); interlaced ? "Interlaced" : "Progressive");
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
} }
if (g_settings.display_show_cpu) if (g_settings.display_show_cpu)
{ {
text.Clear(); text.fmt("{:.2f}ms | {:.2f}ms | {:.2f}ms", System::GetMinimumFrameTime(), System::GetAverageFrameTime(),
text.AppendFmtString("{:.2f}ms | {:.2f}ms | {:.2f}ms", System::GetMinimumFrameTime(), System::GetMaximumFrameTime());
System::GetAverageFrameTime(), System::GetMaximumFrameTime());
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); 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 || if (g_settings.cpu_overclock_active || (!g_settings.IsUsingRecompiler() || g_settings.cpu_recompiler_icache ||
g_settings.cpu_recompiler_memory_exceptions)) g_settings.cpu_recompiler_memory_exceptions))
{ {
first = true; first = true;
text.AppendString("CPU["); text.assign("CPU[");
if (g_settings.cpu_overclock_active) if (g_settings.cpu_overclock_active)
{ {
text.AppendFmtString("{}", g_settings.GetCPUOverclockPercent()); text.append_fmt("{}", g_settings.GetCPUOverclockPercent());
first = false; first = false;
} }
if (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter) if (g_settings.cpu_execution_mode == CPUExecutionMode::Interpreter)
{ {
text.AppendFmtString("{}{}", first ? "" : "/", "I"); text.append_fmt("{}{}", first ? "" : "/", "I");
first = false; first = false;
} }
else if (g_settings.cpu_execution_mode == CPUExecutionMode::CachedInterpreter) else if (g_settings.cpu_execution_mode == CPUExecutionMode::CachedInterpreter)
{ {
text.AppendFmtString("{}{}", first ? "" : "/", "CI"); text.append_fmt("{}{}", first ? "" : "/", "CI");
first = false; first = false;
} }
else else
{ {
if (g_settings.cpu_recompiler_icache) if (g_settings.cpu_recompiler_icache)
{ {
text.AppendFmtString("{}{}", first ? "" : "/", "IC"); text.append_fmt("{}{}", first ? "" : "/", "IC");
first = false; first = false;
} }
if (g_settings.cpu_recompiler_memory_exceptions) if (g_settings.cpu_recompiler_memory_exceptions)
{ {
text.AppendFmtString("{}{}", first ? "" : "/", "ME"); text.append_fmt("{}{}", first ? "" : "/", "ME");
first = false; first = false;
} }
} }
text.AppendString("]: "); text.append("]: ");
} }
else else
{ {
text.Assign("CPU: "); text.assign("CPU: ");
} }
FormatProcessorStat(text, System::GetCPUThreadUsage(), System::GetCPUThreadAverageTime()); FormatProcessorStat(text, System::GetCPUThreadUsage(), System::GetCPUThreadAverageTime());
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
if (g_gpu->GetSWThread()) if (g_gpu->GetSWThread())
{ {
text.Assign("SW: "); text.assign("SW: ");
FormatProcessorStat(text, System::GetSWThreadUsage(), System::GetSWThreadAverageTime()); FormatProcessorStat(text, System::GetSWThreadUsage(), System::GetSWThreadAverageTime());
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
} }
@ -414,8 +412,7 @@ void ImGuiManager::DrawPerformanceOverlay()
{ {
AudioStream* stream = g_spu.GetOutputStream(); AudioStream* stream = g_spu.GetOutputStream();
const u32 frames = stream->GetBufferedFramesRelaxed(); 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)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
} }
#endif #endif
@ -423,7 +420,7 @@ void ImGuiManager::DrawPerformanceOverlay()
if (g_settings.display_show_gpu && g_gpu_device->IsGPUTimingEnabled()) if (g_settings.display_show_gpu && g_gpu_device->IsGPUTimingEnabled())
{ {
text.Assign("GPU: "); text.assign("GPU: ");
FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime()); FormatProcessorStat(text, System::GetGPUUsage(), System::GetGPUAverageTime());
DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255)); DRAW_LINE(fixed_font, text, IM_COL32(255, 255, 255, 255));
} }
@ -433,7 +430,7 @@ void ImGuiManager::DrawPerformanceOverlay()
const bool rewinding = System::IsRewinding(); const bool rewinding = System::IsRewinding();
if (rewinding || System::IsFastForwardEnabled() || System::IsTurboEnabled()) 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)); DRAW_LINE(standard_font, text, IM_COL32(255, 255, 255, 255));
} }
} }
@ -477,25 +474,21 @@ void ImGuiManager::DrawPerformanceOverlay()
ImDrawList* win_dl = ImGui::GetCurrentWindow()->DrawList; ImDrawList* win_dl = ImGui::GetCurrentWindow()->DrawList;
const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos); const ImVec2 wpos(ImGui::GetCurrentWindow()->Pos);
text.Clear(); text.fmt("{:.1f} ms", max);
text.AppendFmtString("{:.1f} ms", max); text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.end_ptr());
text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.GetCharArray(),
text.GetCharArray() + text.GetLength());
win_dl->AddText(ImVec2(wpos.x + history_size.x - text_size.x - spacing + shadow_offset, wpos.y + shadow_offset), 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), 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.fmt("{:.1f} ms", min);
text.AppendFmtString("{:.1f} ms", min); text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.end_ptr());
text_size = fixed_font->CalcTextSizeA(fixed_font->FontSize, FLT_MAX, 0.0f, text.GetCharArray(),
text.GetCharArray() + text.GetLength());
win_dl->AddText(ImVec2(wpos.x + history_size.x - text_size.x - spacing + shadow_offset, 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), 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( win_dl->AddText(
ImVec2(wpos.x + history_size.x - text_size.x - spacing, wpos.y + history_size.y - fixed_font->FontSize), 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::PopFont();
} }
ImGui::End(); ImGui::End();
@ -506,7 +499,7 @@ void ImGuiManager::DrawPerformanceOverlay()
else if (g_settings.display_show_status_indicators && state == System::State::Paused && else if (g_settings.display_show_status_indicators && state == System::State::Paused &&
!FullscreenUI::HasActiveWindow()) !FullscreenUI::HasActiveWindow())
{ {
text.Assign(ICON_FA_PAUSE); text.assign(ICON_FA_PAUSE);
DRAW_LINE(standard_font, text, IM_COL32(255, 255, 255, 255)); DRAW_LINE(standard_font, text, IM_COL32(255, 255, 255, 255));
} }
@ -516,58 +509,57 @@ void ImGuiManager::DrawPerformanceOverlay()
void ImGuiManager::DrawEnhancementsOverlay() void ImGuiManager::DrawEnhancementsOverlay()
{ {
LargeString text; LargeString text;
text.AppendFmtString("{} {}-{}", Settings::GetConsoleRegionName(System::GetRegion()), text.append_fmt("{} {}-{}", Settings::GetConsoleRegionName(System::GetRegion()),
GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()), GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()),
g_gpu->IsHardwareRenderer() ? "HW" : "SW"); g_gpu->IsHardwareRenderer() ? "HW" : "SW");
if (g_settings.rewind_enable) 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()) 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) 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) if (g_settings.enable_8mb_ram)
text.AppendString(" 8MB"); text.append(" 8MB");
if (g_settings.cdrom_read_speedup != 1) 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) 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) 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) if (g_settings.gpu_multisamples != 1)
{ {
text.AppendFormattedString(" %ux%s", g_settings.gpu_multisamples, text.append_fmt(" {}x{}", g_settings.gpu_multisamples, g_settings.gpu_per_sample_shading ? "SSAA" : "MSAA");
g_settings.gpu_per_sample_shading ? "SSAA" : "MSAA");
} }
if (g_settings.gpu_true_color) if (g_settings.gpu_true_color)
text.AppendString(" TrueCol"); text.append(" TrueCol");
if (g_settings.gpu_disable_interlacing) if (g_settings.gpu_disable_interlacing)
text.AppendString(" ForceProg"); text.append(" ForceProg");
if (g_settings.gpu_force_ntsc_timings && System::GetRegion() == ConsoleRegion::PAL) 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) 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 && if (g_settings.gpu_widescreen_hack && g_settings.display_aspect_ratio != DisplayAspectRatio::Auto &&
g_settings.display_aspect_ratio != DisplayAspectRatio::R4_3) g_settings.display_aspect_ratio != DisplayAspectRatio::R4_3)
{ {
text.AppendString(" WSHack"); text.append(" WSHack");
} }
if (g_settings.gpu_pgxp_enable) if (g_settings.gpu_pgxp_enable)
{ {
text.AppendString(" PGXP"); text.append(" PGXP");
if (g_settings.gpu_pgxp_culling) if (g_settings.gpu_pgxp_culling)
text.AppendString("/Cull"); text.append("/Cull");
if (g_settings.gpu_pgxp_texture_correction) if (g_settings.gpu_pgxp_texture_correction)
text.AppendString("/Tex"); text.append("/Tex");
if (g_settings.gpu_pgxp_color_correction) if (g_settings.gpu_pgxp_color_correction)
text.AppendString("/Col"); text.append("/Col");
if (g_settings.gpu_pgxp_vertex_cache) if (g_settings.gpu_pgxp_vertex_cache)
text.AppendString("/VC"); text.append("/VC");
if (g_settings.gpu_pgxp_cpu) if (g_settings.gpu_pgxp_cpu)
text.AppendString("/CPU"); text.append("/CPU");
if (g_settings.gpu_pgxp_depth_buffer) if (g_settings.gpu_pgxp_depth_buffer)
text.AppendString("/Depth"); text.append("/Depth");
} }
const float scale = ImGuiManager::GetGlobalScale(); const float scale = ImGuiManager::GetGlobalScale();
@ -577,13 +569,13 @@ void ImGuiManager::DrawEnhancementsOverlay()
const float position_y = ImGui::GetIO().DisplaySize.y - margin - font->FontSize; const float position_y = ImGui::GetIO().DisplaySize.y - margin - font->FontSize;
ImDrawList* dl = ImGui::GetBackgroundDrawList(); ImDrawList* dl = ImGui::GetBackgroundDrawList();
ImVec2 text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, text, ImVec2 text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, text.c_str(),
text.GetCharArray() + text.GetLength(), nullptr); text.end_ptr(), nullptr);
dl->AddText(font, font->FontSize, dl->AddText(font, font->FontSize,
ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x + shadow_offset, position_y + shadow_offset), 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), 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() 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); 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++) for (u32 port = 0; port < NUM_CONTROLLER_AND_CARD_PORTS; port++)
{ {
@ -625,7 +617,7 @@ void ImGuiManager::DrawInputsOverlay()
if (!cinfo) if (!cinfo)
continue; continue;
text.Fmt("P{} |", port + 1u); text.fmt("P{} |", port + 1u);
for (const Controller::ControllerBindingInfo& bi : cinfo->bindings) for (const Controller::ControllerBindingInfo& bi : cinfo->bindings)
{ {
@ -637,9 +629,9 @@ void ImGuiManager::DrawInputsOverlay()
// axes are always shown // axes are always shown
const float value = controller->GetBindState(bi.bind_index); const float value = controller->GetBindState(bi.bind_index);
if (value >= (254.0f / 255.0f)) if (value >= (254.0f / 255.0f))
text.AppendFmtString(" {}", bi.name); text.append_fmt(" {}", bi.name);
else if (value > (1.0f / 255.0f)) else if (value > (1.0f / 255.0f))
text.AppendFmtString(" {}: {:.2f}", bi.name, value); text.append_fmt(" {}: {:.2f}", bi.name, value);
} }
break; break;
@ -648,7 +640,7 @@ void ImGuiManager::DrawInputsOverlay()
// buttons only shown when active // buttons only shown when active
const float value = controller->GetBindState(bi.bind_index); const float value = controller->GetBindState(bi.bind_index);
if (value >= 0.5f) if (value >= 0.5f)
text.AppendFmtString(" {}", bi.name); text.append_fmt(" {}", bi.name);
} }
break; break;
@ -662,9 +654,9 @@ void ImGuiManager::DrawInputsOverlay()
} }
dl->AddText(font, font->FontSize, ImVec2(current_x + shadow_offset, current_y + shadow_offset), shadow_color, 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); text.c_str(), text.end_ptr(), 0.0f, &clip_rect);
dl->AddText(font, font->FontSize, ImVec2(current_x, current_y), text_color, text.GetCharArray(), dl->AddText(font, font->FontSize, ImVec2(current_x, current_y), text_color, text.c_str(), text.end_ptr(), 0.0f,
text.GetCharArray() + text.GetLength(), 0.0f, &clip_rect); &clip_rect);
current_y += font->FontSize + spacing; current_y += font->FontSize + spacing;
} }

View file

@ -214,7 +214,7 @@ static bool LoadLibraryPSF(const char* path, bool use_pc_sp, u32 depth = 0)
u32 lib_counter = 2; u32 lib_counter = 2;
for (;;) 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()) if (!lib_name.has_value())
break; break;

View file

@ -101,34 +101,6 @@ bool Settings::HasAnyPerGameMemoryCards() const
}); });
} }
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> Settings::GeneratePortLabels() const
{
static constexpr std::array<std::array<bool, NUM_MULTITAPS>, static_cast<size_t>(MultitapMode::Count)>
multitap_enabled_on_port = {{{false, false}, {true, false}, {false, true}, {true, true}}};
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> labels;
u32 logical_port = 0;
for (u32 physical_port = 0; physical_port < NUM_MULTITAPS; physical_port++)
{
if (multitap_enabled_on_port[static_cast<size_t>(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) void Settings::CPUOverclockPercentToFraction(u32 percent, u32* numerator, u32* denominator)
{ {
const u32 percent_gcd = std::gcd(percent, 100); const u32 percent_gcd = std::gcd(percent, 100);

View file

@ -4,7 +4,7 @@
#pragma once #pragma once
#include "common/log.h" #include "common/log.h"
#include "common/settings_interface.h" #include "common/settings_interface.h"
#include "common/string.h" #include "common/small_string.h"
#include "types.h" #include "types.h"
#include "util/audio_stream.h" #include "util/audio_stream.h"
#include <array> #include <array>
@ -246,8 +246,6 @@ struct Settings
std::string pcdrv_root; std::string pcdrv_root;
bool pcdrv_enable_writes = false; bool pcdrv_enable_writes = false;
std::array<TinyString, NUM_CONTROLLER_AND_CARD_PORTS> GeneratePortLabels() const;
LOGLEVEL log_level = DEFAULT_LOG_LEVEL; LOGLEVEL log_level = DEFAULT_LOG_LEVEL;
std::string log_filter; std::string log_filter;
bool log_to_console = DEFAULT_LOG_TO_CONSOLE; bool log_to_console = DEFAULT_LOG_TO_CONSOLE;

View file

@ -237,7 +237,7 @@ static bool s_discord_presence_active = false;
static TinyString GetTimestampStringForFileName() static TinyString GetTimestampStringForFileName()
{ {
return TinyString::FromFmt("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr))); return TinyString::from_fmt("{:%Y-%m-%d_%H-%M-%S}", fmt::localtime(std::time(nullptr)));
} }
void System::Internal::ProcessStartup() void System::Internal::ProcessStartup()
@ -3341,25 +3341,21 @@ bool System::CheckForSBIFile(CDImage* image)
{ {
return Host::ConfirmMessage( return Host::ConfirmMessage(
"Confirm Unsupported Configuration", "Confirm Unsupported Configuration",
StringUtil::StdStringFromFormat( LargeString::from_fmt(
TRANSLATE( TRANSLATE_FS("System", "You are attempting to run a libcrypt protected game without an SBI file:\n\n{0}: "
"System", "{1}\n\nThe game will likely not run properly.\n\nPlease check the README for "
"You are attempting to run a libcrypt protected game without an SBI file:\n\n%s: %s\n\nThe game will " "instructions on how to add an SBI file.\n\nDo you wish to continue?"),
"likely not run properly.\n\nPlease check the README for instructions on how to add an SBI file.\n\nDo " s_running_game_serial, s_running_game_title));
"you wish to continue?"),
s_running_game_serial.c_str(), s_running_game_title.c_str())
.c_str());
} }
else else
{ {
Host::ReportErrorAsync( Host::ReportErrorAsync(
TRANSLATE("System", "Error"), TRANSLATE("System", "Error"),
SmallString::FromFormat( LargeString::from_fmt(
TRANSLATE("System", TRANSLATE_FS("System", "You are attempting to run a libcrypt protected game without an SBI file:\n\n{0}: "
"You are attempting to run a libcrypt protected game without an SBI file:\n\n%s: %s\n\nYour dump is " "{1}\n\nYour dump is incomplete, you must add the SBI file to run this game. \n\nThe "
"incomplete, you must add the SBI file to run this game. \n\n" "name of the SBI file must match the name of the disc image."),
"The name of the SBI file must match the name of the disc image."), s_running_game_serial, s_running_game_title));
s_running_game_serial.c_str(), s_running_game_title.c_str()));
return false; return false;
} }
} }

View file

@ -147,7 +147,7 @@ void AutoUpdaterDialog::queueGetLatestRelease()
connect(m_network_access_mgr, &QNetworkAccessManager::finished, this, &AutoUpdaterDialog::getLatestReleaseComplete); connect(m_network_access_mgr, &QNetworkAccessManager::finished, this, &AutoUpdaterDialog::getLatestReleaseComplete);
SmallString url_string; SmallString url_string;
url_string.Format(LATEST_RELEASE_URL, getCurrentUpdateTag().c_str()); url_string.format(LATEST_RELEASE_URL, getCurrentUpdateTag().c_str());
QUrl url(QUrl::fromEncoded(QByteArray(url_string))); QUrl url(QUrl::fromEncoded(QByteArray(url_string)));
QNetworkRequest request(url); QNetworkRequest request(url);

View file

@ -402,11 +402,11 @@ QString ControllerMacroEditWidget::getSummary() const
SmallString str; SmallString str;
for (const Controller::ControllerBindingInfo* bi : m_binds) for (const Controller::ControllerBindingInfo* bi : m_binds)
{ {
if (!str.IsEmpty()) if (!str.empty())
str.AppendCharacter('/'); str.append('/');
str.AppendString(bi->name); str.append(bi->name);
} }
return str.IsEmpty() ? tr("Not Configured") : QString::fromUtf8(str.GetCharArray(), str.GetLength()); return str.empty() ? tr("Not Configured") : QString::fromUtf8(str.c_str(), static_cast<int>(str.length()));
} }
void ControllerMacroEditWidget::onSetFrequencyClicked() void ControllerMacroEditWidget::onSetFrequencyClicked()

View file

@ -2,9 +2,13 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "debuggermodels.h" #include "debuggermodels.h"
#include "core/cpu_core.h" #include "core/cpu_core.h"
#include "core/cpu_core_private.h" #include "core/cpu_core_private.h"
#include "core/cpu_disasm.h" #include "core/cpu_disasm.h"
#include "common/small_string.h"
#include <QtGui/QColor> #include <QtGui/QColor>
#include <QtGui/QIcon> #include <QtGui/QIcon>
#include <QtGui/QPalette> #include <QtGui/QPalette>
@ -21,7 +25,9 @@ DebuggerCodeModel::DebuggerCodeModel(QObject* parent /*= nullptr*/) : QAbstractT
m_breakpoint_pixmap = QIcon(QStringLiteral(":/icons/media-record.png")).pixmap(QSize(12, 12)); m_breakpoint_pixmap = QIcon(QStringLiteral(":/icons/media-record.png")).pixmap(QSize(12, 12));
} }
DebuggerCodeModel::~DebuggerCodeModel() {} DebuggerCodeModel::~DebuggerCodeModel()
{
}
int DebuggerCodeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const int DebuggerCodeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{ {
@ -92,7 +98,7 @@ QVariant DebuggerCodeModel::data(const QModelIndex& index, int role /*= Qt::Disp
SmallString str; SmallString str;
CPU::DisassembleInstruction(&str, address, instruction_bits); CPU::DisassembleInstruction(&str, address, instruction_bits);
return QString::fromUtf8(str.GetCharArray(), static_cast<int>(str.GetLength())); return QString::fromUtf8(str.c_str(), static_cast<int>(str.length()));
} }
case 4: case 4:
@ -107,7 +113,7 @@ QVariant DebuggerCodeModel::data(const QModelIndex& index, int role /*= Qt::Disp
TinyString str; TinyString str;
CPU::DisassembleInstructionComment(&str, address, instruction_bits, &CPU::g_state.regs); CPU::DisassembleInstructionComment(&str, address, instruction_bits, &CPU::g_state.regs);
return QString::fromUtf8(str.GetCharArray(), static_cast<int>(str.GetLength())); return QString::fromUtf8(str.c_str(), static_cast<int>(str.length()));
} }
default: default:
@ -287,9 +293,13 @@ void DebuggerCodeModel::setBreakpointState(VirtualMemoryAddress address, bool en
} }
} }
DebuggerRegistersModel::DebuggerRegistersModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) {} DebuggerRegistersModel::DebuggerRegistersModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent)
{
}
DebuggerRegistersModel::~DebuggerRegistersModel() {} DebuggerRegistersModel::~DebuggerRegistersModel()
{
}
int DebuggerRegistersModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const int DebuggerRegistersModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{ {
@ -314,8 +324,8 @@ QVariant DebuggerRegistersModel::data(const QModelIndex& index, int role /*= Qt:
{ {
case 0: // address case 0: // address
{ {
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
return QString::fromUtf8(CPU::g_debugger_register_list[reg_index].name); return QString::fromUtf8(CPU::g_debugger_register_list[reg_index].name);
} }
break; break;
@ -372,9 +382,13 @@ void DebuggerRegistersModel::saveCurrentValues()
m_old_reg_values[i] = CPU::g_state.regs.r[i]; m_old_reg_values[i] = CPU::g_state.regs.r[i];
} }
DebuggerStackModel::DebuggerStackModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent) {} DebuggerStackModel::DebuggerStackModel(QObject* parent /*= nullptr*/) : QAbstractListModel(parent)
{
}
DebuggerStackModel::~DebuggerStackModel() {} DebuggerStackModel::~DebuggerStackModel()
{
}
int DebuggerStackModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const int DebuggerStackModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{ {

View file

@ -481,7 +481,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
static TinyString getColumnVisibilitySettingsKeyName(int column) static TinyString getColumnVisibilitySettingsKeyName(int column)
{ {
return TinyString::FromFormat("Show%s", GameListModel::getColumnName(static_cast<GameListModel::Column>(column))); return TinyString::from_fmt("Show{}", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
} }
void GameListWidget::loadTableViewColumnVisibilitySettings() void GameListWidget::loadTableViewColumnVisibilitySettings()

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "memorycardsettingswidget.h" #include "memorycardsettingswidget.h"
#include "common/string_util.h"
#include "core/controller.h" #include "core/controller.h"
#include "core/settings.h" #include "core/settings.h"
#include "inputbindingwidgets.h" #include "inputbindingwidgets.h"
@ -11,6 +11,10 @@
#include "qtutils.h" #include "qtutils.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include "settingwidgetbinder.h" #include "settingwidgetbinder.h"
#include "common/small_string.h"
#include "common/string_util.h"
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <QtWidgets/QFileDialog> #include <QtWidgets/QFileDialog>
#include <QtWidgets/QLabel> #include <QtWidgets/QLabel>
@ -168,7 +172,7 @@ void MemoryCardSettingsWidget::onBrowseMemoryCardPathClicked(int index)
void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index) void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index)
{ {
const auto key = TinyString::FromFormat("Card%dPath", index + 1); const auto key = TinyString::from_fmt("Card{}Path", index + 1);
std::string relative_path( std::string relative_path(
Path::MakeRelative(m_port_ui[index].memory_card_path->text().toStdString(), EmuFolders::MemoryCards)); Path::MakeRelative(m_port_ui[index].memory_card_path->text().toStdString(), EmuFolders::MemoryCards));
m_dialog->setStringSettingValue("MemoryCards", key, relative_path.c_str()); m_dialog->setStringSettingValue("MemoryCards", key, relative_path.c_str());
@ -176,7 +180,7 @@ void MemoryCardSettingsWidget::onMemoryCardPathChanged(int index)
void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index) void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index)
{ {
const auto key = TinyString::FromFormat("Card%dPath", index + 1); const auto key = TinyString::from_fmt("Card{}Path", index + 1);
if (m_dialog->isPerGameSettings()) if (m_dialog->isPerGameSettings())
m_dialog->removeSettingValue("MemoryCards", key); m_dialog->removeSettingValue("MemoryCards", key);
else else
@ -187,7 +191,7 @@ void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(int index)
void MemoryCardSettingsWidget::updateMemoryCardPath(int index) void MemoryCardSettingsWidget::updateMemoryCardPath(int index)
{ {
const auto key = TinyString::FromFormat("Card%dPath", index + 1); const auto key = TinyString::from_fmt("Card{}Path", index + 1);
std::string path( std::string path(
m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str())); m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str()));
if (!Path::IsAbsolute(path)) if (!Path::IsAbsolute(path))

View file

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "core/types.h" #include "core/types.h"
#include <QtWidgets/QComboBox> #include <QtWidgets/QComboBox>
#include <QtWidgets/QGroupBox> #include <QtWidgets/QGroupBox>
#include <QtWidgets/QLineEdit> #include <QtWidgets/QLineEdit>

View file

@ -128,7 +128,7 @@ void Win32ProgressCallback::Redraw(bool force)
SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range)); SendMessageA(m_progress_hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, m_progress_range));
SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast<WPARAM>(m_progress_value), 0); SendMessageA(m_progress_hwnd, PBM_SETPOS, static_cast<WPARAM>(m_progress_value), 0);
SetWindowTextA(m_text_hwnd, m_status_text); SetWindowTextA(m_text_hwnd, m_status_text.c_str());
RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE); RedrawWindow(m_text_hwnd, nullptr, nullptr, RDW_INVALIDATE);
PumpMessages(); PumpMessages();
} }

View file

@ -666,7 +666,7 @@ bool CDImagePBP::OpenDisc(u32 index, Error* error)
if (m_disc_offsets.size() > 1) if (m_disc_offsets.size() > 1)
{ {
std::string sbi_path(Path::StripExtension(m_filename)); std::string sbi_path(Path::StripExtension(m_filename));
sbi_path += TinyString::FromFormat("_%u.sbi", index + 1); sbi_path += TinyString::from_fmt("_%u.sbi", index + 1).view();
m_sbi.LoadSBI(sbi_path.c_str()); m_sbi.LoadSBI(sbi_path.c_str());
} }
else else

View file

@ -71,10 +71,10 @@ void File::SetError(u32 line_number, Error* error, const char* format, ...)
std::va_list ap; std::va_list ap;
SmallString str; SmallString str;
va_start(ap, format); va_start(ap, format);
str.FormatVA(format, ap); str.format_va(format, ap);
va_end(ap); va_end(ap);
Log_ErrorPrintf("Cue parse error at line %u: %s", line_number, str.GetCharArray()); Log_ErrorPrintf("Cue parse error at line %u: %s", line_number, str.c_str());
Error::SetString(error, fmt::format("Cue parse error at line {}: {}", line_number, str)); Error::SetString(error, fmt::format("Cue parse error at line {}: {}", line_number, str));
} }

View file

@ -17,7 +17,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "D3D12MemAlloc.h" #include "D3D12MemAlloc.h"

View file

@ -265,7 +265,7 @@ void GPUDevice::OpenShaderCache(const std::string_view& base_path, u32 version)
if (m_features.pipeline_cache) if (m_features.pipeline_cache)
{ {
const std::string pc_filename = const std::string pc_filename =
Path::Combine(base_path, TinyString::FromFmt("{}.bin", GetShaderCacheBaseName("pipelines"))); Path::Combine(base_path, TinyString::from_fmt("{}.bin", GetShaderCacheBaseName("pipelines")));
if (FileSystem::FileExists(pc_filename.c_str())) if (FileSystem::FileExists(pc_filename.c_str()))
{ {
Log_InfoPrintf("Removing old pipeline cache '%s'", pc_filename.c_str()); Log_InfoPrintf("Removing old pipeline cache '%s'", pc_filename.c_str());
@ -284,7 +284,7 @@ void GPUDevice::OpenShaderCache(const std::string_view& base_path, u32 version)
if (m_features.pipeline_cache && !base_path.empty()) if (m_features.pipeline_cache && !base_path.empty())
{ {
const std::string basename = GetShaderCacheBaseName("pipelines"); const std::string basename = GetShaderCacheBaseName("pipelines");
const std::string filename = Path::Combine(base_path, TinyString::FromFmt("{}.bin", basename)); const std::string filename = Path::Combine(base_path, TinyString::from_fmt("{}.bin", basename));
if (ReadPipelineCache(filename)) if (ReadPipelineCache(filename))
s_pipeline_cache_path = std::move(filename); s_pipeline_cache_path = std::move(filename);
else else

View file

@ -2375,12 +2375,12 @@ void ImGuiFullscreen::DrawBackgroundProgressDialogs(ImVec2& position, float spac
dl->AddRectFilled(pos, ImVec2(pos.x + fraction * (box_end.x - pos.x), box_end.y), dl->AddRectFilled(pos, ImVec2(pos.x + fraction * (box_end.x - pos.x), box_end.y),
ImGui::GetColorU32(UISecondaryColor)); ImGui::GetColorU32(UISecondaryColor));
const auto text = TinyString::FromFmt("{}%", static_cast<int>(std::round(fraction * 100.0f))); const auto text = TinyString::from_fmt("{}%", static_cast<int>(std::round(fraction * 100.0f)));
const ImVec2 text_size(ImGui::CalcTextSize(text)); const ImVec2 text_size(ImGui::CalcTextSize(text));
const ImVec2 text_pos(pos.x + ((box_end.x - pos.x) / 2.0f) - (text_size.x / 2.0f), const ImVec2 text_pos(pos.x + ((box_end.x - pos.x) / 2.0f) - (text_size.x / 2.0f),
pos.y + ((box_end.y - pos.y) / 2.0f) - (text_size.y / 2.0f)); pos.y + ((box_end.y - pos.y) / 2.0f) - (text_size.y / 2.0f));
dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, ImGui::GetColorU32(UIPrimaryTextColor), dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, ImGui::GetColorU32(UIPrimaryTextColor),
text.GetCharArray(), text.GetCharArray() + text.GetLength()); text.c_str(), text.end_ptr());
} }
else else
{ {

View file

@ -1714,9 +1714,9 @@ bool InputManager::MigrateBindings(SettingsInterface& si)
if (bnum >= std::size(button_mapping)) if (bnum >= std::size(button_mapping))
continue; continue;
new_bind.Fmt("SDL-{}/{}", cnum, button_mapping[bnum]); new_bind.fmt("SDL-{}/{}", cnum, button_mapping[bnum]);
si.SetStringValue(new_section.c_str(), new_key, new_bind); si.SetStringValue(new_section.c_str(), new_key, new_bind);
Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str());
num_changes++; num_changes++;
} }
else if (std::sscanf(old_bind.c_str(), "Controller%u/%cAxis%u", &cnum, &dir, &bnum) == 3) else if (std::sscanf(old_bind.c_str(), "Controller%u/%cAxis%u", &cnum, &dir, &bnum) == 3)
@ -1724,16 +1724,16 @@ bool InputManager::MigrateBindings(SettingsInterface& si)
if (bnum >= std::size(axis_mapping)) if (bnum >= std::size(axis_mapping))
continue; continue;
new_bind.Fmt("SDL-{}/{}{}", cnum, dir, axis_mapping[bnum]); new_bind.fmt("SDL-{}/{}{}", cnum, dir, axis_mapping[bnum]);
si.SetStringValue(new_section.c_str(), new_key, new_bind); si.SetStringValue(new_section.c_str(), new_key, new_bind);
Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str());
num_changes++; num_changes++;
} }
else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/Keypad+")) else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/Keypad+"))
{ {
new_bind.Fmt("Keyboard/Numpad{}", old_bind.substr(16)); new_bind.fmt("Keyboard/Numpad{}", old_bind.substr(16));
si.SetStringValue(new_section.c_str(), new_key, new_bind); si.SetStringValue(new_section.c_str(), new_key, new_bind);
Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str());
num_changes++; num_changes++;
} }
else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/")) else if (StringUtil::StartsWith(old_bind.c_str(), "Keyboard/"))
@ -1764,12 +1764,12 @@ bool InputManager::MigrateBindings(SettingsInterface& si)
if (bnum >= std::size(axis_mapping)) if (bnum >= std::size(axis_mapping))
continue; continue;
new_bind.Fmt("SDL-{}/-{}", cnum, axis_mapping[bnum]); new_bind.fmt("SDL-{}/-{}", cnum, axis_mapping[bnum]);
si.SetStringValue(new_section.c_str(), new_neg_key, new_bind); si.SetStringValue(new_section.c_str(), new_neg_key, new_bind);
new_bind.Fmt("SDL-{}/+{}", cnum, axis_mapping[bnum]); new_bind.fmt("SDL-{}/+{}", cnum, axis_mapping[bnum]);
si.SetStringValue(new_section.c_str(), new_pos_key, new_bind); si.SetStringValue(new_section.c_str(), new_pos_key, new_bind);
Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.GetCharArray()); Log_DevPrintf("%s -> %s", old_bind.c_str(), new_bind.c_str());
num_changes++; num_changes++;
} }
} }
@ -1780,9 +1780,9 @@ bool InputManager::MigrateBindings(SettingsInterface& si)
unsigned cnum; unsigned cnum;
if (std::sscanf(rumble_source.c_str(), "Controller%u", &cnum) == 1) if (std::sscanf(rumble_source.c_str(), "Controller%u", &cnum) == 1)
{ {
new_bind.Fmt("SDL-{}/LargeMotor", cnum); new_bind.fmt("SDL-{}/LargeMotor", cnum);
si.SetStringValue(new_section.c_str(), "LargeMotor", new_bind); si.SetStringValue(new_section.c_str(), "LargeMotor", new_bind);
new_bind.Fmt("SDL-{}/SmallMotor", cnum); new_bind.fmt("SDL-{}/SmallMotor", cnum);
si.SetStringValue(new_section.c_str(), "SmallMotor", new_bind); si.SetStringValue(new_section.c_str(), "SmallMotor", new_bind);
num_changes++; num_changes++;
} }

View file

@ -12,7 +12,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -358,7 +358,7 @@ GLuint OpenGLDevice::CompileProgram(const GPUPipeline::GraphicsConfig& plconfig)
{ {
glBindAttribLocation( glBindAttribLocation(
program_id, i, program_id, i,
TinyString::FromFmt("{}{}", semantic_vars[static_cast<u8>(va.semantic.GetValue())], va.semantic_index)); TinyString::from_fmt("{}{}", semantic_vars[static_cast<u8>(va.semantic.GetValue())], va.semantic_index));
} }
} }
@ -418,7 +418,7 @@ void OpenGLDevice::PostLinkProgram(const GPUPipeline::GraphicsConfig& plconfig,
const u32 num_textures = std::max<u32>(GetActiveTexturesForLayout(plconfig.layout), 1); const u32 num_textures = std::max<u32>(GetActiveTexturesForLayout(plconfig.layout), 1);
for (u32 i = 0; i < num_textures; i++) for (u32 i = 0; i < num_textures; i++)
{ {
location = glGetUniformLocation(program_id, TinyString::FromFmt("samp{}", i)); location = glGetUniformLocation(program_id, TinyString::from_fmt("samp{}", i));
if (location >= 0) if (location >= 0)
glUniform1i(location, i); glUniform1i(location, i);
} }

View file

@ -5,6 +5,7 @@
#include "common/types.h" #include "common/types.h"
#include "fmt/core.h"
#include "fmt/format.h" #include "fmt/format.h"
#include <array> #include <array>

View file

@ -6,7 +6,7 @@
#include "cocoa_tools.h" #include "cocoa_tools.h"
#include "common/log.h" #include "common/log.h"
#include "common/string.h" #include "common/small_string.h"
#include <IOKit/pwr_mgt/IOPMLib.h> #include <IOKit/pwr_mgt/IOPMLib.h>
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>

View file

@ -6,7 +6,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
#include "common/string.h" #include "common/small_string.h"
#include <cinttypes> #include <cinttypes>
#include <spawn.h> #include <spawn.h>

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "common/log.h" #include "common/log.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "platform_misc.h" #include "platform_misc.h"
#include <cinttypes> #include <cinttypes>

View file

@ -19,7 +19,7 @@
#include "common/file_system.h" #include "common/file_system.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
#include "common/string.h" #include "common/small_string.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/timer.h" #include "common/timer.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -120,20 +120,20 @@ TinyString PostProcessing::ValueToString(ShaderOption::Type type, u32 vector_siz
for (u32 i = 0; i < vector_size; i++) for (u32 i = 0; i < vector_size; i++)
{ {
if (i > 0) if (i > 0)
ret.AppendCharacter(','); ret.append(',');
switch (type) switch (type)
{ {
case ShaderOption::Type::Bool: case ShaderOption::Type::Bool:
ret.AppendString((value[i].int_value != 0) ? "true" : "false"); ret.append((value[i].int_value != 0) ? "true" : "false");
break; break;
case ShaderOption::Type::Int: case ShaderOption::Type::Int:
ret.AppendFmtString("{}", value[i].int_value); ret.append_fmt("{}", value[i].int_value);
break; break;
case ShaderOption::Type::Float: case ShaderOption::Type::Float:
ret.AppendFmtString("{}", value[i].float_value); ret.append_fmt("{}", value[i].float_value);
break; break;
default: default:
@ -207,7 +207,7 @@ std::vector<std::pair<std::string, std::string>> PostProcessing::GetAvailableSha
TinyString PostProcessing::GetStageConfigSection(u32 index) TinyString PostProcessing::GetStageConfigSection(u32 index)
{ {
return TinyString::FromFmt("PostProcessing/Stage{}", index + 1); return TinyString::from_fmt("PostProcessing/Stage{}", index + 1);
} }
void PostProcessing::CopyStageConfig(SettingsInterface& si, u32 old_index, u32 new_index) void PostProcessing::CopyStageConfig(SettingsInterface& si, u32 old_index, u32 new_index)

View file

@ -3,7 +3,7 @@
#include "state_wrapper.h" #include "state_wrapper.h"
#include "common/log.h" #include "common/log.h"
#include "common/string.h" #include "common/small_string.h"
#include <cinttypes> #include <cinttypes>
#include <cstring> #include <cstring>
Log_SetChannel(StateWrapper); Log_SetChannel(StateWrapper);
@ -67,14 +67,14 @@ void StateWrapper::Do(std::string* value_ptr)
value_ptr->resize(std::strlen(&(*value_ptr)[0])); value_ptr->resize(std::strlen(&(*value_ptr)[0]));
} }
void StateWrapper::Do(String* value_ptr) void StateWrapper::Do(SmallStringBase* value_ptr)
{ {
u32 length = static_cast<u32>(value_ptr->GetLength()); u32 length = static_cast<u32>(value_ptr->length());
Do(&length); Do(&length);
if (m_mode == Mode::Read) if (m_mode == Mode::Read)
value_ptr->Resize(length); value_ptr->resize(length);
DoBytes(value_ptr->GetWriteableCharArray(), length); DoBytes(value_ptr->data(), length);
value_ptr->UpdateSize(); value_ptr->update_size();
} }
bool StateWrapper::DoMarker(const char* marker) bool StateWrapper::DoMarker(const char* marker)
@ -84,11 +84,11 @@ bool StateWrapper::DoMarker(const char* marker)
if (m_error) if (m_error)
return false; return false;
if (m_mode == Mode::Write || file_value.Compare(marker)) if (m_mode == Mode::Write || file_value.equals(marker))
return true; return true;
Log_ErrorPrintf("Marker mismatch at offset %" PRIu64 ": found '%s' expected '%s'", m_stream->GetPosition(), Log_ErrorPrintf("Marker mismatch at offset %" PRIu64 ": found '%s' expected '%s'", m_stream->GetPosition(),
file_value.GetCharArray(), marker); file_value.c_str(), marker);
return false; return false;
} }

View file

@ -12,7 +12,7 @@
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
class String; class SmallStringBase;
class StateWrapper class StateWrapper
{ {
@ -108,7 +108,7 @@ public:
void Do(bool* value_ptr); void Do(bool* value_ptr);
void Do(std::string* value_ptr); void Do(std::string* value_ptr);
void Do(String* value_ptr); void Do(SmallStringBase* value_ptr);
template<typename T, size_t N> template<typename T, size_t N>
void Do(std::array<T, N>* data) void Do(std::array<T, N>* data)

View file

@ -17,7 +17,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
#include "common/scoped_guard.h" #include "common/scoped_guard.h"
#include "common/string.h" #include "common/small_string.h"
#include "fmt/format.h" #include "fmt/format.h"
@ -662,7 +662,7 @@ bool VulkanDevice::CreateCommandBuffers()
LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: "); LOG_VULKAN_ERROR(res, "vkCreateCommandPool failed: ");
return false; return false;
} }
Vulkan::SetObjectName(m_device, resources.command_pool, TinyString::FromFmt("Frame Command Pool {}", frame_index)); Vulkan::SetObjectName(m_device, resources.command_pool, TinyString::from_fmt("Frame Command Pool {}", frame_index));
VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, VkCommandBufferAllocateInfo buffer_info = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr,
resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, resources.command_pool, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
@ -677,7 +677,7 @@ bool VulkanDevice::CreateCommandBuffers()
for (u32 i = 0; i < resources.command_buffers.size(); i++) for (u32 i = 0; i < resources.command_buffers.size(); i++)
{ {
Vulkan::SetObjectName(m_device, resources.command_buffers[i], Vulkan::SetObjectName(m_device, resources.command_buffers[i],
TinyString::FromFmt("Frame {} {}Command Buffer", frame_index, (i == 0) ? "Init" : "")); TinyString::from_fmt("Frame {} {}Command Buffer", frame_index, (i == 0) ? "Init" : ""));
} }
VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT}; VkFenceCreateInfo fence_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT};
@ -688,7 +688,7 @@ bool VulkanDevice::CreateCommandBuffers()
LOG_VULKAN_ERROR(res, "vkCreateFence failed: "); LOG_VULKAN_ERROR(res, "vkCreateFence failed: ");
return false; return false;
} }
Vulkan::SetObjectName(m_device, resources.fence, TinyString::FromFmt("Frame Fence {}", frame_index)); Vulkan::SetObjectName(m_device, resources.fence, TinyString::from_fmt("Frame Fence {}", frame_index));
if (!m_optional_extensions.vk_khr_push_descriptor) if (!m_optional_extensions.vk_khr_push_descriptor)
{ {
@ -707,7 +707,7 @@ bool VulkanDevice::CreateCommandBuffers()
return false; return false;
} }
Vulkan::SetObjectName(m_device, resources.descriptor_pool, Vulkan::SetObjectName(m_device, resources.descriptor_pool,
TinyString::FromFmt("Frame Descriptor Pool {}", frame_index)); TinyString::from_fmt("Frame Descriptor Pool {}", frame_index));
} }
++frame_index; ++frame_index;