mirror of
https://github.com/stenzek/duckstation.git
synced 2026-02-04 05:04:33 +00:00
StringUtil: Move most non-template functions to source file
This commit is contained in:
@@ -140,12 +140,6 @@ std::size_t StringUtil::Strlcpy(char* dst, const char* src, std::size_t size)
|
||||
return len;
|
||||
}
|
||||
|
||||
std::size_t StringUtil::Strnlen(const char* str, std::size_t max_size)
|
||||
{
|
||||
const char* loc = static_cast<const char*>(std::memchr(str, 0, max_size));
|
||||
return loc ? static_cast<size_t>(loc - str) : max_size;
|
||||
}
|
||||
|
||||
std::size_t StringUtil::Strlcpy(char* dst, const std::string_view src, std::size_t size)
|
||||
{
|
||||
std::size_t len = src.length();
|
||||
@@ -162,6 +156,57 @@ std::size_t StringUtil::Strlcpy(char* dst, const std::string_view src, std::size
|
||||
return len;
|
||||
}
|
||||
|
||||
std::size_t StringUtil::Strnlen(const char* str, std::size_t max_size)
|
||||
{
|
||||
const char* loc = static_cast<const char*>(std::memchr(str, 0, max_size));
|
||||
return loc ? static_cast<size_t>(loc - str) : max_size;
|
||||
}
|
||||
|
||||
int StringUtil::Strcasecmp(const char* s1, const char* s2)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _stricmp(s1, s2);
|
||||
#else
|
||||
return strcasecmp(s1, s2);
|
||||
#endif
|
||||
}
|
||||
|
||||
int StringUtil::Strncasecmp(const char* s1, const char* s2, std::size_t n)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _strnicmp(s1, s2, n);
|
||||
#else
|
||||
return strncasecmp(s1, s2, n);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool StringUtil::EqualNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
const size_t s1_len = s1.length();
|
||||
const size_t s2_len = s2.length();
|
||||
if (s1_len != s2_len)
|
||||
return false;
|
||||
else if (s1_len == 0)
|
||||
return true;
|
||||
|
||||
return (Strncasecmp(s1.data(), s2.data(), s1_len) == 0);
|
||||
}
|
||||
|
||||
int StringUtil::CompareNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
const size_t s1_len = s1.length();
|
||||
const size_t s2_len = s2.length();
|
||||
const size_t compare_len = std::min(s1_len, s2_len);
|
||||
const int compare_res = (compare_len > 0) ? Strncasecmp(s1.data(), s2.data(), compare_len) : 0;
|
||||
return (compare_res != 0) ? compare_res : ((s1_len < s2_len) ? -1 : ((s1_len > s2_len) ? 1 : 0));
|
||||
}
|
||||
|
||||
bool StringUtil::ContainsNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
return (std::search(s1.begin(), s1.end(), s2.begin(), s2.end(),
|
||||
[](char lhs, char rhs) { return (ToLower(lhs) == ToLower(rhs)); }) != s1.end());
|
||||
}
|
||||
|
||||
std::string StringUtil::StripControlCharacters(std::string_view str)
|
||||
{
|
||||
std::string out;
|
||||
@@ -335,6 +380,18 @@ std::string StringUtil::EncodeBase64(const std::span<u8> data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool StringUtil::StartsWithNoCase(const std::string_view str, const std::string_view prefix)
|
||||
{
|
||||
return (!str.empty() && Strncasecmp(str.data(), prefix.data(), prefix.length()) == 0);
|
||||
}
|
||||
|
||||
bool StringUtil::EndsWithNoCase(const std::string_view str, const std::string_view suffix)
|
||||
{
|
||||
const std::size_t suffix_length = suffix.length();
|
||||
return (str.length() >= suffix_length &&
|
||||
Strncasecmp(str.data() + (str.length() - suffix_length), suffix.data(), suffix_length) == 0);
|
||||
}
|
||||
|
||||
size_t StringUtil::CountChar(const std::string_view str, char ch)
|
||||
{
|
||||
return std::count(str.begin(), str.end(), ch);
|
||||
@@ -488,6 +545,18 @@ bool StringUtil::ParseAssignmentString(const std::string_view str, std::string_v
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::string_view> StringUtil::GetNextToken(std::string_view& caret, char separator)
|
||||
{
|
||||
std::optional<std::string_view> ret;
|
||||
const std::string_view::size_type pos = caret.find(separator);
|
||||
if (pos != std::string_view::npos)
|
||||
{
|
||||
ret = caret.substr(0, pos);
|
||||
caret = caret.substr(pos + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t StringUtil::GetUTF8CharacterCount(const std::string_view str)
|
||||
{
|
||||
size_t count = 0;
|
||||
@@ -905,6 +974,45 @@ std::optional<size_t> StringUtil::BytePatternSearch(const std::span<const u8> by
|
||||
return ret;
|
||||
}
|
||||
|
||||
void StringUtil::StrideMemCpy(void* dst, std::size_t dst_stride, const void* src, std::size_t src_stride,
|
||||
std::size_t copy_size, std::size_t count)
|
||||
{
|
||||
if (src_stride == dst_stride && src_stride == copy_size)
|
||||
{
|
||||
std::memcpy(dst, src, src_stride * count);
|
||||
return;
|
||||
}
|
||||
|
||||
const u8* src_ptr = static_cast<const u8*>(src);
|
||||
u8* dst_ptr = static_cast<u8*>(dst);
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
{
|
||||
std::memcpy(dst_ptr, src_ptr, copy_size);
|
||||
src_ptr += src_stride;
|
||||
dst_ptr += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
int StringUtil::StrideMemCmp(const void* p1, std::size_t p1_stride, const void* p2, std::size_t p2_stride,
|
||||
std::size_t copy_size, std::size_t count)
|
||||
{
|
||||
if (p1_stride == p2_stride && p1_stride == copy_size)
|
||||
return std::memcmp(p1, p2, p1_stride * count);
|
||||
|
||||
const u8* p1_ptr = static_cast<const u8*>(p1);
|
||||
const u8* p2_ptr = static_cast<const u8*>(p2);
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
{
|
||||
int result = std::memcmp(p1_ptr, p2_ptr, copy_size);
|
||||
if (result != 0)
|
||||
return result;
|
||||
p2_ptr += p2_stride;
|
||||
p1_ptr += p1_stride;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t StringUtil::DecodeUTF8(const std::string_view str, size_t offset, char32_t* ch)
|
||||
{
|
||||
return DecodeUTF8(str.data() + offset, str.length() - offset, ch);
|
||||
|
||||
@@ -52,50 +52,15 @@ std::size_t Strlcpy(char* dst, const std::string_view src, std::size_t size);
|
||||
std::size_t Strnlen(const char* str, std::size_t max_size);
|
||||
|
||||
/// Platform-independent strcasecmp
|
||||
inline int Strcasecmp(const char* s1, const char* s2)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _stricmp(s1, s2);
|
||||
#else
|
||||
return strcasecmp(s1, s2);
|
||||
#endif
|
||||
}
|
||||
int Strcasecmp(const char* s1, const char* s2);
|
||||
|
||||
/// Platform-independent strcasecmp
|
||||
inline int Strncasecmp(const char* s1, const char* s2, std::size_t n)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
return _strnicmp(s1, s2, n);
|
||||
#else
|
||||
return strncasecmp(s1, s2, n);
|
||||
#endif
|
||||
}
|
||||
int Strncasecmp(const char* s1, const char* s2, std::size_t n);
|
||||
|
||||
// Case-insensitive equality of string views.
|
||||
inline bool EqualNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
const size_t s1_len = s1.length();
|
||||
const size_t s2_len = s2.length();
|
||||
if (s1_len != s2_len)
|
||||
return false;
|
||||
else if (s1_len == 0)
|
||||
return true;
|
||||
|
||||
return (Strncasecmp(s1.data(), s2.data(), s1_len) == 0);
|
||||
}
|
||||
inline int CompareNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
const size_t s1_len = s1.length();
|
||||
const size_t s2_len = s2.length();
|
||||
const size_t compare_len = std::min(s1_len, s2_len);
|
||||
const int compare_res = (compare_len > 0) ? Strncasecmp(s1.data(), s2.data(), compare_len) : 0;
|
||||
return (compare_res != 0) ? compare_res : ((s1_len < s2_len) ? -1 : ((s1_len > s2_len) ? 1 : 0));
|
||||
}
|
||||
inline bool ContainsNoCase(std::string_view s1, std::string_view s2)
|
||||
{
|
||||
return (std::search(s1.begin(), s1.end(), s2.begin(), s2.end(),
|
||||
[](char lhs, char rhs) { return (ToLower(lhs) == ToLower(rhs)); }) != s1.end());
|
||||
}
|
||||
bool EqualNoCase(std::string_view s1, std::string_view s2);
|
||||
int CompareNoCase(std::string_view s1, std::string_view s2);
|
||||
bool ContainsNoCase(std::string_view s1, std::string_view s2);
|
||||
|
||||
/// Constexpr version of strcmp, suitable for use in static_assert.
|
||||
inline constexpr int ConstexprCompare(const char* s1, const char* s2)
|
||||
@@ -339,16 +304,8 @@ std::string EncodeBase64(const std::span<u8> data);
|
||||
std::optional<std::vector<u8>> DecodeBase64(const std::string_view str);
|
||||
|
||||
/// StartsWith/EndsWith variants which aren't case sensitive.
|
||||
ALWAYS_INLINE bool StartsWithNoCase(const std::string_view str, const std::string_view prefix)
|
||||
{
|
||||
return (!str.empty() && Strncasecmp(str.data(), prefix.data(), prefix.length()) == 0);
|
||||
}
|
||||
ALWAYS_INLINE bool EndsWithNoCase(const std::string_view str, const std::string_view suffix)
|
||||
{
|
||||
const std::size_t suffix_length = suffix.length();
|
||||
return (str.length() >= suffix_length &&
|
||||
Strncasecmp(str.data() + (str.length() - suffix_length), suffix.data(), suffix_length) == 0);
|
||||
}
|
||||
bool StartsWithNoCase(const std::string_view str, const std::string_view prefix);
|
||||
bool EndsWithNoCase(const std::string_view str, const std::string_view suffix);
|
||||
|
||||
/// Returns the number of occurrences of the given character in the string.
|
||||
size_t CountChar(const std::string_view str, char ch);
|
||||
@@ -450,17 +407,7 @@ void ReplaceAll(std::string* subject, const char search, const char replacement)
|
||||
bool ParseAssignmentString(const std::string_view str, std::string_view* key, std::string_view* value);
|
||||
|
||||
/// Helper for tokenizing strings.
|
||||
ALWAYS_INLINE std::optional<std::string_view> GetNextToken(std::string_view& caret, char separator)
|
||||
{
|
||||
std::optional<std::string_view> ret;
|
||||
const std::string_view::size_type pos = caret.find(separator);
|
||||
if (pos != std::string_view::npos)
|
||||
{
|
||||
ret = caret.substr(0, pos);
|
||||
caret = caret.substr(pos + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
std::optional<std::string_view> GetNextToken(std::string_view& caret, char separator);
|
||||
|
||||
/// Unicode replacement character.
|
||||
inline constexpr char32_t UNICODE_REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
@@ -499,44 +446,11 @@ void EllipsiseInPlace(std::string& str, u32 max_length, const char* ellipsis = "
|
||||
std::optional<size_t> BytePatternSearch(const std::span<const u8> bytes, const std::string_view pattern);
|
||||
|
||||
/// Strided memcpy/memcmp.
|
||||
ALWAYS_INLINE void StrideMemCpy(void* dst, std::size_t dst_stride, const void* src, std::size_t src_stride,
|
||||
std::size_t copy_size, std::size_t count)
|
||||
{
|
||||
if (src_stride == dst_stride && src_stride == copy_size)
|
||||
{
|
||||
std::memcpy(dst, src, src_stride * count);
|
||||
return;
|
||||
}
|
||||
void StrideMemCpy(void* dst, std::size_t dst_stride, const void* src, std::size_t src_stride, std::size_t copy_size,
|
||||
std::size_t count);
|
||||
|
||||
const u8* src_ptr = static_cast<const u8*>(src);
|
||||
u8* dst_ptr = static_cast<u8*>(dst);
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
{
|
||||
std::memcpy(dst_ptr, src_ptr, copy_size);
|
||||
src_ptr += src_stride;
|
||||
dst_ptr += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int StrideMemCmp(const void* p1, std::size_t p1_stride, const void* p2, std::size_t p2_stride,
|
||||
std::size_t copy_size, std::size_t count)
|
||||
{
|
||||
if (p1_stride == p2_stride && p1_stride == copy_size)
|
||||
return std::memcmp(p1, p2, p1_stride * count);
|
||||
|
||||
const u8* p1_ptr = static_cast<const u8*>(p1);
|
||||
const u8* p2_ptr = static_cast<const u8*>(p2);
|
||||
for (std::size_t i = 0; i < count; i++)
|
||||
{
|
||||
int result = std::memcmp(p1_ptr, p2_ptr, copy_size);
|
||||
if (result != 0)
|
||||
return result;
|
||||
p2_ptr += p2_stride;
|
||||
p1_ptr += p1_stride;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int StrideMemCmp(const void* p1, std::size_t p1_stride, const void* p2, std::size_t p2_stride, std::size_t copy_size,
|
||||
std::size_t count);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
||||
Reference in New Issue
Block a user