diff options
author | crupest <crupest@outlook.com> | 2021-08-12 01:28:11 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-08-12 01:28:11 +0800 |
commit | d718b0f576aeae1fa853124caefc8b0078f1deed (patch) | |
tree | 01e1f53d0e0e1b9f4d8f91635cc528ea24d1f121 | |
parent | 7be2ea15e41d296cd26635f276551959362aa39d (diff) | |
download | cru-d718b0f576aeae1fa853124caefc8b0078f1deed.tar.gz cru-d718b0f576aeae1fa853124caefc8b0078f1deed.tar.bz2 cru-d718b0f576aeae1fa853124caefc8b0078f1deed.zip |
...
-rw-r--r-- | include/cru/common/String.hpp | 132 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/common/String.cpp | 141 |
3 files changed, 275 insertions, 0 deletions
diff --git a/include/cru/common/String.hpp b/include/cru/common/String.hpp new file mode 100644 index 00000000..ea9480f0 --- /dev/null +++ b/include/cru/common/String.hpp @@ -0,0 +1,132 @@ +#pragma once + +#include <vcruntime.h> +#include "Base.hpp" + +#include <cstdint> +#include <iterator> + +namespace cru { +class CRU_BASE_API String { + public: + static String fromUtf8(const char* str, Index size); + + static String fromUtf16(const std::uint16_t* str) { return String(str); } + static String fromUtf16(const std::uint16_t* str, Index size) { + return String(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); + } + +#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: + using value_type = std::uint16_t; + using size_type = Index; + using difference_type = Index; + using reference = std::uint16_t&; + using const_reference = const std::uint16_t&; + using pointer = std::uint16_t*; + using const_pointer = const std::uint16_t*; + using iterator = std::uint16_t*; + using const_iterator = const std::uint16_t*; + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + + public: + String() = default; + + String(const std::uint16_t* str); + String(const std::uint16_t* str, Index size); + + String(const char16_t* str); + String(const char16_t* str, Index size); + +#ifdef CRU_PLATFORM_WINDOWS + String(const wchar_t* str); + String(const wchar_t* str, Index size); +#endif + + String(const String& other); + String(String&& other) noexcept; + + String& operator=(const String& other); + String& operator=(String&& other) noexcept; + + ~String(); + + 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_; } + std::uint16_t* data() { return this->buffer_; } + + void reserve(Index new_capacity); + + std::uint16_t& front() { return this->operator[](0); } + const std::uint16_t& front() const { return this->operator[](0); } + + std::uint16_t& back() { return this->operator[](size_ - 1); } + const std::uint16_t& back() const { return this->operator[](size_ - 1); } + + const std::uint16_t* c_str() const { return buffer_; } + + std::uint16_t& operator[](Index index) { return buffer_[index]; } + const std::uint16_t& 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{begin()}; } + const_reverse_iterator rbegin() const { + return const_reverse_iterator{begin()}; + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator{cbegin()}; + } + + reverse_iterator rend() { return reverse_iterator{end()}; } + const_reverse_iterator rend() const { return const_reverse_iterator{end()}; } + const_reverse_iterator crend() const { + return const_reverse_iterator{cend()}; + } + + public: + void clear(); + iterator insert(const_iterator pos, std::uint16_t value) { + return this->insert(pos, &value, 1); + } + iterator insert(const_iterator pos, std::uint16_t* str, Index size); + iterator erase(const_iterator pos) { return this->erase(pos, pos + 1); } + iterator erase(const_iterator start, const_iterator end); + void push_back(std::uint16_t value) { this->append(value); } + void pop_back() { this->erase(cend() - 1); } + void append(std::uint16_t value) { this->insert(cend(), value); } + void append(std::uint16_t* str, Index size) { + this->insert(cend(), str, size); + } + + private: + static std::uint16_t kEmptyBuffer[1]; + + private: + std::uint16_t* buffer_ = kEmptyBuffer; + Index size_ = 0; // not including trailing '\0' + Index capacity_ = 0; // always 1 smaller than real buffer size +}; +} // namespace cru diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index cfd5be15..d5d544ee 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,6 +1,7 @@ set(CRU_BASE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/common) add_library(cru_base SHARED Logger.cpp + String.cpp StringUtil.cpp ) target_sources(cru_base PUBLIC @@ -11,6 +12,7 @@ target_sources(cru_base PUBLIC ${CRU_BASE_INCLUDE_DIR}/Logger.hpp ${CRU_BASE_INCLUDE_DIR}/PreConfig.hpp ${CRU_BASE_INCLUDE_DIR}/SelfResolvable.hpp + ${CRU_BASE_INCLUDE_DIR}/String.hpp ${CRU_BASE_INCLUDE_DIR}/StringUtil.hpp ) target_include_directories(cru_base PUBLIC ${CRU_INCLUDE_DIR}) diff --git a/src/common/String.cpp b/src/common/String.cpp new file mode 100644 index 00000000..ce124575 --- /dev/null +++ b/src/common/String.cpp @@ -0,0 +1,141 @@ +#include "cru/common/String.hpp" + +#include <cstring> + +namespace cru { +std::uint16_t String::kEmptyBuffer[1] = {0}; + +template <typename C> +Index GetStrSize(const C* str) { + Index i = 0; + while (str[i]) { + i++; + } + return i; +} + +String::String(const std::uint16_t* str) : String(str, GetStrSize(str)) {} +String::String(const std::uint16_t* str, Index size) { + this->buffer_ = new std::uint16_t[size + 1]; + std::memcpy(this->buffer_, str, size * sizeof(char16_t)); + this->buffer_[size] = 0; + this->size_ = size; + this->capacity_ = size; +} + +String::String(const char16_t* str) : String(str, GetStrSize(str)) {} +String::String(const char16_t* str, Index size) + : String(reinterpret_cast<const std::uint16_t*>(str), size) {} + +#ifdef CRU_PLATFORM_WINDOWS +String::String(const wchar_t* str) : String(str, GetStrSize(str)) {} +String::String(const wchar_t* str, Index size) + : String(reinterpret_cast<const std::uint16_t*>(str), size) {} +#endif + +String::String(const String& other) { + if (other.buffer_ == kEmptyBuffer) return; + this->buffer_ = new std::uint16_t[other.size_ + 1]; + std::memcpy(this->buffer_, other.buffer_, other.size_ * sizeof(wchar_t)); + this->buffer_[other.size_] = 0; + this->size_ = other.size_; + this->capacity_ = other.size_; +} + +String::String(String&& other) noexcept { + if (other.buffer_ == kEmptyBuffer) return; + this->buffer_ = other.buffer_; + this->size_ = other.size_; + this->capacity_ = other.capacity_; + other.buffer_ = kEmptyBuffer; + other.size_ = 0; + other.capacity_ = 0; +} + +String& String::operator=(const String& other) { + if (this != &other) { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } + + if (other.buffer_ == kEmptyBuffer) { + this->buffer_ = kEmptyBuffer; + this->size_ = 0; + this->capacity_ = 0; + } else { + this->buffer_ = new std::uint16_t[other.size_ + 1]; + std::memcpy(this->buffer_, other.buffer_, other.size_ * sizeof(wchar_t)); + this->buffer_[other.size_] = 0; + this->size_ = other.size_; + this->capacity_ = other.size_; + } + } + return *this; +} + +String& String::operator=(String&& other) noexcept { + if (this != &other) { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } + + this->buffer_ = other.buffer_; + this->size_ = other.size_; + this->capacity_ = other.capacity_; + other.buffer_ = kEmptyBuffer; + other.size_ = 0; + other.capacity_ = 0; + } + return *this; +} + +String::~String() { + if (this->buffer_ != kEmptyBuffer) { + delete[] this->buffer_; + } +} + +void String::reserve(Index new_capacity) { + if (new_capacity <= this->capacity_) return; + if (new_capacity > 0) { + std::uint16_t* new_buffer = new std::uint16_t[new_capacity + 1]; + if (this->buffer_ != kEmptyBuffer) { + memcpy(new_buffer, this->buffer_, this->size_ * sizeof(std::uint16_t)); + delete[] this->buffer_; + } + new_buffer[this->size_] = 0; + this->capacity_ = new_capacity; + } +} + +String::iterator String::insert(const_iterator pos, std::uint16_t* str, + Index size) { + Index new_size = size_ + size; + if (new_size > capacity_) { + this->reserve(this->capacity_ * 2); + } + + auto p = const_cast<iterator>(pos); + + std::memmove(p + size, pos, (cend() - pos) * sizeof(std::uint16_t)); + std::memcpy(p, str, size * sizeof(std::uint16_t)); + + buffer_[new_size] = 0; + + return p + size; +} + +String::iterator String::erase(const_iterator start, const_iterator end) { + Index new_size = size_ - (end - start); + + auto s = const_cast<iterator>(start); + auto e = const_cast<iterator>(end); + + std::memmove(e, s, (cend() - end) * sizeof(std::uint16_t)); + this->size_ = new_size; + this->buffer_[new_size] = 0; + + return s; +} + +} // namespace cru |