Luna/libluna/src/StringView.cpp
apio 7f990b161b
All checks were successful
continuous-integration/drone/push Build is passing
libluna: Fix comparison of StringViews without null termination
This regressed in de7e58c274, and made value arguments pretty much unusable.

This really needs a test...
2023-07-25 17:25:18 +02:00

163 lines
3.5 KiB
C++

#include <luna/CString.h>
#include <luna/NumberParsing.h>
#include <luna/ScopeGuard.h>
#include <luna/String.h>
#include <luna/StringView.h>
static const char* empty = "";
StringView::StringView()
{
m_string = empty;
m_length = 0;
}
StringView::StringView(const StringView& other)
{
m_string = other.m_string;
m_length = other.m_length;
}
StringView::StringView(const char* c_str)
{
check(c_str);
m_string = c_str;
m_length = strlen(m_string);
}
StringView::StringView(const char* c_str, usize length)
{
check(c_str);
m_string = c_str;
m_length = length;
}
StringView& StringView::operator=(const StringView& other)
{
if (&other == this) return *this;
m_string = other.m_string;
m_length = other.m_length;
return *this;
}
const char& StringView::operator[](usize index) const
{
expect(index < m_length, "index out of range");
return m_string[index];
}
bool StringView::operator==(const char* other) const
{
if (m_length != strlen(other)) return false;
return !strncmp(m_string, other, m_length);
}
bool StringView::operator==(StringView other) const
{
if (m_length != other.m_length) return false;
return !strncmp(m_string, other.m_string, m_length);
}
Result<Vector<String>> StringView::split(StringView delim) const
{
Vector<String> result;
String str;
char* copy = strndup(m_string, m_length);
auto guard = make_scope_guard([copy] { free_impl(copy); });
char* segment = strtok(copy, delim.chars());
if (!segment) return result;
str = TRY(String::from_cstring(segment));
TRY(result.try_append(move(str)));
while (true)
{
segment = strtok(nullptr, delim.chars());
if (!segment) return result;
str = TRY(String::from_cstring(segment));
TRY(result.try_append(move(str)));
}
return result;
}
Result<Vector<String>> StringView::split_once(char delim) const
{
Vector<String> result;
char* copy = strndup(m_string, m_length);
auto guard = make_scope_guard([copy] { free_impl(copy); });
char* middle = strchr(copy, delim);
if (!middle)
{
auto str = TRY(String::from_cstring(copy));
TRY(result.try_append(move(str)));
return result;
}
*middle = '\0';
auto begin = TRY(String::from_cstring(copy));
auto end = TRY(String::from_cstring(middle + 1));
TRY(result.try_append(move(begin)));
TRY(result.try_append(move(end)));
return result;
}
Result<Vector<StringView>> StringView::split_view(char delim) const
{
Vector<StringView> result;
char* middle = strchr(m_string, delim);
if (!middle)
{
TRY(result.try_append(*this));
return result;
}
// begin will not contain a null terminator.
auto begin = StringView::from_fixed_size_cstring(m_string, middle - m_string);
auto end = StringView { middle + 1 };
TRY(result.try_append(begin));
TRY(result.try_append(end));
return result;
}
bool StringView::contains(char v) const
{
return strchr(m_string, v);
}
Result<usize> StringView::to_uint() const
{
const char* endptr = nullptr;
auto result = parse_unsigned_integer(m_string, &endptr, 0);
if (endptr == m_string) return err(EINVAL);
return result;
}
Result<String> StringView::to_string()
{
return String::from_string_view(*this);
}
StringView StringView::from_fixed_size_cstring(const char* string, usize max)
{
return { string, strnlen(string, max) };
}
template <> u64 hash(const StringView& value, u64 salt)
{
return hash_memory(value.chars(), value.length(), salt);
}