#include #include #include #include #include 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> StringView::split(StringView delim) const { Vector 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> StringView::split_once(char delim) const { Vector 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> StringView::split_view(char delim) const { Vector 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 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 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); }