From 60c1175503b6f1f34570a5cefd3414084bb0ae33 Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Thu, 26 Feb 2026 14:43:19 -0500 Subject: [PATCH 1/3] The great gd::string expansion --- loader/include/Geode/c++stl/string.hpp | 521 ++++++++++++++++++++++- loader/src/c++stl/string-impl.hpp | 12 +- loader/src/c++stl/string.cpp | 367 +++++++++++++++- loader/src/platform/android/gdstdlib.cpp | 122 +++++- 4 files changed, 1004 insertions(+), 18 deletions(-) diff --git a/loader/include/Geode/c++stl/string.hpp b/loader/include/Geode/c++stl/string.hpp index b9f6f1439..74ee8b67b 100644 --- a/loader/include/Geode/c++stl/string.hpp +++ b/loader/include/Geode/c++stl/string.hpp @@ -63,21 +63,258 @@ namespace gd { geode::stl::StringData m_data; friend geode::stl::StringImpl; public: + using size_type = size_t; + using difference_type = ptrdiff_t; + using value_type = char; + using reference = char&; + using const_reference = char const&; + using pointer = char*; + using const_pointer = char const*; + using iterator = std::string::iterator; + using const_iterator = std::string::const_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + static const size_t npos = -1; + string(); string(string const&); - // string(string&&); + string(string&&); string(char const*); string(char const*, size_t); + string(size_t, char); string(std::string const&); - // tried to add a string_view ctor, but got overload errors :( + string(std::initializer_list); + string(string const&, size_t); + string(string const&, size_t, size_t); + string(string&&, size_t); + string(string&&, size_t, size_t); + + template + requires std::convertible_to + string(T const& other) { + this->assign(std::string_view(other)); + } + + template + requires std::convertible_to + string(T const& other, size_t pos, size_t count) { + this->assign(std::string_view(other), pos, count); + } + + template + string(It first, It last) : string(std::to_address(first), std::distance(first, last)) {} + + template + string(std::from_range_t, Range&& range) : string(std::ranges::begin(range), std::ranges::end(range)) {} + ~string(); + string& assign(string const& other); + string& assign(string&& other); + string& assign(char const* other); + string& assign(char const* other, size_t count); + string& assign(string const& other, size_t pos, size_t count = npos); + string& assign(std::initializer_list ilist); + string& assign(size_t count, char c); + + template + requires std::convertible_to + string& assign(T const& other) { + std::string_view view(other); + return this->assign(view.data(), view.size()); + } + + template + requires std::convertible_to + string& assign(T const& other, size_t pos, size_t count = npos) { + std::string_view view(other); + if (pos > view.size()) { + throw std::out_of_range("gd::string::assign"); + } + return this->assign(view.data() + pos, std::min(count, view.size() - pos)); + } + + template + string& assign(It first, It last) { + return this->assign(std::to_address(first), std::distance(first, last)); + } + + template + string& assign_range(Range&& range) { + return this->assign(std::ranges::begin(range), std::ranges::end(range)); + } + string& operator=(string const&); string& operator=(string&&); string& operator=(char const*); + string& operator=(char); + string& operator=(std::initializer_list); string& operator=(std::string const&); + template + requires std::convertible_to + string& operator=(T const& other) { + return this->assign(std::string_view(other)); + } + void clear(); + void swap(string& other); + + void reserve(size_t capacity); + void resize(size_t size, char fill = '\0'); + void push_back(char c); + void pop_back(); + size_t copy(char* buffer, size_t count, size_t pos = 0) const; + void shrink_to_fit(); + + template + void resize_and_overwrite(size_t newSize, Operation op) { + this->resize(newSize); + this->erase(op(this->data(), newSize)); + } + + string& append(char const* other); + string& append(char const* other, size_t count); + string& append(string const& other); + string& append(string const& other, size_t pos, size_t count = npos); + string& append(std::initializer_list ilist); + string& append(size_t count, char c); + + template + requires std::convertible_to + string& append(T const& other) { + std::string_view view(other); + return this->append(view.data(), view.size()); + } + + template + requires std::convertible_to + string& append(T const& other, size_t pos, size_t count = npos) { + std::string_view view(other); + if (pos > view.size()) { + throw std::out_of_range("gd::string::append"); + } + return this->append(view.data() + pos, std::min(count, view.size() - pos)); + } + + template + string& append(It first, It last) { + return this->append(std::to_address(first), std::distance(first, last)); + } + + template + string& append_range(Range&& range) { + return this->append(std::ranges::begin(range), std::ranges::end(range)); + } + + string& operator+=(string const&); + string& operator+=(char const*); + string& operator+=(char); + string& operator+=(std::initializer_list); + + template + requires std::convertible_to + string& operator+=(T const& other) { + return this->append(std::string_view(other)); + } + + string& insert(size_t pos, char const* other); + string& insert(size_t pos, char const* other, size_t count); + string& insert(size_t pos, string const& other); + string& insert(size_t pos, string const& other, size_t pos2, size_t count = npos); + iterator insert(const_iterator pos, char c); + iterator insert(const_iterator pos, size_t count, char c); + iterator insert(const_iterator pos, std::initializer_list ilist); + string& insert(size_t pos, size_t count, char c); + + template + iterator insert(const_iterator pos, It first, It last) { + size_t index = pos - this->begin(); + this->insert(index, std::to_address(first), std::distance(first, last)); + return this->begin() + index; + } + + template + requires std::convertible_to + string& insert(size_t pos, T const& other) { + std::string_view view(other); + return this->insert(pos, view.data(), view.size()); + } + + template + requires std::convertible_to + string& insert(size_t pos, T const& other, size_t pos2, size_t count = npos) { + std::string_view view(other); + if (pos2 > view.size()) { + throw std::out_of_range("gd::string::insert"); + } + return this->insert(pos, view.data() + pos2, std::min(count, view.size() - pos2)); + } + + string& erase(size_t pos = 0, size_t count = npos); + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + string& replace(size_t pos, size_t count, string const& other); + string& replace(const_iterator first, const_iterator last, string const& other); + string& replace(size_t pos, size_t count, string const& other, size_t pos2, size_t count2 = npos); + string& replace(size_t pos, size_t count, char const* other); + string& replace(size_t pos, size_t count, char const* other, size_t count2); + string& replace(const_iterator first, const_iterator last, char const* other); + string& replace(const_iterator first, const_iterator last, char const* other, size_t count2); + string& replace(const_iterator first, const_iterator last, std::initializer_list ilist); + string& replace(size_t pos, size_t count, size_t count2, char c); + string& replace(const_iterator first, const_iterator last, size_t count2, char c); + + template + string& replace(const_iterator first, const_iterator last, It first2, It last2) { + this->replace(first, last, std::to_address(first2), std::distance(first2, last2)); + return *this; + } + + template + requires std::convertible_to + string& replace(size_t pos, size_t count, T const& other) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + std::string_view view(other); + return this->replace(pos, count, view.data(), view.size()); + } + + template + requires std::convertible_to + string& replace(const_iterator first, const_iterator last, T const& other) { + std::string_view view(other); + return this->replace(first, last, view.data(), view.size()); + } + + template + requires std::convertible_to + string& replace(size_t pos, size_t count, T const& other, size_t pos2, size_t count2 = npos) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + std::string_view view(other); + if (pos2 > view.size()) { + throw std::out_of_range("gd::string::replace"); + } + return this->replace(pos, count, view.data() + pos2, std::min(count2, view.size() - pos2)); + } + + template + string& replace_with_range(const_iterator first, const_iterator last, Range&& range) { + return this->replace(first, last, std::ranges::begin(range), std::ranges::end(range)); + } + + string substr(size_t pos = 0, size_t count = npos) const& { + return string(*this, pos, count); + } + + string substr(size_t pos = 0, size_t count = npos) && { + return string(std::move(*this), pos, count); + } char& at(size_t pos); char const& at(size_t pos) const; @@ -85,13 +322,68 @@ namespace gd { char& operator[](size_t pos); char const& operator[](size_t pos) const; + char& front(); + char const& front() const; + char& back(); + char const& back() const; + char* data(); char const* data() const; char const* c_str() const; size_t size() const; + size_t length() const; size_t capacity() const; bool empty() const; + size_t max_size() const; + + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; + iterator end(); + const_iterator end() const; + const_iterator cend() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + const_reverse_iterator crbegin() const; + reverse_iterator rend(); + const_reverse_iterator rend() const; + const_reverse_iterator crend() const; + + int compare(string const& other) const { + return std::string_view(*this).compare(other); + } + int compare(size_t pos, size_t count, string const& other) const { + return std::string_view(*this).compare(pos, count, other); + } + int compare(size_t pos, size_t count, string const& other, size_t pos2, size_t count2 = npos) const { + return std::string_view(*this).compare(pos, count, other, pos2, count2); + } + int compare(char const* other) const { + return std::string_view(*this).compare(other); + } + int compare(size_t pos, size_t count, char const* other) const { + return std::string_view(*this).compare(pos, count, other); + } + int compare(size_t pos, size_t count, char const* other, size_t count2) const { + return std::string_view(*this).compare(pos, count, other, count2); + } + template + requires std::convertible_to + int compare(T const& other) const { + return std::string_view(*this).compare(std::string_view(other)); + } + template + requires std::convertible_to + int compare(size_t pos, size_t count, T const& other) const { + return std::string_view(*this).compare(pos, count, std::string_view(other)); + } + template + requires std::convertible_to + int compare(size_t pos, size_t count, T const& other, size_t pos2, size_t count2 = npos) const { + return std::string_view(*this).compare(pos, count, std::string_view(other), pos2, count2); + } bool operator==(string const& other) const; bool operator==(std::string_view other) const; @@ -110,10 +402,235 @@ namespace gd { return *this <=> std::string_view(other); } + bool starts_with(std::string_view prefix) const { + return std::string_view(*this).starts_with(prefix); + } + bool starts_with(char const* prefix) const { + return std::string_view(*this).starts_with(prefix); + } + bool starts_with(char prefix) const { + return std::string_view(*this).starts_with(prefix); + } + + bool ends_with(std::string_view suffix) const { + return std::string_view(*this).ends_with(suffix); + } + bool ends_with(char const* suffix) const { + return std::string_view(*this).ends_with(suffix); + } + bool ends_with(char suffix) const { + return std::string_view(*this).ends_with(suffix); + } + + bool contains(std::string_view str) const { + return std::string_view(*this).find(str) != npos; + } + bool contains(char const* str) const { + return std::string_view(*this).find(str) != npos; + } + bool contains(char c) const { + return std::string_view(*this).find(c) != npos; + } + + size_t find(string const& str, size_t pos = 0) const { + return std::string_view(*this).find(str, pos); + } + size_t find(char const* str, size_t pos = 0) const { + return std::string_view(*this).find(str, pos); + } + size_t find(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).find(str, pos, count); + } + size_t find(char c, size_t pos = 0) const { + return std::string_view(*this).find(c, pos); + } + template + requires std::convertible_to + size_t find(T const& other, size_t pos = 0) const { + return std::string_view(*this).find(std::string_view(other), pos); + } + + size_t rfind(string const& str, size_t pos = npos) const { + return std::string_view(*this).rfind(str, pos); + } + size_t rfind(char const* str, size_t pos = npos) const { + return std::string_view(*this).rfind(str, pos); + } + size_t rfind(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).rfind(str, pos, count); + } + size_t rfind(char c, size_t pos = npos) const { + return std::string_view(*this).rfind(c, pos); + } + template + requires std::convertible_to + size_t rfind(T const& other, size_t pos = npos) const { + return std::string_view(*this).rfind(std::string_view(other), pos); + } + + size_t find_first_of(string const& str, size_t pos = 0) const { + return std::string_view(*this).find_first_of(str, pos); + } + size_t find_first_of(char const* str, size_t pos = 0) const { + return std::string_view(*this).find_first_of(str, pos); + } + size_t find_first_of(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).find_first_of(str, pos, count); + } + size_t find_first_of(char c, size_t pos = 0) const { + return std::string_view(*this).find_first_of(c, pos); + } + template + requires std::convertible_to + size_t find_first_of(T const& other, size_t pos = 0) const { + return std::string_view(*this).find_first_of(std::string_view(other), pos); + } + + size_t find_last_of(string const& str, size_t pos = npos) const { + return std::string_view(*this).find_last_of(str, pos); + } + size_t find_last_of(char const* str, size_t pos = npos) const { + return std::string_view(*this).find_last_of(str, pos); + } + size_t find_last_of(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).find_last_of(str, pos, count); + } + size_t find_last_of(char c, size_t pos = npos) const { + return std::string_view(*this).find_last_of(c, pos); + } + template + requires std::convertible_to + size_t find_last_of(T const& other, size_t pos = npos) const { + return std::string_view(*this).find_last_of(std::string_view(other), pos); + } + + size_t find_first_not_of(string const& str, size_t pos = 0) const { + return std::string_view(*this).find_first_not_of(str, pos); + } + size_t find_first_not_of(char const* str, size_t pos = 0) const { + return std::string_view(*this).find_first_not_of(str, pos); + } + size_t find_first_not_of(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).find_first_not_of(str, pos, count); + } + size_t find_first_not_of(char c, size_t pos = 0) const { + return std::string_view(*this).find_first_not_of(c, pos); + } + template + requires std::convertible_to + size_t find_first_not_of(T const& other, size_t pos = 0) const { + return std::string_view(*this).find_first_not_of(std::string_view(other), pos); + } + + size_t find_last_not_of(string const& str, size_t pos = npos) const { + return std::string_view(*this).find_last_not_of(str, pos); + } + size_t find_last_not_of(char const* str, size_t pos = npos) const { + return std::string_view(*this).find_last_not_of(str, pos); + } + size_t find_last_not_of(char const* str, size_t pos, size_t count) const { + return std::string_view(*this).find_last_not_of(str, pos, count); + } + size_t find_last_not_of(char c, size_t pos = npos) const { + return std::string_view(*this).find_last_not_of(c, pos); + } + template + requires std::convertible_to + size_t find_last_not_of(T const& other, size_t pos = npos) const { + return std::string_view(*this).find_last_not_of(std::string_view(other), pos); + } + operator std::string() const; operator std::string_view() const; }; + inline string operator+(string const& lhs, string const& rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(string const& lhs, char const* rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(char const* lhs, string const& rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(string const& lhs, char rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(char lhs, string const& rhs) { + string out = string(1, lhs); + out += rhs; + return out; + } + + inline string operator+(string const& lhs, std::type_identity_t rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(std::type_identity_t lhs, string const& rhs) { + string out = string(lhs); + out += rhs; + return out; + } + + inline string operator+(string&& lhs, string const& rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(string const& lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, string&& rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(string&& lhs, char const* rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(char const* lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, char rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(char lhs, string&& rhs) { + rhs.insert(0, 1, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, std::type_identity_t rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(std::type_identity_t lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } + inline std::string_view format_as(gd::string const& str) { return std::string_view(str); } diff --git a/loader/src/c++stl/string-impl.hpp b/loader/src/c++stl/string-impl.hpp index 003355933..f9b0934dc 100644 --- a/loader/src/c++stl/string-impl.hpp +++ b/loader/src/c++stl/string-impl.hpp @@ -14,11 +14,21 @@ namespace geode::stl { char* getStorage(); void setStorage(std::string_view); + void setStorage(StringData&); + void swapStorage(StringData&); size_t getSize(); - void setSize(size_t); + void setSize(size_t, char); size_t getCapacity(); void setCapacity(size_t); + + void append(std::string_view); + void append(size_t, char); + void insert(size_t, std::string_view); + void insert(size_t, size_t, char); + void erase(size_t, size_t); + void replace(size_t, size_t, std::string_view); + void replace(size_t, size_t, size_t, char); }; } \ No newline at end of file diff --git a/loader/src/c++stl/string.cpp b/loader/src/c++stl/string.cpp index d0ca51215..903d77d5b 100644 --- a/loader/src/c++stl/string.cpp +++ b/loader/src/c++stl/string.cpp @@ -20,15 +20,13 @@ namespace gd { } string::string(string const& str) { - impl.setStorage(str); + impl.setStorage(intoMutRef(str.m_data)); } - // string::string(string&& other) { - // // TODO: do this better :-) - // impl.setStorage(other); - // implFor(other).free(); - // implFor(other).setEmpty(); - // } + string::string(string&& other) { + impl.swapStorage(other.m_data); + implFor(other).setEmpty(); + } string::string(char const* str) { impl.setStorage(str); @@ -38,23 +36,104 @@ namespace gd { impl.setStorage(std::string_view(str, size)); } + string::string(size_t count, char c) { + impl.setSize(count, c); + } + string::string(std::string const& str) { impl.setStorage(str); } + string::string(std::initializer_list ilist) { + impl.setStorage(std::string_view(ilist.begin(), ilist.size())); + } + + string::string(string const& other, size_t pos) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::string"); + } + impl.setStorage(std::string_view(other.data() + pos, other.size() - pos)); + } + + string::string(string const& other, size_t pos, size_t count) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::string"); + } + impl.setStorage(std::string_view(other.data() + pos, std::min(count, other.size() - pos))); + } + + string::string(string&& other, size_t pos) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::string"); + } + other.erase(0, pos); + impl.swapStorage(other.m_data); + implFor(other).setEmpty(); + } + + string::string(string&& other, size_t pos, size_t count) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::string"); + } + other.erase(0, pos); + other.erase(std::min(count, other.size() - pos)); + impl.swapStorage(other.m_data); + implFor(other).setEmpty(); + } + string::~string() { this->clear(); } + string& string::assign(string const& other) { + impl.setStorage(other); + return *this; + } + + string& string::assign(string&& other) { + impl.swapStorage(other.m_data); + implFor(other).setEmpty(); + return *this; + } + + string& string::assign(char const* other) { + impl.setStorage(other); + return *this; + } + + string& string::assign(char const* other, size_t count) { + impl.setStorage(std::string_view(other, count)); + return *this; + } + + string& string::assign(string const& other, size_t pos, size_t count) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::assign"); + } + + impl.setStorage(std::string_view(other.data() + pos, std::min(count, other.size() - pos))); + return *this; + } + + string& string::assign(std::initializer_list ilist) { + impl.setStorage(std::string_view(ilist.begin(), ilist.size())); + return *this; + } + + string& string::assign(size_t count, char c) { + impl.setSize(count, c); + return *this; + } + string& string::operator=(string const& other) { - if (this != &other) { + // check if the strings share the same storage + if (this->m_data.m_data != other.m_data.m_data) { impl.setStorage(other); } return *this; } string& string::operator=(string&& other) { - // TODO: do this better :-) - impl.setStorage(other); + impl.swapStorage(other.m_data); implFor(other).setEmpty(); return *this; } @@ -62,6 +141,14 @@ namespace gd { impl.setStorage(other); return *this; } + string& string::operator=(char other) { + impl.setSize(1, other); + return *this; + } + string& string::operator=(std::initializer_list ilist) { + impl.setStorage(std::string_view(ilist.begin(), ilist.size())); + return *this; + } string& string::operator=(std::string const& other) { impl.setStorage(other); return *this; @@ -71,6 +158,235 @@ namespace gd { impl.setEmpty(); } + void string::swap(string& other) { + impl.swapStorage(other.m_data); + } + + void string::reserve(size_t capacity) { + impl.setCapacity(impl.getSize() + capacity); + } + + void string::resize(size_t size, char fill) { + impl.setSize(size, fill); + } + + void string::push_back(char c) { + impl.append(1, c); + } + + void string::pop_back() { + impl.setSize(this->size() - 1, 0); + } + + size_t string::copy(char* buffer, size_t count, size_t pos) const { + if (pos > this->size()) { + throw std::out_of_range("gd::string::copy"); + } + size_t toCopy = std::min(count, this->size() - pos); + std::memcpy(buffer, this->data() + pos, toCopy); + return toCopy; + } + + void string::shrink_to_fit() { + impl.setCapacity(this->size()); + } + + string& string::append(char const* other) { + impl.append(other); + return *this; + } + + string& string::append(char const* other, size_t count) { + impl.append(std::string_view(other, count)); + return *this; + } + + string& string::append(string const& other) { + impl.append(other); + return *this; + } + + string& string::append(string const& other, size_t pos, size_t count) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::append"); + } + impl.append(std::string_view(other.data() + pos, std::min(count, other.size() - pos))); + return *this; + } + + string& string::append(std::initializer_list ilist) { + impl.append(std::string_view(ilist.begin(), ilist.size())); + return *this; + } + + string& string::append(size_t count, char c) { + impl.append(count, c); + return *this; + } + + string& string::insert(size_t pos, char const* other) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::insert"); + } + impl.insert(pos, other); + return *this; + } + + string& string::insert(size_t pos, char const* other, size_t count) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::insert"); + } + impl.insert(pos, std::string_view(other, count)); + return *this; + } + + string& string::insert(size_t pos, string const& other) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::insert"); + } + impl.insert(pos, other); + return *this; + } + + string& string::insert(size_t pos, string const& other, size_t pos2, size_t count) { + if (pos > this->size() || pos2 > other.size()) { + throw std::out_of_range("gd::string::insert"); + } + impl.insert(pos, std::string_view(other.data() + pos2, std::min(count, other.size() - pos2))); + return *this; + } + + string::iterator string::insert(const_iterator pos, char c) { + size_t index = pos - this->begin(); + impl.insert(index, 1, c); + return this->begin() + index; + } + + string::iterator string::insert(const_iterator pos, size_t count, char c) { + size_t index = pos - this->begin(); + impl.insert(index, count, c); + return this->begin() + index; + } + + string::iterator string::insert(const_iterator pos, std::initializer_list ilist) { + size_t index = pos - this->begin(); + impl.insert(index, std::string_view(ilist.begin(), ilist.size())); + return this->begin() + index; + } + + string& string::insert(size_t pos, size_t count, char c) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::insert"); + } + impl.insert(pos, count, c); + return *this; + } + + string& string::erase(size_t pos, size_t count) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::erase"); + } + impl.erase(pos, count); + return *this; + } + + string::iterator string::erase(const_iterator pos) { + size_t index = pos - this->begin(); + impl.erase(index, 1); + return this->begin() + index; + } + + string::iterator string::erase(const_iterator first, const_iterator last) { + size_t index = first - this->begin(); + impl.erase(index, last - first); + return this->begin() + index; + } + + string& string::replace(size_t pos, size_t count, string const& other) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + impl.replace(pos, count, other); + return *this; + } + + string& string::replace(const_iterator first, const_iterator last, string const& other) { + size_t index = first - this->begin(); + impl.replace(index, last - first, other); + return *this; + } + + string& string::replace(size_t pos, size_t count, string const& other, size_t pos2, size_t count2) { + if (pos > this->size() || pos2 > other.size()) { + throw std::out_of_range("gd::string::replace"); + } + impl.replace(pos, count, std::string_view(other.data() + pos2, std::min(count2, other.size() - pos2))); + return *this; + } + + string& string::replace(size_t pos, size_t count, char const* other) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + impl.replace(pos, count, other); + return *this; + } + + string& string::replace(size_t pos, size_t count, char const* other, size_t count2) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + impl.replace(pos, count, std::string_view(other, count2)); + return *this; + } + + string& string::replace(const_iterator first, const_iterator last, char const* other) { + size_t index = first - this->begin(); + impl.replace(index, last - first, other); + return *this; + } + + string& string::replace(const_iterator first, const_iterator last, char const* other, size_t count2) { + size_t index = first - this->begin(); + impl.replace(index, last - first, std::string_view(other, count2)); + return *this; + } + + string& string::replace(const_iterator first, const_iterator last, std::initializer_list ilist) { + size_t index = first - this->begin(); + impl.replace(index, last - first, std::string_view(ilist.begin(), ilist.size())); + return *this; + } + + string& string::replace(size_t pos, size_t count, size_t count2, char c) { + if (pos > this->size()) { + throw std::out_of_range("gd::string::replace"); + } + impl.replace(pos, count, count2, c); + return *this; + } + + string& string::replace(const_iterator first, const_iterator last, size_t count2, char c) { + size_t index = first - this->begin(); + impl.replace(index, last - first, count2, c); + return *this; + } + + string& string::operator+=(string const& other) { + impl.append(other); + return *this; + } + + string& string::operator+=(char const* other) { + impl.append(other); + return *this; + } + + string& string::operator+=(char c) { + impl.append(1, c); + return *this; + } + char& string::at(size_t pos) { if (pos >= this->size()) throw std::out_of_range("gd::string::at"); @@ -83,13 +399,44 @@ namespace gd { char& string::operator[](size_t pos) { return impl.getStorage()[pos]; } char const& string::operator[](size_t pos) const { return impl.getStorage()[pos]; } + char& string::front() { return impl.getStorage()[0]; } + char const& string::front() const { return impl.getStorage()[0]; } + char& string::back() { return impl.getStorage()[this->size() - 1]; } + char const& string::back() const { return impl.getStorage()[this->size() - 1]; } + char* string::data() { return impl.getStorage(); } char const* string::data() const { return impl.getStorage(); } char const* string::c_str() const { return this->data(); } size_t string::size() const { return impl.getSize(); } + size_t string::length() const { return this->size(); } size_t string::capacity() const { return impl.getCapacity(); } bool string::empty() const { return this->size() == 0; } + size_t string::max_size() const { + return (npos - sizeof(geode::stl::StringData::Internal) - 1) / 4; + } + + string::iterator makeIter(char* ptr) { + return *reinterpret_cast(&ptr); + } + + string::const_iterator makeIter(char const* ptr) { + return *reinterpret_cast(&ptr); + } + + string::iterator string::begin() { return makeIter(this->data()); } + string::const_iterator string::begin() const { return makeIter(this->data()); } + string::const_iterator string::cbegin() const { return this->begin(); } + string::iterator string::end() { return makeIter(this->data() + this->size()); } + string::const_iterator string::end() const { return makeIter(this->data() + this->size()); } + string::const_iterator string::cend() const { return this->end(); } + + string::reverse_iterator string::rbegin() { return string::reverse_iterator(this->end()); } + string::const_reverse_iterator string::rbegin() const { return string::const_reverse_iterator(this->end()); } + string::const_reverse_iterator string::crbegin() const { return this->rbegin(); } + string::reverse_iterator string::rend() { return string::reverse_iterator(this->begin()); } + string::const_reverse_iterator string::rend() const { return string::const_reverse_iterator(this->begin()); } + string::const_reverse_iterator string::crend() const { return this->rend(); } bool string::operator==(string const& other) const { return std::string_view(*this) == std::string_view(other); diff --git a/loader/src/platform/android/gdstdlib.cpp b/loader/src/platform/android/gdstdlib.cpp index 43dd55bed..5e1b62f39 100644 --- a/loader/src/platform/android/gdstdlib.cpp +++ b/loader/src/platform/android/gdstdlib.cpp @@ -101,8 +101,7 @@ namespace geode::stl { char* StringImpl::getStorage() { return reinterpret_cast(data.m_data); } - // TODO: add a copyFrom(string const&) to take advantage - // of gnustl refcounted strings + void StringImpl::setStorage(std::string_view str) { this->free(); @@ -125,17 +124,130 @@ namespace geode::stl { this->getStorage()[str.size()] = 0; } + void StringImpl::setStorage(StringData& str) { + this->free(); + + auto& internal = str.m_data[-1]; + + if (str.m_data[-1].m_refcount < 0) { + this->setStorage(std::string_view(reinterpret_cast(str.m_data), internal.m_size)); + } else { + if (str.m_data != emptyInternalString()) { + ++internal.m_refcount; + } + data.m_data = &internal; + } + } + + void StringImpl::swapStorage(StringData& other) { + std::swap(this->data.m_data, other.m_data); + } + size_t StringImpl::getSize() { return data.m_data[-1].m_size; } - void StringImpl::setSize(size_t size) { - // TODO: implement this, remember its copy-on-write... + void StringImpl::setSize(size_t size, char fill) { + if (size > this->getCapacity()) { + this->setCapacity(size); + } + + if (size > this->getSize()) { + std::memset(this->getStorage() + this->getSize(), fill, size - this->getSize()); + } + + data.m_data[-1].m_size = size; + this->getStorage()[size] = 0; } size_t StringImpl::getCapacity() { return data.m_data[-1].m_capacity; } void StringImpl::setCapacity(size_t cap) { - // TODO: implement this, remember its copy-on-write... + if (cap == this->getCapacity()) return; + + StringData::Internal internal; + internal.m_size = this->getSize(); + internal.m_capacity = cap; + internal.m_refcount = 0; + + // use char* so we can do easy pointer arithmetic with it + auto* buffer = static_cast(gd::operatorNew(cap + 1 + sizeof(internal))); + std::memcpy(buffer, &internal, sizeof(internal)); + std::memcpy(buffer + sizeof(internal), this->getStorage(), this->getSize()); + + this->free(); + data.m_data = reinterpret_cast(buffer + sizeof(internal)); + + this->getStorage()[this->getSize()] = 0; + } + + void StringImpl::append(std::string_view str) { + if (str.size() == 0) return; + + size_t oldSize = this->getSize(); + this->setSize(oldSize + str.size(), 0); + std::memcpy(this->getStorage() + oldSize, str.data(), str.size()); + } + + void StringImpl::append(size_t count, char c) { + if (count == 0) return; + + this->setSize(this->getSize() + count, c); + } + + void StringImpl::insert(size_t pos, std::string_view str) { + if (str.size() == 0) return; + + size_t oldSize = this->getSize(); + this->setSize(oldSize + str.size(), 0); + std::memmove(this->getStorage() + pos + str.size(), this->getStorage() + pos, oldSize - pos); + std::memcpy(this->getStorage() + pos, str.data(), str.size()); + } + + void StringImpl::insert(size_t pos, size_t count, char c) { + if (count == 0) return; + + size_t oldSize = this->getSize(); + this->setSize(oldSize + count, 0); + std::memmove(this->getStorage() + pos + count, this->getStorage() + pos, oldSize - pos); + std::memset(this->getStorage() + pos, c, count); + } + + void StringImpl::erase(size_t pos, size_t count) { + if (count == 0) return; + + size_t oldSize = this->getSize(); + count = std::min(count, oldSize - pos); + + std::memmove(this->getStorage() + pos, this->getStorage() + pos + count, oldSize - pos - count); + this->setSize(oldSize - count, 0); + } + + void StringImpl::replace(size_t pos, size_t count, std::string_view other) { + if (count == 0 && other.size() == 0) return; + + size_t oldSize = this->getSize(); + count = std::min(count, oldSize - pos); + + if (other.size() > count) { + this->setSize(oldSize + other.size() - count, 0); + } + + std::memmove(this->getStorage() + pos + other.size(), this->getStorage() + pos + count, oldSize - pos - count); + std::memcpy(this->getStorage() + pos, other.data(), other.size()); + } + + void StringImpl::replace(size_t pos, size_t count, size_t count2, char c) { + if (count == 0 && count2 == 0) return; + + size_t oldSize = this->getSize(); + count = std::min(count, oldSize - pos); + + if (count2 > count) { + this->setSize(oldSize + count2 - count, 0); + } + + std::memmove(this->getStorage() + pos + count2, this->getStorage() + pos + count, oldSize - pos - count); + std::memset(this->getStorage() + pos, c, count2); } } From 5319a365245dd33194b436c12b8c215033623fca Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:29:18 -0500 Subject: [PATCH 2/3] Parameter names --- loader/include/Geode/c++stl/string.hpp | 42 +++++++++++++------------- loader/src/c++stl/string-impl.hpp | 24 +++++++-------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/loader/include/Geode/c++stl/string.hpp b/loader/include/Geode/c++stl/string.hpp index 74ee8b67b..a5af908f0 100644 --- a/loader/include/Geode/c++stl/string.hpp +++ b/loader/include/Geode/c++stl/string.hpp @@ -78,17 +78,17 @@ namespace gd { static const size_t npos = -1; string(); - string(string const&); - string(string&&); - string(char const*); - string(char const*, size_t); - string(size_t, char); - string(std::string const&); - string(std::initializer_list); - string(string const&, size_t); - string(string const&, size_t, size_t); - string(string&&, size_t); - string(string&&, size_t, size_t); + string(string const& str); + string(string&& other); + string(char const* str); + string(char const* str, size_t count); + string(size_t count, char c); + string(std::string const& str); + string(std::initializer_list ilist); + string(string const& other, size_t pos); + string(string const& other, size_t pos, size_t count); + string(string&& other, size_t pos); + string(string&& other, size_t pos, size_t count); template requires std::convertible_to @@ -145,12 +145,12 @@ namespace gd { return this->assign(std::ranges::begin(range), std::ranges::end(range)); } - string& operator=(string const&); - string& operator=(string&&); - string& operator=(char const*); - string& operator=(char); - string& operator=(std::initializer_list); - string& operator=(std::string const&); + string& operator=(string const& other); + string& operator=(string&& other); + string& operator=(char const* other); + string& operator=(char other); + string& operator=(std::initializer_list ilist); + string& operator=(std::string const& other); template requires std::convertible_to @@ -208,10 +208,10 @@ namespace gd { return this->append(std::ranges::begin(range), std::ranges::end(range)); } - string& operator+=(string const&); - string& operator+=(char const*); - string& operator+=(char); - string& operator+=(std::initializer_list); + string& operator+=(string const& other); + string& operator+=(char const* other); + string& operator+=(char c); + string& operator+=(std::initializer_list ilist); template requires std::convertible_to diff --git a/loader/src/c++stl/string-impl.hpp b/loader/src/c++stl/string-impl.hpp index f9b0934dc..aae8439b6 100644 --- a/loader/src/c++stl/string-impl.hpp +++ b/loader/src/c++stl/string-impl.hpp @@ -13,22 +13,22 @@ namespace geode::stl { void free(); char* getStorage(); - void setStorage(std::string_view); - void setStorage(StringData&); - void swapStorage(StringData&); + void setStorage(std::string_view str); + void setStorage(StringData& other); + void swapStorage(StringData& other); size_t getSize(); - void setSize(size_t, char); + void setSize(size_t size, char fill); size_t getCapacity(); - void setCapacity(size_t); + void setCapacity(size_t capacity); - void append(std::string_view); - void append(size_t, char); - void insert(size_t, std::string_view); - void insert(size_t, size_t, char); - void erase(size_t, size_t); - void replace(size_t, size_t, std::string_view); - void replace(size_t, size_t, size_t, char); + void append(std::string_view str); + void append(size_t count, char c); + void insert(size_t pos, std::string_view str); + void insert(size_t pos, size_t count, char c); + void erase(size_t pos, size_t count); + void replace(size_t pos, size_t count, std::string_view str); + void replace(size_t pos, size_t count, size_t count2, char c); }; } \ No newline at end of file From 24159485e44f087ef49ca3554b042d124b7778da Mon Sep 17 00:00:00 2001 From: Jasmine <52604018+hiimjasmine00@users.noreply.github.com> Date: Mon, 2 Mar 2026 07:01:03 -0500 Subject: [PATCH 3/3] More inline definitions --- loader/include/Geode/c++stl/string.hpp | 410 +++++++++++++++++-------- loader/src/c++stl/string.cpp | 211 +------------ 2 files changed, 288 insertions(+), 333 deletions(-) diff --git a/loader/include/Geode/c++stl/string.hpp b/loader/include/Geode/c++stl/string.hpp index a5af908f0..723bbe280 100644 --- a/loader/include/Geode/c++stl/string.hpp +++ b/loader/include/Geode/c++stl/string.hpp @@ -79,7 +79,7 @@ namespace gd { string(); string(string const& str); - string(string&& other); + string(string&& other) noexcept; string(char const* str); string(char const* str, size_t count); string(size_t count, char c); @@ -111,12 +111,35 @@ namespace gd { ~string(); string& assign(string const& other); - string& assign(string&& other); - string& assign(char const* other); string& assign(char const* other, size_t count); - string& assign(string const& other, size_t pos, size_t count = npos); - string& assign(std::initializer_list ilist); - string& assign(size_t count, char c); + + string& assign(string&& other) { + this->swap(other); + other.clear(); + return *this; + } + + string& assign(char const* other) { + this->assign(other, std::char_traits::length(other)); + return *this; + } + + string& assign(string const& other, size_t pos, size_t count = npos) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::assign"); + } + return this->assign(other.data() + pos, std::min(count, other.size() - pos)); + } + + string& assign(std::initializer_list ilist) { + return this->assign(ilist.begin(), ilist.size()); + } + + string& assign(size_t count, char c) { + this->clear(); + this->resize(count, c); + return *this; + } template requires std::convertible_to @@ -146,12 +169,18 @@ namespace gd { } string& operator=(string const& other); - string& operator=(string&& other); + string& operator=(string&& other) noexcept; string& operator=(char const* other); - string& operator=(char other); - string& operator=(std::initializer_list ilist); string& operator=(std::string const& other); + string& operator=(char other) { + return this->assign(1, other); + } + + string& operator=(std::initializer_list ilist) { + return this->assign(ilist); + } + template requires std::convertible_to string& operator=(T const& other) { @@ -163,24 +192,53 @@ namespace gd { void reserve(size_t capacity); void resize(size_t size, char fill = '\0'); - void push_back(char c); - void pop_back(); - size_t copy(char* buffer, size_t count, size_t pos = 0) const; void shrink_to_fit(); + void push_back(char c) { + this->append(1, c); + } + + void pop_back() { + this->resize(this->size() - 1); + } + + size_t copy(char* buffer, size_t count, size_t pos = 0) const { + if (pos > this->size()) { + throw std::out_of_range("gd::string::copy"); + } + size_t toCopy = std::min(count, this->size() - pos); + std::memcpy(buffer, this->data() + pos, toCopy); + return toCopy; + } + template void resize_and_overwrite(size_t newSize, Operation op) { this->resize(newSize); this->erase(op(this->data(), newSize)); } - string& append(char const* other); string& append(char const* other, size_t count); - string& append(string const& other); - string& append(string const& other, size_t pos, size_t count = npos); - string& append(std::initializer_list ilist); string& append(size_t count, char c); + string& append(char const* other) { + return this->append(other, std::char_traits::length(other)); + } + + string& append(string const& other) { + return this->append(other.data(), other.size()); + } + + string& append(string const& other, size_t pos, size_t count = npos) { + if (pos > other.size()) { + throw std::out_of_range("gd::string::append"); + } + return this->append(other.data() + pos, std::min(count, other.size() - pos)); + } + + string& append(std::initializer_list ilist) { + return this->append(ilist.begin(), ilist.size()); + } + template requires std::convertible_to string& append(T const& other) { @@ -208,10 +266,21 @@ namespace gd { return this->append(std::ranges::begin(range), std::ranges::end(range)); } - string& operator+=(string const& other); - string& operator+=(char const* other); - string& operator+=(char c); - string& operator+=(std::initializer_list ilist); + string& operator+=(string const& other) { + return this->append(other); + } + + string& operator+=(char const* other) { + return this->append(other); + } + + string& operator+=(char c) { + return this->append(1, c); + } + + string& operator+=(std::initializer_list ilist) { + return this->append(ilist); + } template requires std::convertible_to @@ -219,15 +288,30 @@ namespace gd { return this->append(std::string_view(other)); } - string& insert(size_t pos, char const* other); string& insert(size_t pos, char const* other, size_t count); - string& insert(size_t pos, string const& other); - string& insert(size_t pos, string const& other, size_t pos2, size_t count = npos); - iterator insert(const_iterator pos, char c); iterator insert(const_iterator pos, size_t count, char c); iterator insert(const_iterator pos, std::initializer_list ilist); string& insert(size_t pos, size_t count, char c); + string& insert(size_t pos, char const* other) { + return this->insert(pos, other, std::char_traits::length(other)); + } + + string& insert(size_t pos, string const& other) { + return this->insert(pos, other.data(), other.size()); + } + + string& insert(size_t pos, string const& other, size_t pos2, size_t count = npos) { + if (pos2 > other.size()) { + throw std::out_of_range("gd::string::insert"); + } + return this->insert(pos, other.data() + pos2, std::min(count, other.size() - pos2)); + } + + iterator insert(const_iterator pos, char c) { + return this->insert(pos, 1, c); + } + template iterator insert(const_iterator pos, It first, It last) { size_t index = pos - this->begin(); @@ -253,20 +337,44 @@ namespace gd { } string& erase(size_t pos = 0, size_t count = npos); - iterator erase(const_iterator pos); iterator erase(const_iterator first, const_iterator last); - string& replace(size_t pos, size_t count, string const& other); - string& replace(const_iterator first, const_iterator last, string const& other); - string& replace(size_t pos, size_t count, string const& other, size_t pos2, size_t count2 = npos); - string& replace(size_t pos, size_t count, char const* other); + iterator erase(const_iterator pos) { + return this->erase(pos, pos + 1); + } + string& replace(size_t pos, size_t count, char const* other, size_t count2); - string& replace(const_iterator first, const_iterator last, char const* other); string& replace(const_iterator first, const_iterator last, char const* other, size_t count2); - string& replace(const_iterator first, const_iterator last, std::initializer_list ilist); string& replace(size_t pos, size_t count, size_t count2, char c); string& replace(const_iterator first, const_iterator last, size_t count2, char c); + string& replace(size_t pos, size_t count, string const& other) { + return this->replace(pos, count, other.data(), other.size()); + } + + string& replace(const_iterator first, const_iterator last, string const& other) { + return this->replace(first, last, other.data(), other.size()); + } + + string& replace(size_t pos, size_t count, string const& other, size_t pos2, size_t count2 = npos) { + if (pos2 > other.size()) { + throw std::out_of_range("gd::string::replace"); + } + return this->replace(pos, count, other.data() + pos2, std::min(count2, other.size() - pos2)); + } + + string& replace(size_t pos, size_t count, char const* other) { + return this->replace(pos, count, other, std::char_traits::length(other)); + } + + string& replace(const_iterator first, const_iterator last, char const* other) { + return this->replace(first, last, other, std::char_traits::length(other)); + } + + string& replace(const_iterator first, const_iterator last, std::initializer_list ilist) { + return this->replace(first, last, ilist.begin(), ilist.size()); + } + template string& replace(const_iterator first, const_iterator last, It first2, It last2) { this->replace(first, last, std::to_address(first2), std::distance(first2, last2)); @@ -322,34 +430,74 @@ namespace gd { char& operator[](size_t pos); char const& operator[](size_t pos) const; - char& front(); - char const& front() const; - char& back(); - char const& back() const; + char& front() { + return this->data()[0]; + } + + char const& front() const { + return this->data()[0]; + } + + char& back() { + return this->data()[this->size() - 1]; + } + + char const& back() const { + return this->data()[this->size() - 1]; + } char* data(); char const* data() const; char const* c_str() const; size_t size() const; - size_t length() const; size_t capacity() const; bool empty() const; - size_t max_size() const; + + size_t length() const { + return this->size(); + } + + size_t max_size() const { + return (npos - sizeof(geode::stl::StringData::Internal) - 1) / 4; + } iterator begin(); const_iterator begin() const; - const_iterator cbegin() const; iterator end(); const_iterator end() const; - const_iterator cend() const; - reverse_iterator rbegin(); - const_reverse_iterator rbegin() const; - const_reverse_iterator crbegin() const; - reverse_iterator rend(); - const_reverse_iterator rend() const; - const_reverse_iterator crend() const; + const_iterator cbegin() const { + return this->begin(); + } + + const_iterator cend() const { + return this->end(); + } + + reverse_iterator rbegin() { + return reverse_iterator(this->end()); + } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(this->end()); + } + + const_reverse_iterator crbegin() const { + return this->rbegin(); + } + + reverse_iterator rend() { + return reverse_iterator(this->begin()); + } + + const_reverse_iterator rend() const { + return const_reverse_iterator(this->begin()); + } + + const_reverse_iterator crend() const { + return this->rend(); + } int compare(string const& other) const { return std::string_view(*this).compare(other); @@ -544,92 +692,92 @@ namespace gd { operator std::string_view() const; }; - inline string operator+(string const& lhs, string const& rhs) { - string out = lhs; - out += rhs; - return out; - } - - inline string operator+(string const& lhs, char const* rhs) { - string out = lhs; - out += rhs; - return out; - } - - inline string operator+(char const* lhs, string const& rhs) { - string out = lhs; - out += rhs; - return out; - } - - inline string operator+(string const& lhs, char rhs) { - string out = lhs; - out += rhs; - return out; - } - - inline string operator+(char lhs, string const& rhs) { - string out = string(1, lhs); - out += rhs; - return out; - } - - inline string operator+(string const& lhs, std::type_identity_t rhs) { - string out = lhs; - out += rhs; - return out; - } - - inline string operator+(std::type_identity_t lhs, string const& rhs) { - string out = string(lhs); - out += rhs; - return out; - } - - inline string operator+(string&& lhs, string const& rhs) { - lhs += rhs; - return std::move(lhs); - } - - inline string operator+(string const& lhs, string&& rhs) { - rhs.insert(0, lhs); - return std::move(rhs); - } - - inline string operator+(string&& lhs, string&& rhs) { - lhs += rhs; - return std::move(lhs); - } - - inline string operator+(string&& lhs, char const* rhs) { - lhs += rhs; - return std::move(lhs); - } - - inline string operator+(char const* lhs, string&& rhs) { - rhs.insert(0, lhs); - return std::move(rhs); - } - - inline string operator+(string&& lhs, char rhs) { - lhs += rhs; - return std::move(lhs); - } - - inline string operator+(char lhs, string&& rhs) { - rhs.insert(0, 1, lhs); - return std::move(rhs); - } - - inline string operator+(string&& lhs, std::type_identity_t rhs) { - lhs += rhs; - return std::move(lhs); - } - - inline string operator+(std::type_identity_t lhs, string&& rhs) { - rhs.insert(0, lhs); - return std::move(rhs); - } + inline string operator+(string const& lhs, string const& rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(string const& lhs, char const* rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(char const* lhs, string const& rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(string const& lhs, char rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(char lhs, string const& rhs) { + string out = string(1, lhs); + out += rhs; + return out; + } + + inline string operator+(string const& lhs, std::type_identity_t rhs) { + string out = lhs; + out += rhs; + return out; + } + + inline string operator+(std::type_identity_t lhs, string const& rhs) { + string out = string(lhs); + out += rhs; + return out; + } + + inline string operator+(string&& lhs, string const& rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(string const& lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, string&& rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(string&& lhs, char const* rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(char const* lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, char rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(char lhs, string&& rhs) { + rhs.insert(0, 1, lhs); + return std::move(rhs); + } + + inline string operator+(string&& lhs, std::type_identity_t rhs) { + lhs += rhs; + return std::move(lhs); + } + + inline string operator+(std::type_identity_t lhs, string&& rhs) { + rhs.insert(0, lhs); + return std::move(rhs); + } inline std::string_view format_as(gd::string const& str) { return std::string_view(str); diff --git a/loader/src/c++stl/string.cpp b/loader/src/c++stl/string.cpp index 903d77d5b..ee78b1017 100644 --- a/loader/src/c++stl/string.cpp +++ b/loader/src/c++stl/string.cpp @@ -23,7 +23,7 @@ namespace gd { impl.setStorage(intoMutRef(str.m_data)); } - string::string(string&& other) { + string::string(string&& other) noexcept { impl.swapStorage(other.m_data); implFor(other).setEmpty(); } @@ -86,18 +86,7 @@ namespace gd { } string& string::assign(string const& other) { - impl.setStorage(other); - return *this; - } - - string& string::assign(string&& other) { - impl.swapStorage(other.m_data); - implFor(other).setEmpty(); - return *this; - } - - string& string::assign(char const* other) { - impl.setStorage(other); + impl.setStorage(intoMutRef(other.m_data)); return *this; } @@ -106,33 +95,14 @@ namespace gd { return *this; } - string& string::assign(string const& other, size_t pos, size_t count) { - if (pos > other.size()) { - throw std::out_of_range("gd::string::assign"); - } - - impl.setStorage(std::string_view(other.data() + pos, std::min(count, other.size() - pos))); - return *this; - } - - string& string::assign(std::initializer_list ilist) { - impl.setStorage(std::string_view(ilist.begin(), ilist.size())); - return *this; - } - - string& string::assign(size_t count, char c) { - impl.setSize(count, c); - return *this; - } - string& string::operator=(string const& other) { // check if the strings share the same storage if (this->m_data.m_data != other.m_data.m_data) { - impl.setStorage(other); + impl.setStorage(intoMutRef(other.m_data)); } return *this; } - string& string::operator=(string&& other) { + string& string::operator=(string&& other) noexcept { impl.swapStorage(other.m_data); implFor(other).setEmpty(); return *this; @@ -141,18 +111,6 @@ namespace gd { impl.setStorage(other); return *this; } - string& string::operator=(char other) { - impl.setSize(1, other); - return *this; - } - string& string::operator=(std::initializer_list ilist) { - impl.setStorage(std::string_view(ilist.begin(), ilist.size())); - return *this; - } - string& string::operator=(std::string const& other) { - impl.setStorage(other); - return *this; - } void string::clear() { impl.setEmpty(); @@ -170,68 +128,20 @@ namespace gd { impl.setSize(size, fill); } - void string::push_back(char c) { - impl.append(1, c); - } - - void string::pop_back() { - impl.setSize(this->size() - 1, 0); - } - - size_t string::copy(char* buffer, size_t count, size_t pos) const { - if (pos > this->size()) { - throw std::out_of_range("gd::string::copy"); - } - size_t toCopy = std::min(count, this->size() - pos); - std::memcpy(buffer, this->data() + pos, toCopy); - return toCopy; - } - void string::shrink_to_fit() { impl.setCapacity(this->size()); } - string& string::append(char const* other) { - impl.append(other); - return *this; - } - string& string::append(char const* other, size_t count) { impl.append(std::string_view(other, count)); return *this; } - string& string::append(string const& other) { - impl.append(other); - return *this; - } - - string& string::append(string const& other, size_t pos, size_t count) { - if (pos > other.size()) { - throw std::out_of_range("gd::string::append"); - } - impl.append(std::string_view(other.data() + pos, std::min(count, other.size() - pos))); - return *this; - } - - string& string::append(std::initializer_list ilist) { - impl.append(std::string_view(ilist.begin(), ilist.size())); - return *this; - } - string& string::append(size_t count, char c) { impl.append(count, c); return *this; } - string& string::insert(size_t pos, char const* other) { - if (pos > this->size()) { - throw std::out_of_range("gd::string::insert"); - } - impl.insert(pos, other); - return *this; - } - string& string::insert(size_t pos, char const* other, size_t count) { if (pos > this->size()) { throw std::out_of_range("gd::string::insert"); @@ -240,36 +150,14 @@ namespace gd { return *this; } - string& string::insert(size_t pos, string const& other) { - if (pos > this->size()) { - throw std::out_of_range("gd::string::insert"); - } - impl.insert(pos, other); - return *this; - } - - string& string::insert(size_t pos, string const& other, size_t pos2, size_t count) { - if (pos > this->size() || pos2 > other.size()) { - throw std::out_of_range("gd::string::insert"); - } - impl.insert(pos, std::string_view(other.data() + pos2, std::min(count, other.size() - pos2))); - return *this; - } - - string::iterator string::insert(const_iterator pos, char c) { - size_t index = pos - this->begin(); - impl.insert(index, 1, c); - return this->begin() + index; - } - string::iterator string::insert(const_iterator pos, size_t count, char c) { - size_t index = pos - this->begin(); + size_t index = pos - this->cbegin(); impl.insert(index, count, c); return this->begin() + index; } string::iterator string::insert(const_iterator pos, std::initializer_list ilist) { - size_t index = pos - this->begin(); + size_t index = pos - this->cbegin(); impl.insert(index, std::string_view(ilist.begin(), ilist.size())); return this->begin() + index; } @@ -290,48 +178,12 @@ namespace gd { return *this; } - string::iterator string::erase(const_iterator pos) { - size_t index = pos - this->begin(); - impl.erase(index, 1); - return this->begin() + index; - } - string::iterator string::erase(const_iterator first, const_iterator last) { - size_t index = first - this->begin(); + size_t index = first - this->cbegin(); impl.erase(index, last - first); return this->begin() + index; } - string& string::replace(size_t pos, size_t count, string const& other) { - if (pos > this->size()) { - throw std::out_of_range("gd::string::replace"); - } - impl.replace(pos, count, other); - return *this; - } - - string& string::replace(const_iterator first, const_iterator last, string const& other) { - size_t index = first - this->begin(); - impl.replace(index, last - first, other); - return *this; - } - - string& string::replace(size_t pos, size_t count, string const& other, size_t pos2, size_t count2) { - if (pos > this->size() || pos2 > other.size()) { - throw std::out_of_range("gd::string::replace"); - } - impl.replace(pos, count, std::string_view(other.data() + pos2, std::min(count2, other.size() - pos2))); - return *this; - } - - string& string::replace(size_t pos, size_t count, char const* other) { - if (pos > this->size()) { - throw std::out_of_range("gd::string::replace"); - } - impl.replace(pos, count, other); - return *this; - } - string& string::replace(size_t pos, size_t count, char const* other, size_t count2) { if (pos > this->size()) { throw std::out_of_range("gd::string::replace"); @@ -340,24 +192,12 @@ namespace gd { return *this; } - string& string::replace(const_iterator first, const_iterator last, char const* other) { - size_t index = first - this->begin(); - impl.replace(index, last - first, other); - return *this; - } - string& string::replace(const_iterator first, const_iterator last, char const* other, size_t count2) { - size_t index = first - this->begin(); + size_t index = first - this->cbegin(); impl.replace(index, last - first, std::string_view(other, count2)); return *this; } - string& string::replace(const_iterator first, const_iterator last, std::initializer_list ilist) { - size_t index = first - this->begin(); - impl.replace(index, last - first, std::string_view(ilist.begin(), ilist.size())); - return *this; - } - string& string::replace(size_t pos, size_t count, size_t count2, char c) { if (pos > this->size()) { throw std::out_of_range("gd::string::replace"); @@ -367,26 +207,11 @@ namespace gd { } string& string::replace(const_iterator first, const_iterator last, size_t count2, char c) { - size_t index = first - this->begin(); + size_t index = first - this->cbegin(); impl.replace(index, last - first, count2, c); return *this; } - string& string::operator+=(string const& other) { - impl.append(other); - return *this; - } - - string& string::operator+=(char const* other) { - impl.append(other); - return *this; - } - - string& string::operator+=(char c) { - impl.append(1, c); - return *this; - } - char& string::at(size_t pos) { if (pos >= this->size()) throw std::out_of_range("gd::string::at"); @@ -399,22 +224,13 @@ namespace gd { char& string::operator[](size_t pos) { return impl.getStorage()[pos]; } char const& string::operator[](size_t pos) const { return impl.getStorage()[pos]; } - char& string::front() { return impl.getStorage()[0]; } - char const& string::front() const { return impl.getStorage()[0]; } - char& string::back() { return impl.getStorage()[this->size() - 1]; } - char const& string::back() const { return impl.getStorage()[this->size() - 1]; } - char* string::data() { return impl.getStorage(); } char const* string::data() const { return impl.getStorage(); } char const* string::c_str() const { return this->data(); } size_t string::size() const { return impl.getSize(); } - size_t string::length() const { return this->size(); } size_t string::capacity() const { return impl.getCapacity(); } bool string::empty() const { return this->size() == 0; } - size_t string::max_size() const { - return (npos - sizeof(geode::stl::StringData::Internal) - 1) / 4; - } string::iterator makeIter(char* ptr) { return *reinterpret_cast(&ptr); @@ -426,17 +242,8 @@ namespace gd { string::iterator string::begin() { return makeIter(this->data()); } string::const_iterator string::begin() const { return makeIter(this->data()); } - string::const_iterator string::cbegin() const { return this->begin(); } string::iterator string::end() { return makeIter(this->data() + this->size()); } string::const_iterator string::end() const { return makeIter(this->data() + this->size()); } - string::const_iterator string::cend() const { return this->end(); } - - string::reverse_iterator string::rbegin() { return string::reverse_iterator(this->end()); } - string::const_reverse_iterator string::rbegin() const { return string::const_reverse_iterator(this->end()); } - string::const_reverse_iterator string::crbegin() const { return this->rbegin(); } - string::reverse_iterator string::rend() { return string::reverse_iterator(this->begin()); } - string::const_reverse_iterator string::rend() const { return string::const_reverse_iterator(this->begin()); } - string::const_reverse_iterator string::crend() const { return this->rend(); } bool string::operator==(string const& other) const { return std::string_view(*this) == std::string_view(other);