aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2021-08-12 01:28:11 +0800
committercrupest <crupest@outlook.com>2021-08-12 01:28:11 +0800
commitd718b0f576aeae1fa853124caefc8b0078f1deed (patch)
tree01e1f53d0e0e1b9f4d8f91635cc528ea24d1f121
parent7be2ea15e41d296cd26635f276551959362aa39d (diff)
downloadcru-d718b0f576aeae1fa853124caefc8b0078f1deed.tar.gz
cru-d718b0f576aeae1fa853124caefc8b0078f1deed.tar.bz2
cru-d718b0f576aeae1fa853124caefc8b0078f1deed.zip
...
-rw-r--r--include/cru/common/String.hpp132
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/String.cpp141
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