mirror of https://github.com/PCSX2/pcsx2.git
425 lines
12 KiB
C++
425 lines
12 KiB
C++
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: LGPL-3.0+
|
|
|
|
#pragma once
|
|
|
|
#include "Pcsx2Defs.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_sprintf(const char* format, ...) /*printflike(2, 3)*/;
|
|
void append_vsprintf(const char* format, va_list ap);
|
|
|
|
template <typename... T>
|
|
void append_format(fmt::format_string<T...> fmt, T&&... args);
|
|
|
|
// append hex string
|
|
void append_hex(const void* data, size_t len);
|
|
|
|
// 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_sprintf(const char* format, ...) /*printflike(2, 3)*/;
|
|
void prepend_vsprintf(const char* format, va_list ap);
|
|
|
|
template <typename... T>
|
|
void prepend_format(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 sprintf(const char* format, ...) /*printflike(2, 3)*/;
|
|
void vsprintf(const char* format, va_list ap);
|
|
|
|
template <typename... T>
|
|
void format(fmt::format_string<T...> fmt, T&&... args);
|
|
|
|
void vformat(fmt::string_view fmt, fmt::format_args 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 equals(const std::string& str) const;
|
|
bool iequals(const char* str) const;
|
|
bool iequals(const SmallStringBase& str) const;
|
|
bool iequals(const std::string_view str) const;
|
|
bool iequals(const std::string& 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 compare(const std::string& str) const;
|
|
int icompare(const char* str) const;
|
|
int icompare(const SmallStringBase& str) const;
|
|
int icompare(const std::string_view str) const;
|
|
int icompare(const std::string& str) const;
|
|
|
|
// starts with / ends with
|
|
bool starts_with(const char* str, bool case_sensitive = true) const;
|
|
bool starts_with(const SmallStringBase& str, bool case_sensitive = true) const;
|
|
bool starts_with(const std::string_view str, bool case_sensitive = true) const;
|
|
bool starts_with(const std::string& str, bool case_sensitive = true) const;
|
|
bool ends_with(const char* str, bool case_sensitive = true) const;
|
|
bool ends_with(const SmallStringBase& str, bool case_sensitive = true) const;
|
|
bool ends_with(const std::string_view str, bool case_sensitive = true) const;
|
|
bool ends_with(const std::string& 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;
|
|
|
|
// returns the number of instances of the specified character
|
|
u32 count(char ch) 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
|
|
__fi u32 length() const { return m_length; }
|
|
__fi bool empty() const { return (m_length == 0); }
|
|
|
|
// gets the maximum number of bytes we can write to the string, currently
|
|
__fi u32 buffer_size() const { return m_buffer_size; }
|
|
|
|
// gets a constant pointer to the C string
|
|
__fi const char* c_str() const { return m_buffer; }
|
|
|
|
// gets a writable char array, do not write more than reserve characters to it.
|
|
__fi char* data() { return m_buffer; }
|
|
|
|
// returns the end of the string (pointer is past the last character)
|
|
__fi const char* end_ptr() const { return m_buffer + m_length; }
|
|
|
|
// STL adapters
|
|
__fi 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
|
|
__fi operator const char*() const { return c_str(); }
|
|
__fi operator char*() { return data(); }
|
|
__fi operator std::string_view() const { return view(); }
|
|
|
|
// comparative operators
|
|
__fi bool operator==(const char* str) const { return equals(str); }
|
|
__fi bool operator==(const SmallStringBase& str) const { return equals(str); }
|
|
__fi bool operator==(const std::string_view str) const { return equals(str); }
|
|
__fi bool operator==(const std::string& str) const { return equals(str); }
|
|
__fi bool operator!=(const char* str) const { return !equals(str); }
|
|
__fi bool operator!=(const SmallStringBase& str) const { return !equals(str); }
|
|
__fi bool operator!=(const std::string_view str) const { return !equals(str); }
|
|
__fi bool operator!=(const std::string& str) const { return !equals(str); }
|
|
__fi bool operator<(const char* str) const { return (compare(str) < 0); }
|
|
__fi bool operator<(const SmallStringBase& str) const { return (compare(str) < 0); }
|
|
__fi bool operator<(const std::string_view str) const { return (compare(str) < 0); }
|
|
__fi bool operator<(const std::string& str) const { return (compare(str) < 0); }
|
|
__fi bool operator>(const char* str) const { return (compare(str) > 0); }
|
|
__fi bool operator>(const SmallStringBase& str) const { return (compare(str) > 0); }
|
|
__fi bool operator>(const std::string_view str) const { return (compare(str) > 0); }
|
|
__fi bool operator>(const std::string& 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:
|
|
__fi SmallStackString() { init(); }
|
|
|
|
__fi SmallStackString(const char* str)
|
|
{
|
|
init();
|
|
assign(str);
|
|
}
|
|
|
|
__fi SmallStackString(const char* str, u32 length)
|
|
{
|
|
init();
|
|
assign(str, length);
|
|
}
|
|
|
|
__fi SmallStackString(const SmallStringBase& copy)
|
|
{
|
|
init();
|
|
assign(copy);
|
|
}
|
|
|
|
__fi SmallStackString(SmallStringBase&& move)
|
|
{
|
|
init();
|
|
assign(move);
|
|
}
|
|
|
|
__fi SmallStackString(const SmallStackString& copy)
|
|
{
|
|
init();
|
|
assign(copy);
|
|
}
|
|
|
|
__fi SmallStackString(SmallStackString&& move)
|
|
{
|
|
init();
|
|
assign(move);
|
|
}
|
|
|
|
__fi SmallStackString(const std::string_view sv)
|
|
{
|
|
init();
|
|
assign(sv);
|
|
}
|
|
|
|
__fi SmallStackString& operator=(const SmallStringBase& copy)
|
|
{
|
|
assign(copy);
|
|
return *this;
|
|
}
|
|
|
|
__fi SmallStackString& operator=(SmallStringBase&& move)
|
|
{
|
|
assign(move);
|
|
return *this;
|
|
}
|
|
|
|
__fi SmallStackString& operator=(const SmallStackString& copy)
|
|
{
|
|
assign(copy);
|
|
return *this;
|
|
}
|
|
|
|
__fi SmallStackString& operator=(SmallStackString&& move)
|
|
{
|
|
assign(move);
|
|
return *this;
|
|
}
|
|
|
|
__fi SmallStackString& operator=(const std::string_view sv)
|
|
{
|
|
assign(sv);
|
|
return *this;
|
|
}
|
|
|
|
__fi SmallStackString& operator=(const char* str)
|
|
{
|
|
assign(str);
|
|
return *this;
|
|
}
|
|
|
|
// Override the fromstring method
|
|
static SmallStackString from_sprintf(const char* format, ...) /*printflike(1, 2)*/;
|
|
|
|
template <typename... T>
|
|
static SmallStackString from_format(fmt::format_string<T...> fmt, T&&... args);
|
|
|
|
static SmallStackString from_vformat(fmt::string_view fmt, fmt::format_args args);
|
|
|
|
private:
|
|
char m_stack_buffer[L + 1];
|
|
|
|
__fi 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>
|
|
__fi SmallStackString<L> SmallStackString<L>::from_sprintf(const char* format, ...)
|
|
{
|
|
std::va_list ap;
|
|
va_start(ap, format);
|
|
|
|
SmallStackString ret;
|
|
ret.vsprintf(format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
template <u32 L>
|
|
template <typename... T>
|
|
__fi SmallStackString<L> SmallStackString<L>::from_format(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;
|
|
}
|
|
|
|
template <u32 L>
|
|
__fi SmallStackString<L> SmallStackString<L>::from_vformat(fmt::string_view fmt, fmt::format_args args)
|
|
{
|
|
SmallStackString<L> ret;
|
|
fmt::vformat_to(std::back_inserter(ret), fmt, args);
|
|
return ret;
|
|
}
|
|
|
|
// stack string types
|
|
using TinyString = SmallStackString<64>;
|
|
using SmallString = SmallStackString<256>;
|
|
|
|
template <typename... T>
|
|
__fi void SmallStringBase::append_format(fmt::format_string<T...> fmt, T&&... args)
|
|
{
|
|
fmt::vformat_to(std::back_inserter(*this), fmt, fmt::make_format_args(args...));
|
|
}
|
|
|
|
template <typename... T>
|
|
__fi void SmallStringBase::prepend_format(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>
|
|
__fi void SmallStringBase::format(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
|
|
|
|
#define MAKE_FORMATTER(type) \
|
|
template <> \
|
|
struct fmt::formatter<type> \
|
|
{ \
|
|
template <typename ParseContext> \
|
|
constexpr auto parse(ParseContext& ctx) \
|
|
{ \
|
|
return ctx.begin(); \
|
|
} \
|
|
\
|
|
template <typename FormatContext> \
|
|
auto format(const type& str, FormatContext& ctx) \
|
|
{ \
|
|
return fmt::format_to(ctx.out(), "{}", str.view()); \
|
|
} \
|
|
};
|
|
|
|
MAKE_FORMATTER(TinyString);
|
|
MAKE_FORMATTER(SmallString);
|
|
|
|
#undef MAKE_FORMATTER |