mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 23:25:41 +00:00
SmallString: Tidy-up and add wide string helpers
This commit is contained in:
parent
b02d3592dd
commit
8a3dbbbea5
|
@ -1,20 +1,17 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 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 PolyForm-Strict-1.0.0)
|
||||||
|
|
||||||
#include "small_string.h"
|
#include "small_string.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "string_util.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _WIN32
|
||||||
#define CASE_COMPARE _stricmp
|
#include "windows_headers.h"
|
||||||
#define CASE_N_COMPARE _strnicmp
|
|
||||||
#else
|
|
||||||
#define CASE_COMPARE strcasecmp
|
|
||||||
#define CASE_N_COMPARE strncasecmp
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SmallStringBase::SmallStringBase() = default;
|
SmallStringBase::SmallStringBase() = default;
|
||||||
|
@ -443,6 +440,36 @@ void SmallStringBase::assign(const std::string_view str)
|
||||||
append(str.data(), static_cast<u32>(str.size()));
|
append(str.data(), static_cast<u32>(str.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
void SmallStringBase::assign(const std::wstring_view wstr)
|
||||||
|
{
|
||||||
|
int mblen =
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.length()), nullptr, 0, nullptr, nullptr);
|
||||||
|
if (mblen < 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reserve(static_cast<u32>(mblen));
|
||||||
|
if (mblen > 0 && WideCharToMultiByte(CP_UTF8, 0, wstr.data(), static_cast<int>(wstr.length()), m_buffer, mblen,
|
||||||
|
nullptr, nullptr) < 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_length = static_cast<u32>(mblen);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring SmallStringBase::wstring() const
|
||||||
|
{
|
||||||
|
return StringUtil::UTF8StringToWideString(view());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void SmallStringBase::vformat(fmt::string_view fmt, fmt::format_args args)
|
void SmallStringBase::vformat(fmt::string_view fmt, fmt::format_args args)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
@ -479,7 +506,7 @@ bool SmallStringBase::iequals(const char* otherText) const
|
||||||
if (m_length == 0)
|
if (m_length == 0)
|
||||||
return (std::strlen(otherText) == 0);
|
return (std::strlen(otherText) == 0);
|
||||||
else
|
else
|
||||||
return (CASE_COMPARE(m_buffer, otherText) == 0);
|
return StringUtil::EqualNoCase(view(), otherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::iequals(const SmallStringBase& str) const
|
bool SmallStringBase::iequals(const SmallStringBase& str) const
|
||||||
|
@ -490,13 +517,13 @@ bool SmallStringBase::iequals(const SmallStringBase& str) const
|
||||||
bool SmallStringBase::iequals(const std::string_view str) const
|
bool SmallStringBase::iequals(const std::string_view str) const
|
||||||
{
|
{
|
||||||
return (m_length == static_cast<u32>(str.length()) &&
|
return (m_length == static_cast<u32>(str.length()) &&
|
||||||
(m_length == 0 || CASE_N_COMPARE(m_buffer, str.data(), m_length) == 0));
|
(m_length == 0 || StringUtil::Strncasecmp(m_buffer, str.data(), m_length) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::iequals(const std::string& str) const
|
bool SmallStringBase::iequals(const std::string& str) const
|
||||||
{
|
{
|
||||||
return (m_length == static_cast<u32>(str.length()) &&
|
return (m_length == static_cast<u32>(str.length()) &&
|
||||||
(m_length == 0 || CASE_N_COMPARE(m_buffer, str.data(), m_length) == 0));
|
(m_length == 0 || StringUtil::Strncasecmp(m_buffer, str.data(), m_length) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int SmallStringBase::compare(const char* otherText) const
|
int SmallStringBase::compare(const char* otherText) const
|
||||||
|
@ -560,7 +587,7 @@ int SmallStringBase::icompare(const SmallStringBase& str) const
|
||||||
else if (str.m_length == 0)
|
else if (str.m_length == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
const int res = CASE_N_COMPARE(m_buffer, str.m_buffer, std::min(m_length, str.m_length));
|
const int res = StringUtil::Strncasecmp(m_buffer, str.m_buffer, std::min(m_length, str.m_length));
|
||||||
if (m_length == str.m_length || res != 0)
|
if (m_length == str.m_length || res != 0)
|
||||||
return res;
|
return res;
|
||||||
else
|
else
|
||||||
|
@ -575,7 +602,7 @@ int SmallStringBase::icompare(const std::string_view str) const
|
||||||
else if (slength == 0)
|
else if (slength == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
const int res = CASE_N_COMPARE(m_buffer, str.data(), std::min(m_length, slength));
|
const int res = StringUtil::Strncasecmp(m_buffer, str.data(), std::min(m_length, slength));
|
||||||
if (m_length == slength || res != 0)
|
if (m_length == slength || res != 0)
|
||||||
return res;
|
return res;
|
||||||
else
|
else
|
||||||
|
@ -590,7 +617,7 @@ int SmallStringBase::icompare(const std::string& str) const
|
||||||
else if (slength == 0)
|
else if (slength == 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
const int res = CASE_N_COMPARE(m_buffer, str.data(), std::min(m_length, slength));
|
const int res = StringUtil::Strncasecmp(m_buffer, str.data(), std::min(m_length, slength));
|
||||||
if (m_length == slength || res != 0)
|
if (m_length == slength || res != 0)
|
||||||
return res;
|
return res;
|
||||||
else
|
else
|
||||||
|
@ -604,7 +631,7 @@ bool SmallStringBase::starts_with(const char* str, bool case_sensitive) const
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (case_sensitive) ? (std::strncmp(str, m_buffer, other_length) == 0) :
|
return (case_sensitive) ? (std::strncmp(str, m_buffer, other_length) == 0) :
|
||||||
(CASE_N_COMPARE(str, m_buffer, other_length) == 0);
|
(StringUtil::Strncasecmp(str, m_buffer, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitive) const
|
bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitive) const
|
||||||
|
@ -614,7 +641,7 @@ bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitiv
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer, other_length) == 0) :
|
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer, other_length) == 0) :
|
||||||
(CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0);
|
(StringUtil::Strncasecmp(str.m_buffer, m_buffer, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitive) const
|
bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitive) const
|
||||||
|
@ -624,7 +651,7 @@ bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitiv
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
||||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
(StringUtil::Strncasecmp(str.data(), m_buffer, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) const
|
bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) const
|
||||||
|
@ -634,7 +661,7 @@ bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) c
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
|
||||||
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
|
(StringUtil::Strncasecmp(str.data(), m_buffer, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
|
bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
|
||||||
|
@ -645,7 +672,7 @@ bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
|
||||||
|
|
||||||
u32 start_offset = m_length - other_length;
|
u32 start_offset = m_length - other_length;
|
||||||
return (case_sensitive) ? (std::strncmp(str, m_buffer + start_offset, other_length) == 0) :
|
return (case_sensitive) ? (std::strncmp(str, m_buffer + start_offset, other_length) == 0) :
|
||||||
(CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0);
|
(StringUtil::Strncasecmp(str, m_buffer + start_offset, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive) const
|
bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive) const
|
||||||
|
@ -656,7 +683,7 @@ bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive)
|
||||||
|
|
||||||
const u32 start_offset = m_length - other_length;
|
const u32 start_offset = m_length - other_length;
|
||||||
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer + start_offset, other_length) == 0) :
|
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);
|
(StringUtil::Strncasecmp(str.m_buffer, m_buffer + start_offset, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive) const
|
bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive) const
|
||||||
|
@ -667,7 +694,7 @@ bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive)
|
||||||
|
|
||||||
const u32 start_offset = m_length - other_length;
|
const u32 start_offset = m_length - other_length;
|
||||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
|
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);
|
(StringUtil::Strncasecmp(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) const
|
bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) const
|
||||||
|
@ -678,7 +705,7 @@ bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) con
|
||||||
|
|
||||||
const u32 start_offset = m_length - other_length;
|
const u32 start_offset = m_length - other_length;
|
||||||
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
|
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);
|
(StringUtil::Strncasecmp(str.data(), m_buffer + start_offset, other_length) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmallStringBase::clear()
|
void SmallStringBase::clear()
|
||||||
|
@ -732,6 +759,45 @@ u32 SmallStringBase::count(char ch) const
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 SmallStringBase::replace(const char* search, const char* replacement)
|
||||||
|
{
|
||||||
|
const u32 search_length = static_cast<u32>(std::strlen(search));
|
||||||
|
const u32 replacement_length = static_cast<u32>(std::strlen(replacement));
|
||||||
|
|
||||||
|
s32 offset = 0;
|
||||||
|
u32 count = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
offset = find(search, static_cast<u32>(offset));
|
||||||
|
if (offset < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const u32 new_length = m_length - search_length + replacement_length;
|
||||||
|
reserve(new_length);
|
||||||
|
m_length = new_length;
|
||||||
|
|
||||||
|
const u32 chars_after_offset = (m_length - static_cast<u32>(offset));
|
||||||
|
DebugAssert(chars_after_offset >= search_length);
|
||||||
|
if (chars_after_offset > search_length)
|
||||||
|
{
|
||||||
|
std::memmove(&m_buffer[static_cast<u32>(offset) + replacement_length],
|
||||||
|
&m_buffer[static_cast<u32>(offset) + search_length], chars_after_offset - search_length);
|
||||||
|
std::memcpy(&m_buffer[static_cast<u32>(offset)], replacement, replacement_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// at end of string
|
||||||
|
std::memcpy(&m_buffer[static_cast<u32>(offset)], replacement, replacement_length);
|
||||||
|
m_buffer[static_cast<u32>(offset) + replacement_length] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += replacement_length;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
void SmallStringBase::resize(u32 new_size, char fill, bool shrink_if_smaller)
|
void SmallStringBase::resize(u32 new_size, char fill, bool shrink_if_smaller)
|
||||||
{
|
{
|
||||||
// if going larger, or we don't own the buffer, realloc
|
// if going larger, or we don't own the buffer, realloc
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 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 PolyForm-Strict-1.0.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
@ -144,6 +144,9 @@ public:
|
||||||
// returns the number of instances of the specified character
|
// returns the number of instances of the specified character
|
||||||
u32 count(char ch) const;
|
u32 count(char ch) const;
|
||||||
|
|
||||||
|
// replaces search string with replacement, returns the number of replacements made
|
||||||
|
u32 replace(const char* search, const char* replacement);
|
||||||
|
|
||||||
// removes characters from string
|
// removes characters from string
|
||||||
void erase(s32 offset, s32 count = std::numeric_limits<s32>::max());
|
void erase(s32 offset, s32 count = std::numeric_limits<s32>::max());
|
||||||
|
|
||||||
|
@ -189,6 +192,12 @@ public:
|
||||||
// returns a substring view for this string
|
// returns a substring view for this string
|
||||||
std::string_view substr(s32 offset, s32 count) const;
|
std::string_view substr(s32 offset, s32 count) const;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// wide string adapters, win32 only
|
||||||
|
void assign(const std::wstring_view wstr);
|
||||||
|
std::wstring wstring() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
// accessor operators
|
// accessor operators
|
||||||
ALWAYS_INLINE operator const char*() const { return c_str(); }
|
ALWAYS_INLINE operator const char*() const { return c_str(); }
|
||||||
ALWAYS_INLINE operator char*() { return data(); }
|
ALWAYS_INLINE operator char*() { return data(); }
|
||||||
|
|
Loading…
Reference in a new issue