mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
refactor gd::string
This commit is contained in:
parent
cc4dfc1ba4
commit
24bbc65f19
10 changed files with 298 additions and 355 deletions
|
@ -58,6 +58,7 @@ file(GLOB SOURCES CONFIGURE_DEPENDS
|
|||
src/ui/internal/info/*.cpp
|
||||
src/ui/internal/list/*.cpp
|
||||
src/ui/internal/settings/*.cpp
|
||||
src/c++stl/*.cpp
|
||||
hash/hash.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
namespace geode::stl {
|
||||
|
||||
template <class Type>
|
||||
class AllocatorTemplate {
|
||||
protected:
|
||||
inline Type* allocate(size_t count);
|
||||
inline void deallocate(Type* pointer);
|
||||
};
|
||||
|
||||
#if defined(GEODE_IS_WINDOWS)
|
||||
template <class Type>
|
||||
class AllocatorBase {
|
||||
protected:
|
||||
inline Type* allocate(size_t count) {
|
||||
|
||||
}
|
||||
inline void deallocate(Type* pointer) {
|
||||
|
||||
}
|
||||
};
|
||||
#elif defined(GEODE_IS_MACOS) || defined(GEODE_IS_ANDROID)
|
||||
|
||||
#elif defined(GEODE_IS_IOS)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class StringTemplate : public AllocatorBase {
|
||||
protected:
|
||||
// depends on already set size and capacity
|
||||
inline void setStorage(char* pointer) = delete;
|
||||
inline char* getStorage() = delete;
|
||||
|
||||
inline void setSize(size_t size) = delete;
|
||||
inline size_t getSize() = delete;
|
||||
|
||||
inline void setCapacity(size_t capacity) = delete;
|
||||
inline size_t getCapacity() = delete;
|
||||
};
|
||||
|
||||
#if defined(GEODE_IS_WINDOWS)
|
||||
class StringBase : public StringTemplate {
|
||||
protected:
|
||||
union {
|
||||
std::array<char, 16> m_smallStorage;
|
||||
char* m_bigStorage;
|
||||
};
|
||||
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
|
||||
inline void setStorage(char* storage) {
|
||||
if (m_capacity > 15) {
|
||||
return m_bigStorage = storage;
|
||||
}
|
||||
}
|
||||
inline char* getStorage() {
|
||||
if (m_capacity > 15) {
|
||||
return m_bigStorage;
|
||||
}
|
||||
return m_smallStorage.data();
|
||||
}
|
||||
|
||||
inline void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
inline size_t getSize() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
inline void setCapacity(size_t capacity) {
|
||||
m_capacity = capacity;
|
||||
}
|
||||
inline size_t getCapacity() {
|
||||
return m_capacity;
|
||||
}
|
||||
};
|
||||
#elif defined(GEODE_IS_MACOS) || defined(GEODE_IS_ANDROID)
|
||||
class StringBase : public StringTemplate {
|
||||
protected:
|
||||
char* m_storage;
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
|
||||
inline void setStorage(char* storage) {
|
||||
m_storage = storage;
|
||||
}
|
||||
inline char* getStorage() {
|
||||
return m_storage;
|
||||
}
|
||||
|
||||
inline void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
inline size_t getSize() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
inline void setCapacity(size_t capacity) {
|
||||
m_capacity = capacity;
|
||||
}
|
||||
inline size_t getCapacity() {
|
||||
return m_capacity;
|
||||
}
|
||||
};
|
||||
#elif defined(GEODE_IS_IOS)
|
||||
class StringBase : public StringTemplate {
|
||||
protected:
|
||||
struct Short {
|
||||
uint8_t sizex2;
|
||||
std::array<char, 23> shortStorage;
|
||||
};
|
||||
|
||||
struct Long {
|
||||
size_t capacitym1;
|
||||
size_t size;
|
||||
char* longStorage;
|
||||
};
|
||||
|
||||
union {
|
||||
Short m_short;
|
||||
Long m_long;
|
||||
};
|
||||
|
||||
inline void setStorage(char* storage) {
|
||||
m_storage = storage;
|
||||
}
|
||||
inline char* getStorage() {
|
||||
return m_storage;
|
||||
}
|
||||
|
||||
inline void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
inline size_t getSize() {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
inline void setCapacity(size_t capacity) {
|
||||
m_capacity = capacity;
|
||||
}
|
||||
inline size_t getCapacity() {
|
||||
return m_capacity;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <Geode/platform/platform.hpp>
|
||||
|
||||
#include "string-base.hpp"
|
||||
|
||||
#if defined(GEODE_IS_WINDOWS)
|
||||
#include "msvcstl.hpp"
|
||||
#else
|
||||
|
|
|
@ -19,43 +19,6 @@ namespace geode::base {
|
|||
namespace gd {
|
||||
using namespace geode::stl;
|
||||
|
||||
struct _internal_string {
|
||||
size_t m_len;
|
||||
size_t m_capacity;
|
||||
int m_refcount;
|
||||
};
|
||||
|
||||
class GEODE_DLL string {
|
||||
public:
|
||||
string();
|
||||
string(char const* ok);
|
||||
|
||||
string(std::string ok) : string(ok.c_str()) {}
|
||||
|
||||
operator std::string() const {
|
||||
return std::string((char*)m_data, m_data[-1].m_len);
|
||||
}
|
||||
|
||||
bool operator<(string const& other) const;
|
||||
|
||||
bool operator==(string const& other) const;
|
||||
string(string const& ok);
|
||||
string& operator=(char const* ok);
|
||||
string& operator=(string const& ok);
|
||||
__attribute__((noinline)) ~string();
|
||||
|
||||
char const* c_str() const {
|
||||
return (char const*)m_data;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return m_data[-1].m_len;
|
||||
}
|
||||
|
||||
protected:
|
||||
_internal_string* m_data;
|
||||
};
|
||||
|
||||
template <typename K, typename V>
|
||||
class GEODE_DLL map {
|
||||
protected:
|
||||
|
|
|
@ -12,136 +12,6 @@
|
|||
#include <set>
|
||||
|
||||
namespace gd {
|
||||
struct InternalString {
|
||||
union {
|
||||
char m_storage[16];
|
||||
char* m_pointer;
|
||||
};
|
||||
|
||||
size_t m_length;
|
||||
size_t m_capacity;
|
||||
};
|
||||
|
||||
class string {
|
||||
private:
|
||||
InternalString m_data;
|
||||
|
||||
char* get_data() {
|
||||
if (m_data.m_capacity < 16) return m_data.m_storage;
|
||||
return m_data.m_pointer;
|
||||
}
|
||||
|
||||
const char* get_data() const {
|
||||
if (m_data.m_capacity < 16) return m_data.m_storage;
|
||||
return m_data.m_pointer;
|
||||
}
|
||||
|
||||
public:
|
||||
string() {
|
||||
m_data.m_storage[0] = 0;
|
||||
m_data.m_length = 0;
|
||||
m_data.m_capacity = 15;
|
||||
}
|
||||
|
||||
string(string const& param) : string() {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
}
|
||||
|
||||
string(string&& param) : string() {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
}
|
||||
|
||||
string(char const* param) : string() {
|
||||
// (void)this->winAssign(param, std::strlen(param));
|
||||
}
|
||||
|
||||
string(std::string const& param) : string() {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
}
|
||||
|
||||
string& operator=(string const& param) {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(string&& param) {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(char const* param) {
|
||||
// (void)this->winAssign(param, std::strlen(param));
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& operator=(std::string const& param) {
|
||||
// (void)this->winAssign(param.c_str(), param.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
// (void)this->winDtor();
|
||||
}
|
||||
|
||||
~string() {
|
||||
// (void)this->winDtor();
|
||||
}
|
||||
|
||||
char& at(size_t pos) {
|
||||
if (pos >= m_data.m_length) throw std::out_of_range("gd::string::at");
|
||||
return (*this)[pos];
|
||||
}
|
||||
|
||||
char const& at(size_t pos) const {
|
||||
if (pos >= m_data.m_length) throw std::out_of_range("gd::string::at");
|
||||
return (*this)[pos];
|
||||
}
|
||||
|
||||
char& operator[](size_t pos) {
|
||||
return this->get_data()[pos];
|
||||
}
|
||||
|
||||
char const& operator[](size_t pos) const {
|
||||
return this->get_data()[pos];
|
||||
}
|
||||
|
||||
char* data() {
|
||||
return this->get_data();
|
||||
}
|
||||
|
||||
char const* data() const {
|
||||
return this->get_data();
|
||||
}
|
||||
|
||||
char const* c_str() const {
|
||||
return this->get_data();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return m_data.m_length;
|
||||
}
|
||||
|
||||
bool operator<(const gd::string& other) const {
|
||||
return std::string_view(this->c_str(), this->size()) < std::string_view(other.c_str(), other.size());
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return this->size() == 0;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return !this->empty();
|
||||
}
|
||||
|
||||
operator std::string() const {
|
||||
return std::string(this->c_str(), this->size());
|
||||
}
|
||||
|
||||
operator std::string_view() const {
|
||||
return std::string_view(this->c_str(), this->size());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using vector = std::vector<T>;
|
||||
|
||||
|
|
92
loader/include/Geode/c++stl/string-base.hpp
Normal file
92
loader/include/Geode/c++stl/string-base.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
|
||||
namespace geode::stl {
|
||||
class StringImplAdapter;
|
||||
|
||||
struct StringImpl;
|
||||
|
||||
#if defined(GEODE_IS_WINDOWS)
|
||||
struct StringImpl {
|
||||
union {
|
||||
std::array<char, 16> m_smallStorage;
|
||||
char* m_bigStorage;
|
||||
};
|
||||
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
};
|
||||
#elif defined(GEODE_IS_MACOS) || defined(GEODE_IS_ANDROID)
|
||||
struct StringImpl {
|
||||
struct Internal {
|
||||
size_t m_size;
|
||||
size_t m_capacity;
|
||||
int m_refcount;
|
||||
};
|
||||
Internal* m_data;
|
||||
};
|
||||
#elif defined(GEODE_IS_IOS)
|
||||
struct StringImpl {
|
||||
struct Short {
|
||||
uint8_t sizex2;
|
||||
std::array<char, 23> shortStorage;
|
||||
};
|
||||
|
||||
struct Long {
|
||||
size_t capacitym1;
|
||||
size_t size;
|
||||
char* longStorage;
|
||||
};
|
||||
|
||||
union {
|
||||
Short m_short;
|
||||
Long m_long;
|
||||
};
|
||||
};
|
||||
#else
|
||||
using StringImpl = void;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
class GEODE_DLL string {
|
||||
geode::stl::StringImpl m_impl;
|
||||
friend geode::stl::StringImplAdapter;
|
||||
public:
|
||||
string();
|
||||
string(string const&);
|
||||
string(string&&);
|
||||
string(char const*);
|
||||
string(std::string const&);
|
||||
// tried to add a string_view ctor, but got overload errors :(
|
||||
~string();
|
||||
|
||||
string& operator=(string const&);
|
||||
string& operator=(string&&);
|
||||
string& operator=(char const*);
|
||||
string& operator=(std::string const&);
|
||||
|
||||
void clear();
|
||||
|
||||
char& at(size_t pos);
|
||||
char const& at(size_t pos) const;
|
||||
|
||||
char& operator[](size_t pos);
|
||||
char const& operator[](size_t pos) const;
|
||||
|
||||
char* data();
|
||||
char const* data() const;
|
||||
char const* c_str() const;
|
||||
|
||||
size_t size() const;
|
||||
size_t capacity() const;
|
||||
bool empty() const;
|
||||
|
||||
std::strong_ordering operator<=>(const std::string_view other) const;
|
||||
|
||||
operator std::string() const;
|
||||
operator std::string_view() const;
|
||||
};
|
||||
}
|
24
loader/src/c++stl/string-adapter.hpp
Normal file
24
loader/src/c++stl/string-adapter.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include <Geode/c++stl/gdstdlib.hpp>
|
||||
|
||||
namespace geode::stl {
|
||||
struct StringImplAdapter {
|
||||
StringImpl& impl;
|
||||
|
||||
// clear but assumes the existing impl is uninit,
|
||||
// so basically a default ctor
|
||||
void setEmpty();
|
||||
|
||||
// frees the existing string
|
||||
void free();
|
||||
|
||||
char* getStorage();
|
||||
void setStorage(const std::string_view);
|
||||
|
||||
size_t getSize();
|
||||
void setSize(size_t);
|
||||
|
||||
size_t getCapacity();
|
||||
void setCapacity(size_t);
|
||||
};
|
||||
}
|
104
loader/src/c++stl/string.cpp
Normal file
104
loader/src/c++stl/string.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include <Geode/c++stl/gdstdlib.hpp>
|
||||
#include "string-adapter.hpp"
|
||||
|
||||
template <class Type>
|
||||
Type& intoMutRef(const Type& x) {
|
||||
return const_cast<Type&>(x);
|
||||
}
|
||||
|
||||
using geode::stl::StringImplAdapter;
|
||||
|
||||
#define getAdap(x) StringImplAdapter(intoMutRef(x))
|
||||
#define adap getAdap(m_impl)
|
||||
|
||||
namespace gd {
|
||||
string::string() {
|
||||
adap.setEmpty();
|
||||
}
|
||||
|
||||
string::string(string const& str) {
|
||||
adap.setStorage(str);
|
||||
}
|
||||
|
||||
string::string(string&& other) {
|
||||
// TODO: do this better :-)
|
||||
adap.setStorage(other);
|
||||
getAdap(other.m_impl).free();
|
||||
getAdap(other.m_impl).setEmpty();
|
||||
}
|
||||
|
||||
string::string(char const* str) {
|
||||
adap.setStorage(str);
|
||||
}
|
||||
|
||||
string::string(std::string const& str) {
|
||||
adap.setStorage(str);
|
||||
}
|
||||
|
||||
string::~string() {
|
||||
adap.free();
|
||||
adap.setEmpty();
|
||||
}
|
||||
|
||||
string& string::operator=(string const& other) {
|
||||
if (this != &other) {
|
||||
adap.free();
|
||||
adap.setStorage(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
string& string::operator=(string&& other) {
|
||||
// TODO: do this better :-)
|
||||
adap.free();
|
||||
adap.setStorage(other);
|
||||
getAdap(other.m_impl).free();
|
||||
getAdap(other.m_impl).setEmpty();
|
||||
return *this;
|
||||
}
|
||||
string& string::operator=(char const* other) {
|
||||
adap.free();
|
||||
adap.setStorage(other);
|
||||
return *this;
|
||||
}
|
||||
string& string::operator=(std::string const& other) {
|
||||
adap.free();
|
||||
adap.setStorage(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void string::clear() {
|
||||
adap.free();
|
||||
adap.setEmpty();
|
||||
}
|
||||
|
||||
char& string::at(size_t pos) {
|
||||
if (pos >= this->size())
|
||||
throw std::out_of_range("gd::string::at");
|
||||
return adap.getStorage()[pos];
|
||||
}
|
||||
char const& string::at(size_t pos) const {
|
||||
return const_cast<string*>(this)->at(pos);
|
||||
}
|
||||
|
||||
char& string::operator[](size_t pos) { return adap.getStorage()[pos]; }
|
||||
char const& string::operator[](size_t pos) const { return adap.getStorage()[pos]; }
|
||||
|
||||
char* string::data() { return adap.getStorage(); }
|
||||
char const* string::data() const { return adap.getStorage(); }
|
||||
char const* string::c_str() const { return this->data(); }
|
||||
|
||||
size_t string::size() const { return adap.getSize(); }
|
||||
size_t string::capacity() const { return adap.getCapacity(); }
|
||||
bool string::empty() const { return this->size() == 0; }
|
||||
|
||||
std::strong_ordering string::operator<=>(const std::string_view other) const {
|
||||
return std::string_view(*this) <=> other;
|
||||
}
|
||||
|
||||
string::operator std::string() const {
|
||||
return std::string(this->data(), this->size());
|
||||
}
|
||||
string::operator std::string_view() const {
|
||||
return std::string_view(this->data(), this->size());
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <Geode/c++stl/gdstdlib.hpp>
|
||||
#include "../../c++stl/string-adapter.hpp"
|
||||
|
||||
#ifdef GEODE_IS_ANDROID
|
||||
|
||||
|
@ -13,52 +14,44 @@ namespace geode::base {
|
|||
}
|
||||
}
|
||||
|
||||
namespace gd {
|
||||
namespace {
|
||||
static inline auto emptyInternalString() {
|
||||
return reinterpret_cast<_internal_string*>(
|
||||
geode::base::get() + (0xaa1c3c - 0x10000) + sizeof(_internal_string)
|
||||
);
|
||||
}
|
||||
namespace geode::stl {
|
||||
static inline auto emptyInternalString() {
|
||||
return reinterpret_cast<StringImpl::Internal*>(
|
||||
geode::base::get() + (0xaa1c3c - 0x10000) + sizeof(StringImpl::Internal)
|
||||
);
|
||||
}
|
||||
|
||||
string::string() : m_data(nullptr) {
|
||||
m_data = emptyInternalString();
|
||||
void StringImplAdapter::setEmpty() {
|
||||
impl.m_data = emptyInternalString();
|
||||
}
|
||||
|
||||
string::string(char const* ok) : m_data(nullptr) {
|
||||
reinterpret_cast<void (*)(string*, char const*)>(geode::base::get() + (0x753a44 - 0x10000) + 1)(this, ok);
|
||||
void StringImplAdapter::free() {
|
||||
if (impl.m_data == nullptr) return;
|
||||
// TODO: reimplement this
|
||||
reinterpret_cast<void (*)(StringImpl*)>(geode::base::get() + (0x7514c8 - 0x10000) + 1)(&impl.m_data);
|
||||
}
|
||||
|
||||
string::string(string const& ok) : m_data(nullptr) {
|
||||
if (*(string**)(&ok) == nullptr) return;
|
||||
reinterpret_cast<void (*)(string*, string const&)>(geode::base::get() + (0x7530e0 - 0x10000) + 1)(this, ok);
|
||||
char* StringImplAdapter::getStorage() {
|
||||
return reinterpret_cast<char*>(impl.m_data);
|
||||
}
|
||||
void StringImplAdapter::setStorage(const std::string_view str) {
|
||||
this->free();
|
||||
// TODO: should be using char*, size_t at the very least, or yknow, just reimplement it :-)
|
||||
reinterpret_cast<void (*)(StringImpl*, char const*)>(geode::base::get() + (0x753a44 - 0x10000) + 1)(&impl.m_data, str.data());
|
||||
}
|
||||
|
||||
string& string::operator=(char const* ok) {
|
||||
this->~string();
|
||||
new (this) string(ok);
|
||||
return *this;
|
||||
size_t StringImplAdapter::getSize() {
|
||||
return impl.m_data[-1].m_size;
|
||||
}
|
||||
void StringImplAdapter::setSize(size_t size) {
|
||||
// TODO: implement this, remember its copy-on-write...
|
||||
}
|
||||
|
||||
string& string::operator=(string const& ok) {
|
||||
this->~string();
|
||||
new (this) string(ok);
|
||||
return *this;
|
||||
size_t StringImplAdapter::getCapacity() {
|
||||
return impl.m_data[-1].m_capacity;
|
||||
}
|
||||
|
||||
string::~string() {
|
||||
if (m_data == nullptr) return;
|
||||
|
||||
reinterpret_cast<void (*)(string*)>(geode::base::get() + (0x7514c8 - 0x10000) + 1)(this);
|
||||
}
|
||||
|
||||
bool string::operator<(string const& other) const {
|
||||
return std::string(*this) < std::string(other);
|
||||
}
|
||||
|
||||
bool string::operator==(string const& other) const {
|
||||
return std::string(*this) == std::string(other);
|
||||
void StringImplAdapter::setCapacity(size_t cap) {
|
||||
// TODO: implement this, remember its copy-on-write...
|
||||
}
|
||||
}
|
||||
|
||||
|
|
47
loader/src/platform/windows/gdstdlib.cpp
Normal file
47
loader/src/platform/windows/gdstdlib.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "../../c++stl/string-adapter.hpp"
|
||||
|
||||
#ifdef GEODE_IS_WINDOWS
|
||||
|
||||
namespace geode::stl {
|
||||
void StringImplAdapter::setEmpty() {
|
||||
impl.m_size = 0;
|
||||
impl.m_capacity = 15;
|
||||
impl.m_smallStorage[0] = 0;
|
||||
}
|
||||
|
||||
void StringImplAdapter::free() {
|
||||
if (impl.m_capacity > 15) {
|
||||
delete impl.m_bigStorage;
|
||||
}
|
||||
}
|
||||
|
||||
char* StringImplAdapter::getStorage() {
|
||||
return impl.m_capacity <= 15 ? impl.m_smallStorage.data() : impl.m_bigStorage;
|
||||
}
|
||||
void StringImplAdapter::setStorage(const std::string_view str) {
|
||||
impl.m_size = impl.m_capacity = str.size();
|
||||
if (str.size() <= 15) {
|
||||
impl.m_capacity = 15;
|
||||
} else {
|
||||
impl.m_bigStorage = static_cast<char*>(operator new(str.size() + 1));
|
||||
}
|
||||
std::memcpy(getStorage(), str.data(), str.size());
|
||||
getStorage()[str.size()] = 0;
|
||||
}
|
||||
|
||||
size_t StringImplAdapter::getSize() {
|
||||
return impl.m_size;
|
||||
}
|
||||
void StringImplAdapter::setSize(size_t size) {
|
||||
impl.m_size = size;
|
||||
}
|
||||
|
||||
size_t StringImplAdapter::getCapacity() {
|
||||
return impl.m_capacity;
|
||||
}
|
||||
void StringImplAdapter::setCapacity(size_t cap) {
|
||||
impl.m_capacity = cap;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue