#include #include #include #include #include #include String::String() { empty(); } void String::empty() { m_inline = true; m_length = 0; memset(m_inline_storage, 0, sizeof(m_inline_storage)); } String::String(String&& other) { m_inline = other.m_inline; m_string = other.m_string; m_length = other.m_length; if (m_inline) memcpy(m_inline_storage, other.m_inline_storage, sizeof(m_inline_storage)); other.empty(); } String& String::operator=(String&& other) { if (&other == this) return *this; if (!m_inline) free_impl(m_string); m_inline = other.m_inline; m_string = other.m_string; m_length = other.m_length; if (m_inline) memcpy(m_inline_storage, other.m_inline_storage, sizeof(m_inline_storage)); other.empty(); return *this; } String::String(char* c_str) { check(c_str); m_string = c_str; m_inline = false; m_length = strlen(m_string); } String::String(char* c_str, usize length) { check(c_str); m_string = c_str; m_inline = false; m_length = length; } String::~String() { if (!m_inline) free_impl(m_string); } Result String::clone() const { return from_cstring(chars()); } Result String::substring(usize begin, usize size) const { if (begin + size >= size) return err(EINVAL); char* const dup = strndup(chars() + begin, size); if (!dup) return err(ENOMEM); return String { dup, size }; } void String::trim(StringView delim) { isize i = (isize)m_length; while (i--) { char c = chars()[i]; if (!strchr(delim.chars(), c)) break; } i++; if (m_inline) m_inline_storage[i] = '\0'; else m_string[i] = '\0'; m_length = (usize)i; } const char& String::operator[](usize index) const { expect(index < m_length, "index out of range"); return chars()[index]; } Result String::format(const String& fmt, ...) { va_list ap; va_start(ap, fmt); auto rc = vformat(fmt.view(), ap); va_end(ap); return rc; } Result String::format(StringView fmt, ...) { va_list ap; va_start(ap, fmt); auto rc = vformat(fmt, ap); va_end(ap); return rc; } Result String::vformat(StringView fmt, va_list ap) { Vector buf; TRY(cstyle_format( fmt.chars(), [](char c, void* data) -> Result { return ((Vector*)data)->try_append(c); }, &buf, ap)); TRY(buf.try_append(0)); return String { buf.release_data() }; } Result String::from_cstring(const char* str) { return from_string_view(StringView { str }); } Result String::from_string_view(StringView str) { if (str.length() < sizeof(m_inline_storage)) { String result; result.m_inline = true; result.m_length = str.length(); memset(result.m_inline_storage, 0, sizeof(result.m_inline_storage)); memcpy(result.m_inline_storage, str.chars(), str.length()); return result; } char* const dup = strndup(str.chars(), str.length()); if (!dup) return err(ENOMEM); return String { dup, str.length() }; } Result String::join(const Vector& vec, StringView delim) { if (vec.size() == 0) return String {}; if (vec.size() == 1) return vec[0].clone(); StringBuilder sb; TRY(sb.add(vec[0].view())); for (usize i = 1; i < vec.size(); i++) { TRY(sb.add(delim)); TRY(sb.add(vec[i].view())); } return sb.string(); } Result String::join(const Vector& vec, StringView delim) { if (vec.size() == 0) return String {}; if (vec.size() == 1) return from_string_view(vec[0]); StringBuilder sb; TRY(sb.add(vec[0])); for (usize i = 1; i < vec.size(); i++) { TRY(sb.add(delim)); TRY(sb.add(vec[i])); } return sb.string(); } int String::compare(const String* a, const String* b) { return strcmp(a->chars(), b->chars()); } template <> u64 hash(const String& value, u64 salt) { return hash_memory(value.chars(), value.length(), salt); }