#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace nall { struct string; struct string_format; struct string_view { using type = string_view; //view.hpp string_view(); string_view(const string_view& source); string_view(string_view&& source); string_view(const char* data); string_view(const char* data, u32 size); string_view(const string& source); template string_view(P&&... p); ~string_view(); auto operator=(const string_view& source) -> type&; auto operator=(string_view&& source) -> type&; auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; } auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; } explicit operator bool() const; operator const char*() const; auto data() const -> const char*; auto size() const -> u32; auto begin() const { return &_data[0]; } auto end() const { return &_data[size()]; } protected: string* _string; const char* _data; mutable s32 _size; }; //adaptive (SSO + COW) is by far the best choice, the others exist solely to: //1) demonstrate the performance benefit of combining SSO + COW //2) rule out allocator bugs by trying different allocators when needed #define NALL_STRING_ALLOCATOR_ADAPTIVE //#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE //#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION //#define NALL_STRING_ALLOCATOR_VECTOR //cast.hpp template struct stringify; //format.hpp template auto print(P&&...) -> void; template auto print(FILE*, P&&...) -> void; template auto pad(const T& value, long precision = 0, char padchar = ' ') -> string; template auto hex(T value, long precision = 0, char padchar = '0') -> string; template auto octal(T value, long precision = 0, char padchar = '0') -> string; template auto binary(T value, long precision = 0, char padchar = '0') -> string; //match.hpp auto tokenize(const char* s, const char* p) -> bool; auto tokenize(vector& list, const char* s, const char* p) -> bool; //utf8.hpp auto characters(string_view self, s32 offset = 0, s32 length = -1) -> u32; //utility.hpp auto slice(string_view self, s32 offset = 0, s32 length = -1) -> string; template auto fromInteger(char* result, T value) -> char*; template auto fromNatural(char* result, T value) -> char*; template auto fromHex(char* result, T value) -> char*; template auto fromReal(char* str, T value) -> u32; struct string { using type = string; protected: #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) enum : u32 { SSO = 24 }; union { struct { //copy-on-write char* _data; u32* _refs; }; struct { //small-string-optimization char _text[SSO]; }; }; auto _allocate() -> void; auto _copy() -> void; auto _resize() -> void; #endif #if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) char* _data; mutable u32* _refs; auto _allocate() -> char*; auto _copy() -> char*; #endif #if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) enum : u32 { SSO = 24 }; union { char* _data; char _text[SSO]; }; #endif #if defined(NALL_STRING_ALLOCATOR_VECTOR) char* _data; #endif u32 _capacity; u32 _size; public: string(); string(string& source) : string() { operator=(source); } string(const string& source) : string() { operator=(source); } string(string&& source) : string() { operator=(std::move(source)); } template auto get() -> T*; template auto data() const -> const T*; template auto size() const -> u32 { return _size / sizeof(T); } template auto capacity() const -> u32 { return _capacity / sizeof(T); } auto reset() -> type&; auto reserve(u32) -> type&; auto resize(u32) -> type&; auto operator=(const string&) -> type&; auto operator=(string&&) -> type&; template string(T&& s, P&&... p) : string() { append(std::forward(s), std::forward

(p)...); } ~string() { reset(); } explicit operator bool() const { return _size; } operator const char*() const { return (const char*)data(); } operator array_span() { return {(char*)get(), size()}; } operator array_view() const { return {(const char*)data(), size()}; } operator array_span() { return {(u8*)get(), size()}; } operator array_view() const { return {(const u8*)data(), size()}; } auto operator==(const string& source) const -> bool { return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; } auto operator!=(const string& source) const -> bool { return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; } auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; } auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; } auto operator==(string_view source) const -> bool { return compare(source) == 0; } auto operator!=(string_view source) const -> bool { return compare(source) != 0; } auto operator< (string_view source) const -> bool { return compare(source) < 0; } auto operator<=(string_view source) const -> bool { return compare(source) <= 0; } auto operator> (string_view source) const -> bool { return compare(source) > 0; } auto operator>=(string_view source) const -> bool { return compare(source) >= 0; } auto begin() -> char* { return &get()[0]; } auto end() -> char* { return &get()[size()]; } auto begin() const -> const char* { return &data()[0]; } auto end() const -> const char* { return &data()[size()]; } //atoi.hpp auto boolean() const -> bool; auto integer() const -> s64; auto natural() const -> u64; auto hex() const -> u64; auto real() const -> f64; //core.hpp auto operator[](u32) const -> const char&; auto operator()(u32, char = 0) const -> char; template auto assign(P&&...) -> type&; template auto prepend(const T&, P&&...) -> type&; template auto prepend(const nall::string_format&, P&&...) -> type&; template auto _prepend(const stringify&) -> type&; template auto append(const T&, P&&...) -> type&; template auto append(const nall::string_format&, P&&...) -> type&; template auto _append(const stringify&) -> type&; auto length() const -> u32; //find.hpp auto contains(string_view characters) const -> maybe; template auto _find(s32, string_view) const -> maybe; auto find(string_view source) const -> maybe; auto ifind(string_view source) const -> maybe; auto qfind(string_view source) const -> maybe; auto iqfind(string_view source) const -> maybe; auto findFrom(s32 offset, string_view source) const -> maybe; auto ifindFrom(s32 offset, string_view source) const -> maybe; auto findNext(s32 offset, string_view source) const -> maybe; auto ifindNext(s32 offset, string_view source) const -> maybe; auto findPrevious(s32 offset, string_view source) const -> maybe; auto ifindPrevious(s32 offset, string_view source) const -> maybe; //format.hpp auto format(const nall::string_format& params) -> type&; //compare.hpp template static auto _compare(const char*, u32, const char*, u32) -> s32; static auto compare(string_view, string_view) -> s32; static auto icompare(string_view, string_view) -> s32; auto compare(string_view source) const -> s32; auto icompare(string_view source) const -> s32; auto equals(string_view source) const -> bool; auto iequals(string_view source) const -> bool; auto beginsWith(string_view source) const -> bool; auto ibeginsWith(string_view source) const -> bool; auto endsWith(string_view source) const -> bool; auto iendsWith(string_view source) const -> bool; //convert.hpp auto downcase() -> type&; auto upcase() -> type&; auto qdowncase() -> type&; auto qupcase() -> type&; auto transform(string_view from, string_view to) -> type&; //match.hpp auto match(string_view source) const -> bool; auto imatch(string_view source) const -> bool; //replace.hpp template auto _replace(string_view, string_view, long) -> type&; auto replace(string_view from, string_view to, long limit = LONG_MAX) -> type&; auto ireplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; auto qreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; //split.hpp auto split(string_view key, long limit = LONG_MAX) const -> vector; auto isplit(string_view key, long limit = LONG_MAX) const -> vector; auto qsplit(string_view key, long limit = LONG_MAX) const -> vector; auto iqsplit(string_view key, long limit = LONG_MAX) const -> vector; //trim.hpp auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; auto trimLeft(string_view lhs, long limit = LONG_MAX) -> type&; auto trimRight(string_view rhs, long limit = LONG_MAX) -> type&; auto itrim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; auto itrimLeft(string_view lhs, long limit = LONG_MAX) -> type&; auto itrimRight(string_view rhs, long limit = LONG_MAX) -> type&; auto strip() -> type&; auto stripLeft() -> type&; auto stripRight() -> type&; //utf8.hpp auto characters(s32 offset = 0, s32 length = -1) const -> u32; //utility.hpp static auto read(string_view filename) -> string; static auto repeat(string_view pattern, u32 times) -> string; auto fill(char fill = ' ') -> type&; auto hash() const -> u32; auto remove(u32 offset, u32 length) -> type&; auto reverse() -> type&; auto size(s32 length, char fill = ' ') -> type&; auto slice(s32 offset = 0, s32 length = -1) const -> string; }; template<> struct vector : vector_base { using type = vector; using vector_base::vector_base; vector(const vector& source) { vector_base::operator=(source); } vector(vector& source) { vector_base::operator=(source); } vector(vector&& source) { vector_base::operator=(std::move(source)); } template vector(P&&... p) { append(std::forward

(p)...); } auto operator=(const vector& source) -> type& { return vector_base::operator=(source), *this; } auto operator=(vector& source) -> type& { return vector_base::operator=(source), *this; } auto operator=(vector&& source) -> type& { return vector_base::operator=(std::move(source)), *this; } //vector.hpp template auto append(const string&, P&&...) -> type&; auto append() -> type&; auto isort() -> type&; auto find(string_view source) const -> maybe; auto ifind(string_view source) const -> maybe; auto match(string_view pattern) const -> vector; auto merge(string_view separator = "") const -> string; auto strip() -> type&; //split.hpp template auto _split(string_view, string_view, long) -> type&; }; struct string_format : vector { using type = string_format; template string_format(P&&... p) { reserve(sizeof...(p)); append(std::forward

(p)...); } template auto append(const T&, P&&... p) -> type&; auto append() -> type&; }; inline auto operator"" _s(const char* value, std::size_t) -> string { return {value}; } } #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include