#pragma once #include #include #include #include #include #include namespace BAN { class StringView { public: using size_type = size_t; using const_iterator = ConstIteratorSimple; public: constexpr StringView() {} constexpr StringView(const char* string, size_type len = -1) { if (len == size_type(-1)) len = strlen(string); m_data = string; m_size = len; } StringView(const String&); constexpr const_iterator begin() const { return const_iterator(m_data); } constexpr const_iterator end() const { return const_iterator(m_data + m_size); } constexpr char operator[](size_type index) const { ASSERT(index < m_size); return m_data[index]; } constexpr bool operator==(StringView other) const { if (m_size != other.m_size) return false; for (size_type i = 0; i < m_size; i++) if (m_data[i] != other.m_data[i]) return false; return true; } constexpr bool operator==(const char* other) const { for (size_type i = 0; i < m_size; i++) if (m_data[i] != other[i]) return false; return other[m_size] == '\0'; } constexpr StringView substring(size_type index, size_type len = -1) const { ASSERT(index <= m_size); if (len == size_type(-1)) len = m_size - index; ASSERT(len <= m_size - index); // weird order to avoid overflow StringView result; result.m_data = m_data + index; result.m_size = len; return result; } ErrorOr> split(char delim, bool allow_empties = false) const { size_type count = 0; { size_type start = 0; for (size_type i = 0; i < m_size; i++) { if (m_data[i] == delim) { if (allow_empties || start != i) count++; start = i + 1; } } if (start != m_size) count++; } Vector result; TRY(result.reserve(count)); size_type start = 0; for (size_type i = 0; i < m_size; i++) { if (m_data[i] == delim) { if (allow_empties || start != i) TRY(result.push_back(this->substring(start, i - start))); start = i + 1; } } if (start < m_size || (start == m_size && allow_empties)) TRY(result.push_back(this->substring(start))); return result; } ErrorOr> split(bool(*comp)(char), bool allow_empties = false) const { size_type count = 0; { size_type start = 0; for (size_type i = 0; i < m_size; i++) { if (comp(m_data[i])) { if (allow_empties || start != i) count++; start = i + 1; } } if (start != m_size) count++; } Vector result; TRY(result.reserve(count)); size_type start = 0; for (size_type i = 0; i < m_size; i++) { if (comp(m_data[i])) { if (allow_empties || start != i) TRY(result.push_back(this->substring(start, i - start))); start = i + 1; } } if (start < m_size || (start == m_size && allow_empties)) TRY(result.push_back(this->substring(start))); return result; } constexpr char back() const { ASSERT(m_size > 0); return m_data[m_size - 1]; } constexpr char front() const { ASSERT(m_size > 0); return m_data[0]; } BAN::Optional find(char ch) const { for (size_type i = 0; i < m_size; i++) if (m_data[i] == ch) return i; return {}; } BAN::Optional find(bool(*comp)(char)) const { for (size_type i = 0; i < m_size; i++) if (comp(m_data[i])) return i; return {}; } BAN::Optional rfind(char ch) const { for (size_type i = m_size; i > 0; i--) if (m_data[i - 1] == ch) return i - 1; return {}; } BAN::Optional rfind(bool(*comp)(char)) const { for (size_type i = m_size; i > 0; i--) if (comp(m_data[i - 1])) return i - 1; return {}; } constexpr bool starts_with(BAN::StringView target) const { if (target.size() > m_size) return false; for (size_type i = 0; i < target.size(); i++) if (m_data[i] != target[i]) return false; return true; } constexpr bool contains(char ch) const { for (size_type i = 0; i < m_size; i++) if (m_data[i] == ch) return true; return false; } constexpr size_type count(char ch) const { size_type result = 0; for (size_type i = 0; i < m_size; i++) if (m_data[i] == ch) result++; return result; } constexpr bool empty() const { return m_size == 0; } constexpr size_type size() const { return m_size; } constexpr const char* data() const { return m_data; } private: const char* m_data = nullptr; size_type m_size = 0; }; template<> struct hash { hash_t operator()(StringView string) const { constexpr hash_t FNV_offset_basis = 0x811c9dc5; constexpr hash_t FNV_prime = 0x01000193; hash_t hash = FNV_offset_basis; for (StringView::size_type i = 0; i < string.size(); i++) { hash *= FNV_prime; hash ^= (uint8_t)string[i]; } return hash; } }; } inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); } namespace BAN::Formatter { template void print_argument(F putc, const StringView& sv, const ValueFormat&) { for (StringView::size_type i = 0; i < sv.size(); i++) putc(sv[i]); } }