aboutsummaryrefslogtreecommitdiff
path: root/include/cru/common/String.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/cru/common/String.h')
-rw-r--r--include/cru/common/String.h436
1 files changed, 436 insertions, 0 deletions
diff --git a/include/cru/common/String.h b/include/cru/common/String.h
new file mode 100644
index 00000000..0b1b031b
--- /dev/null
+++ b/include/cru/common/String.h
@@ -0,0 +1,436 @@
+#pragma once
+#include "Base.h"
+
+#include "Range.h"
+#include "StringUtil.h"
+
+#include <double-conversion/double-conversion.h>
+#include <filesystem>
+#include <initializer_list>
+#include <iterator>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace cru {
+class StringView;
+
+class CRU_BASE_API String {
+ public:
+ using value_type = char16_t;
+ using size_type = Index;
+ using difference_type = Index;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using iterator = value_type*;
+ using const_iterator = const value_type*;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ public:
+ static String FromUtf8(const char* str);
+ static String FromUtf8(const char* str, Index size);
+ static String FromUtf8(std::string_view str) {
+ return FromUtf8(str.data(), str.size());
+ }
+
+ static String FromUtf16(const char16_t* str) { return String(str); }
+ static String FromUtf16(const char16_t* str, Index size) {
+ return String(str, size);
+ }
+ static String FromUtf16(std::u16string_view str) {
+ return FromUtf16(str.data(), str.size());
+ }
+
+ static inline String From(StringView str);
+
+ // Never use this if you don't know what this mean!
+ static String FromBuffer(pointer buffer, Index size, Index capacity) {
+ return String{from_buffer_tag{}, buffer, size, capacity};
+ }
+
+ static String FromStdPath(const std::filesystem::path& path);
+
+#ifdef CRU_PLATFORM_WINDOWS
+ static String FromUtf16(wchar_t* str) { return String(str); }
+ static String FromUtf16(wchar_t* str, Index size) {
+ return String(str, size);
+ }
+#endif
+
+ public:
+ String() = default;
+
+ explicit String(const_pointer str);
+ String(const_pointer str, size_type size);
+
+ template <Index size>
+ String(const char16_t (&str)[size])
+ : String(reinterpret_cast<const_pointer>(str), size - 1) {}
+
+ template <typename Iter>
+ String(Iter start, Iter end) {
+ for (; start != end; start++) {
+ append(*start);
+ }
+ }
+
+ String(size_type size, value_type ch = 0);
+
+ String(std::initializer_list<value_type> l);
+
+ explicit String(StringView str);
+
+#ifdef CRU_PLATFORM_WINDOWS
+ String(const wchar_t* str);
+ String(const wchar_t* str, Index size);
+ String(const std::wstring& str) : String(str.data(), str.size()) {}
+#endif
+
+ String(const String& other);
+ String(String&& other) noexcept;
+
+ String& operator=(const String& other);
+ String& operator=(String&& other) noexcept;
+
+ ~String();
+
+ private:
+ struct from_buffer_tag {};
+ String(from_buffer_tag, pointer buffer, Index size, Index capacity);
+
+ public:
+ bool empty() const { return this->size_ == 0; }
+ Index size() const { return this->size_; }
+ Index length() const { return this->size(); }
+ Index capacity() const { return this->capacity_; }
+ pointer data() { return this->buffer_; }
+ const_pointer data() const { return this->buffer_; }
+
+ void resize(Index new_size);
+ void reserve(Index new_capacity);
+ void shrink_to_fit();
+
+ reference front() { return this->operator[](0); }
+ const_reference front() const { return this->operator[](0); }
+
+ reference back() { return this->operator[](size_ - 1); }
+ const_reference back() const { return this->operator[](size_ - 1); }
+
+ const_pointer c_str() const { return buffer_; }
+
+ reference operator[](Index index) { return buffer_[index]; }
+ const_reference operator[](Index index) const { return buffer_[index]; }
+
+ public:
+ iterator begin() { return this->buffer_; }
+ const_iterator begin() const { return this->buffer_; }
+ const_iterator cbegin() const { return this->buffer_; }
+
+ iterator end() { return this->buffer_ + this->size_; }
+ const_iterator end() const { return this->buffer_ + this->size_; }
+ const_iterator cend() const { return this->buffer_ + this->size_; }
+
+ reverse_iterator rbegin() { return reverse_iterator{end()}; }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator{end()};
+ }
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator{cend()};
+ }
+
+ reverse_iterator rend() { return reverse_iterator{begin()}; }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator{begin()};
+ }
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator{cbegin()};
+ }
+
+ public:
+ void clear();
+ iterator insert(const_iterator pos, value_type value) {
+ return this->insert(pos, &value, 1);
+ }
+ iterator insert(const_iterator pos, const_iterator str, Index size);
+ iterator insert(const_iterator pos, StringView str);
+ iterator erase(const_iterator pos) { return this->erase(pos, pos + 1); }
+ iterator erase(const_iterator start, const_iterator end);
+ void push_back(value_type value) { this->append(value); }
+ void pop_back() { this->erase(cend() - 1); }
+ void append(value_type value) { this->insert(cend(), value); }
+ void append(const_iterator str, Index size) {
+ this->insert(cend(), str, size);
+ }
+ inline void append(StringView str);
+
+ String substr(size_type start, size_type size = -1) const {
+ if (size == -1) {
+ size = this->size_ - start;
+ }
+ return String(this->buffer_ + start, size);
+ }
+
+ String& operator+=(value_type value) {
+ this->append(value);
+ return *this;
+ }
+ String& operator+=(StringView other);
+
+ public:
+ operator std::u16string_view() const {
+ return std::u16string_view(data(), size());
+ }
+
+ StringView View() const;
+
+ public:
+ Index Find(value_type value, Index start = 0) const;
+ std::vector<String> Split(value_type separator,
+ bool remove_space_line = false) const;
+ std::vector<String> SplitToLines(bool remove_space_line = false) const;
+
+ bool StartWith(StringView str) const;
+ bool EndWith(StringView str) const;
+
+ String& TrimStart();
+ String& TrimEnd();
+ String& Trim();
+
+ public:
+ void AppendCodePoint(CodePoint code_point);
+
+ Utf16CodePointIterator CodePointIterator() const {
+ return Utf16CodePointIterator(buffer_, size_);
+ }
+
+ Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const;
+ Index IndexFromCodePointToCodeUnit(Index code_point_index) const;
+ Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const;
+ Range RangeFromCodePointToCodeUnit(Range code_point_range) const;
+
+ float ParseToFloat(Index* processed_characters_count = nullptr) const;
+ double ParseToDouble(Index* processed_characters_count = nullptr) const;
+ std::vector<float> ParseToFloatList(value_type separator = u' ') const;
+ std::vector<double> ParseToDoubleList(value_type separator = u' ') const;
+
+#ifdef CRU_PLATFORM_WINDOWS
+ const wchar_t* WinCStr() const {
+ return reinterpret_cast<const wchar_t*>(c_str());
+ }
+#endif
+
+ template <typename... T>
+ String Format(T&&... args) const;
+
+ std::string ToUtf8() const;
+
+ int Compare(const String& other) const;
+ int CaseInsensitiveCompare(const String& other) const;
+ bool CaseInsensitiveEqual(const String& other) const {
+ return CaseInsensitiveCompare(other) == 0;
+ }
+
+ private:
+ static char16_t kEmptyBuffer[1];
+
+ private:
+ char16_t* buffer_ = kEmptyBuffer;
+ Index size_ = 0; // not including trailing '\0'
+ Index capacity_ = 0; // always 1 smaller than real buffer size
+};
+
+class CRU_BASE_API StringView {
+ public:
+ static double_conversion::StringToDoubleConverter
+ kDefaultStringToDoubleConverter;
+
+ using value_type = char16_t;
+ using size_type = Index;
+ using difference_type = Index;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using iterator = const value_type*;
+ using const_iterator = const value_type*;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ StringView() = default;
+
+ constexpr StringView(const_pointer ptr, Index size)
+ : ptr_(ptr), size_(size) {}
+
+ template <Index size>
+ constexpr StringView(const value_type (&array)[size])
+ : StringView(array, size - 1) {}
+
+ StringView(const String& str) : StringView(str.data(), str.size()) {}
+
+ CRU_DEFAULT_COPY(StringView)
+ CRU_DEFAULT_MOVE(StringView)
+
+ ~StringView() = default;
+
+ bool empty() const { return size_ == 0; }
+ Index size() const { return size_; }
+ const value_type* data() const { return ptr_; }
+
+ public:
+ iterator begin() { return this->ptr_; }
+ const_iterator begin() const { return this->ptr_; }
+ const_iterator cbegin() const { return this->ptr_; }
+
+ iterator end() { return this->ptr_ + this->size_; }
+ const_iterator end() const { return this->ptr_ + this->size_; }
+ const_iterator cend() const { return this->ptr_ + this->size_; }
+
+ reverse_iterator rbegin() { return reverse_iterator{end()}; }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator{end()};
+ }
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator{cend()};
+ }
+
+ reverse_iterator rend() { return reverse_iterator{begin()}; }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator{begin()};
+ }
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator{cbegin()};
+ }
+
+ StringView substr(Index pos);
+ StringView substr(Index pos, Index size);
+
+ value_type operator[](Index index) const { return ptr_[index]; }
+
+ operator std::u16string_view() const {
+ return std::u16string_view(data(), size());
+ }
+
+ public:
+ int Compare(const StringView& other) const;
+ int CaseInsensitiveCompare(const StringView& other) const;
+ bool CaseInsensitiveEqual(const StringView& other) const {
+ return CaseInsensitiveCompare(other) == 0;
+ }
+
+ String ToString() const { return String(ptr_, size_); }
+
+ Utf16CodePointIterator CodePointIterator() const {
+ return Utf16CodePointIterator(ptr_, size_);
+ }
+
+ Index Find(value_type value, Index start = 0) const;
+ std::vector<String> Split(value_type separator,
+ bool remove_space_line = false) const;
+ std::vector<String> SplitToLines(bool remove_space_line = false) const;
+
+ bool StartWith(StringView str) const;
+ bool EndWith(StringView str) const;
+
+ Index IndexFromCodeUnitToCodePoint(Index code_unit_index) const;
+ Index IndexFromCodePointToCodeUnit(Index code_point_index) const;
+ Range RangeFromCodeUnitToCodePoint(Range code_unit_range) const;
+ Range RangeFromCodePointToCodeUnit(Range code_point_range) const;
+
+ float ParseToFloat(Index* processed_characters_count = nullptr) const;
+ double ParseToDouble(Index* processed_characters_count = nullptr) const;
+ std::vector<float> ParseToFloatList(value_type separator = u' ') const;
+ std::vector<double> ParseToDoubleList(value_type separator = u' ') const;
+
+ std::string ToUtf8() const;
+
+ private:
+ const char16_t* ptr_;
+ Index size_;
+};
+
+CRU_DEFINE_COMPARE_OPERATORS(String)
+
+inline String operator+(const String& left, const String& right) {
+ String result(left);
+ result += right;
+ return result;
+}
+
+CRU_DEFINE_COMPARE_OPERATORS(StringView)
+
+inline String::iterator String::insert(const_iterator pos, StringView str) {
+ return insert(pos, str.data(), str.size());
+}
+
+inline void String::append(StringView str) {
+ this->append(str.data(), str.size());
+}
+
+inline String String::From(StringView str) { return str.ToString(); }
+
+inline String::String(StringView str) : String(str.data(), str.size()) {}
+
+inline String ToString(StringView value) { return value.ToString(); }
+
+inline CodePoint Utf16PreviousCodePoint(StringView str, Index current,
+ Index* previous_position) {
+ return Utf16PreviousCodePoint(str.data(), str.size(), current,
+ previous_position);
+}
+
+inline CodePoint Utf16NextCodePoint(StringView str, Index current,
+ Index* next_position) {
+ return Utf16NextCodePoint(str.data(), str.size(), current, next_position);
+}
+
+inline bool Utf16IsValidInsertPosition(StringView str, Index position) {
+ return Utf16IsValidInsertPosition(str.data(), str.size(), position);
+}
+
+// Return position after the character making predicate returns true or 0 if no
+// character doing so.
+inline Index CRU_BASE_API
+Utf16BackwardUntil(StringView str, Index position,
+ const std::function<bool(CodePoint)>& predicate) {
+ return Utf16BackwardUntil(str.data(), str.size(), position, predicate);
+}
+// Return position before the character making predicate returns true or
+// str.size() if no character doing so.
+inline Index CRU_BASE_API
+Utf16ForwardUntil(StringView str, Index position,
+ const std::function<bool(CodePoint)>& predicate) {
+ return Utf16ForwardUntil(str.data(), str.size(), position, predicate);
+}
+
+inline Index Utf16PreviousWord(StringView str, Index position,
+ bool* is_space = nullptr) {
+ return Utf16PreviousWord(str.data(), str.size(), position, is_space);
+}
+
+inline Index Utf16NextWord(StringView str, Index position,
+ bool* is_space = nullptr) {
+ return Utf16NextWord(str.data(), str.size(), position, is_space);
+}
+
+String CRU_BASE_API ToLower(StringView s);
+String CRU_BASE_API ToUpper(StringView s);
+} // namespace cru
+
+template <>
+struct std::hash<cru::String> {
+ std::size_t operator()(const cru::String& value) const {
+ return std::hash<std::u16string_view>{}(std::u16string_view(
+ reinterpret_cast<const char16_t*>(value.data()), value.size()));
+ }
+};
+
+template <>
+struct std::hash<cru::StringView> {
+ std::size_t operator()(const cru::StringView& value) const {
+ return std::hash<std::u16string_view>{}(std::u16string_view(
+ reinterpret_cast<const char16_t*>(value.data()), value.size()));
+ }
+};