diff --git a/octa/string.h b/octa/string.h index 235b9d5..cc4c010 100644 --- a/octa/string.h +++ b/octa/string.h @@ -14,365 +14,363 @@ #include "octa/vector.h" namespace octa { - static constexpr size_t npos = -1; +static constexpr size_t npos = -1; - template> - class StringBase { - octa::Vector<_T> __buf; +template> +class StringBase { + octa::Vector<_T> p_buf; - void __terminate() { - if (__buf.empty() || (__buf.back() != '\0')) __buf.push('\0'); - } - - public: - typedef size_t Size; - typedef ptrdiff_t Difference; - typedef _T Value; - typedef _T &Reference; - typedef const _T &ConstReference; - typedef _T *Pointer; - typedef const _T *ConstPointer; - typedef PointerRange< _T> Range; - typedef PointerRange ConstRange; - typedef _A Allocator; - - StringBase(const _A &__a = _A()): __buf(1, '\0', __a) {} - - StringBase(const StringBase &__s): __buf(__s.__buf) {} - StringBase(const StringBase &__s, const _A &__a): - __buf(__s.__buf, __a) {} - StringBase(StringBase &&__s): __buf(octa::move(__s.__buf)) {} - StringBase(StringBase &&__s, const _A &__a): - __buf(octa::move(__s.__buf), __a) {} - - StringBase(const StringBase &__s, size_t __pos, size_t __len = npos, - const _A &__a = _A()): - __buf(__s.__buf.each().slice(__pos, - (__len == npos) ? __s.__buf.size() : (__pos + __len)), __a) { - __terminate(); - } - - /* TODO: traits for utf-16/utf-32 string lengths, for now assume char */ - StringBase(const _T *__v, const _A &__a = _A()): - __buf(ConstRange(__v, strlen(__v) + 1), __a) {} - - template StringBase(_R __range, const _A &__a = _A()): - __buf(__range, __a) { - __terminate(); - } - - void clear() { __buf.clear(); } - - StringBase<_T> &operator=(const StringBase &__v) { - __buf.operator=(__v); - return *this; - } - StringBase<_T> &operator=(StringBase &&__v) { - __buf.operator=(octa::move(__v)); - return *this; - } - StringBase<_T> &operator=(const _T *__v) { - __buf = ConstRange(__v, strlen(__v) + 1); - return *this; - } - - void resize(size_t __n, _T __v = _T()) { - __buf.pop(); - __buf.resize(__n, __v); - __terminate(); - } - - void reserve(size_t __n) { - __buf.reserve(__n + 1); - } - - _T &operator[](size_t __i) { return __buf[__i]; } - const _T &operator[](size_t __i) const { return __buf[__i]; } - - _T &at(size_t __i) { return __buf[__i]; } - const _T &at(size_t __i) const { return __buf[__i]; } - - _T &front() { return __buf[0]; } - const _T &front() const { return __buf[0]; }; - - _T &back() { return __buf[size() - 1]; } - const _T &back() const { return __buf[size() - 1]; } - - _T *data() { return __buf.data(); } - const _T *data() const { return __buf.data(); } - - size_t size() const { - return __buf.size() - 1; - } - - size_t capacity() const { - return __buf.capacity() - 1; - } - - bool empty() const { return (size() == 0); } - - void push(_T __v) { - __buf.back() = __v; - __buf.push('\0'); - } - - StringBase<_T> &append(const StringBase &__s) { - __buf.pop(); - __buf.insert_range(__buf.size(), __s.__buf.each()); - return *this; - } - - StringBase<_T> &append(const StringBase &__s, size_t __idx, size_t __len) { - __buf.pop(); - __buf.insert_range(__buf.size(), octa::PointerRange<_T>(&__s[__idx], - (__len == npos) ? (__s.size() - __idx) : __len)); - __terminate(); - return *this; - } - - StringBase<_T> &append(const _T *__s) { - __buf.pop(); - __buf.insert_range(__buf.size(), ConstRange(__s, - strlen(__s) + 1)); - return *this; - } - - StringBase<_T> &append(size_t __n, _T __c) { - __buf.pop(); - for (size_t __i = 0; __i < __n; ++__i) __buf.push(__c); - __buf.push('\0'); - return *this; - } - - template - StringBase<_T> &append_range(_R __range) { - __buf.pop(); - __buf.insert_range(__buf.size(), __range); - __terminate(); - return *this; - } - - StringBase<_T> &operator+=(const StringBase &__s) { - return append(__s); - } - StringBase<_T> &operator+=(const _T *__s) { - return append(__s); - } - StringBase<_T> &operator+=(_T __c) { - __buf.pop(); - __buf.push(__c); - __buf.push('\0'); - return *this; - } - - Range each() { - return Range(__buf.data(), size()); - } - ConstRange each() const { - return ConstRange(__buf.data(), size()); - } - - void swap(StringBase &__v) { - __buf.swap(__v); - } - }; - - typedef StringBase String; - - template - struct __OctaIsRangeTest { - template static char __test(typename _U::Category *); - template static int __test(...); - static constexpr bool value = (sizeof(__test<_T>(0)) == sizeof(char)); - }; - - template - String concat(const _T &__v, const String &__sep, _F __func) { - String __ret; - auto __range = octa::each(__v); - if (__range.empty()) return octa::move(__ret); - for (;;) { - __ret += __func(__range.front()); - __range.pop_front(); - if (__range.empty()) break; - __ret += __sep; - } - return octa::move(__ret); + void terminate() { + if (p_buf.empty() || (p_buf.back() != '\0')) p_buf.push('\0'); } - template - String concat(const _T &__v, const String &__sep = " ") { - String __ret; - auto __range = octa::each(__v); - if (__range.empty()) return octa::move(__ret); - for (;;) { - __ret += __range.front(); - __range.pop_front(); - if (__range.empty()) break; - __ret += __sep; - } - return octa::move(__ret); +public: + typedef size_t Size; + typedef ptrdiff_t Difference; + typedef _T Value; + typedef _T &Reference; + typedef const _T &ConstReference; + typedef _T *Pointer; + typedef const _T *ConstPointer; + typedef PointerRange< _T> Range; + typedef PointerRange ConstRange; + typedef _A Allocator; + + StringBase(const _A &a = _A()): p_buf(1, '\0', a) {} + + StringBase(const StringBase &s): p_buf(s.p_buf) {} + StringBase(const StringBase &s, const _A &a): + p_buf(s.p_buf, a) {} + StringBase(StringBase &&s): p_buf(octa::move(s.p_buf)) {} + StringBase(StringBase &&s, const _A &a): + p_buf(octa::move(s.p_buf), a) {} + + StringBase(const StringBase &s, size_t pos, size_t len = npos, + const _A &a = _A()): + p_buf(s.p_buf.each().slice(pos, + (len == npos) ? s.p_buf.size() : (pos + len)), a) { + terminate(); } - template - String concat(std::initializer_list<_T> __v, const String &__sep, _F __func) { - return concat(octa::each(__v), __sep, __func); + /* TODO: traits for utf-16/utf-32 string lengths, for now assume char */ + StringBase(const _T *v, const _A &a = _A()): + p_buf(ConstRange(v, strlen(v) + 1), a) {} + + template StringBase(_R range, const _A &a = _A()): + p_buf(range, a) { + terminate(); } - template - String concat(std::initializer_list<_T> __v, const String &__sep = " ") { - return concat(octa::each(__v), __sep); + void clear() { p_buf.clear(); } + + StringBase<_T> &operator=(const StringBase &v) { + p_buf.operator=(v); + return *this; + } + StringBase<_T> &operator=(StringBase &&v) { + p_buf.operator=(octa::move(v)); + return *this; + } + StringBase<_T> &operator=(const _T *v) { + p_buf = ConstRange(v, strlen(v) + 1); + return *this; } + void resize(size_t n, _T v = _T()) { + p_buf.pop(); + p_buf.resize(n, v); + terminate(); + } + + void reserve(size_t n) { + p_buf.reserve(n + 1); + } + + _T &operator[](size_t i) { return p_buf[i]; } + const _T &operator[](size_t i) const { return p_buf[i]; } + + _T &at(size_t i) { return p_buf[i]; } + const _T &at(size_t i) const { return p_buf[i]; } + + _T &front() { return p_buf[0]; } + const _T &front() const { return p_buf[0]; }; + + _T &back() { return p_buf[size() - 1]; } + const _T &back() const { return p_buf[size() - 1]; } + + _T *data() { return p_buf.data(); } + const _T *data() const { return p_buf.data(); } + + size_t size() const { + return p_buf.size() - 1; + } + + size_t capacity() const { + return p_buf.capacity() - 1; + } + + bool empty() const { return (size() == 0); } + + void push(_T v) { + p_buf.back() = v; + p_buf.push('\0'); + } + + StringBase<_T> &append(const StringBase &s) { + p_buf.pop(); + p_buf.insert_range(p_buf.size(), s.p_buf.each()); + return *this; + } + + StringBase<_T> &append(const StringBase &s, size_t idx, size_t len) { + p_buf.pop(); + p_buf.insert_range(p_buf.size(), octa::PointerRange<_T>(&s[idx], + (len == npos) ? (s.size() - idx) : len)); + terminate(); + return *this; + } + + StringBase<_T> &append(const _T *s) { + p_buf.pop(); + p_buf.insert_range(p_buf.size(), ConstRange(s, + strlen(s) + 1)); + return *this; + } + + StringBase<_T> &append(size_t n, _T c) { + p_buf.pop(); + for (size_t i = 0; i < n; ++i) p_buf.push(c); + p_buf.push('\0'); + return *this; + } + + template + StringBase<_T> &append_range(_R range) { + p_buf.pop(); + p_buf.insert_range(p_buf.size(), range); + terminate(); + return *this; + } + + StringBase<_T> &operator+=(const StringBase &s) { + return append(s); + } + StringBase<_T> &operator+=(const _T *s) { + return append(s); + } + StringBase<_T> &operator+=(_T c) { + p_buf.pop(); + p_buf.push(c); + p_buf.push('\0'); + return *this; + } + + Range each() { + return Range(p_buf.data(), size()); + } + ConstRange each() const { + return ConstRange(p_buf.data(), size()); + } + + void swap(StringBase &v) { + p_buf.swap(v); + } +}; + +typedef StringBase String; + +template +String concat(const _T v, const String &sep, _F func) { + String ret; + auto range = octa::each(v); + if (range.empty()) return octa::move(ret); + for (;;) { + ret += func(range.front()); + range.pop_front(); + if (range.empty()) break; + ret += sep; + } + return octa::move(ret); +} + +template +String concat(const _T &v, const String &sep = " ") { + String ret; + auto range = octa::each(v); + if (range.empty()) return octa::move(ret); + for (;;) { + ret += range.front(); + range.pop_front(); + if (range.empty()) break; + ret += sep; + } + return octa::move(ret); +} + +template +String concat(std::initializer_list<_T> v, const String &sep, _F func) { + return concat(octa::each(v), sep, func); +} + +template +String concat(std::initializer_list<_T> v, const String &sep = " ") { + return concat(octa::each(v), sep); +} + +namespace detail { template - struct __OctaToStringTest { - template struct __Test {}; - template static char __test(__Test<_U, &_U::to_string> *); - template static int __test(...); - static constexpr bool value = (sizeof(__test<_T>(0)) == sizeof(char)); + struct ToStringTest { + template struct Test {}; + template static char test(Test<_U, &_U::to_string> *); + template static int test(...); + static constexpr bool value = (sizeof(test<_T>(0)) == sizeof(char)); }; +} - template struct ToString { - typedef _T Argument; - typedef String Result; +template struct ToString { + typedef _T Argument; + typedef String Result; - template - static String __octa_to_str(const _U &__v, - octa::EnableIf<__OctaToStringTest<_U>::value, bool> = true - ) { - return __v.to_string(); - } + template + static String to_str(const _U &v, + octa::EnableIf::value, bool> = true + ) { + return v.to_string(); + } - template - static String __octa_to_str(const _U &__v, - octa::EnableIf::value && - !octa::IsScalar<_U>::value, bool> = true - ) { - String __ret("{"); - __ret += concat(octa::each(__v), ", ", ToString>()); - __ret += "}"; - return octa::move(__ret); - } + template + static String to_str(const _U &v, + octa::EnableIf::value && + !octa::IsScalar<_U>::value, bool> = true + ) { + String ret("{"); + ret += concat(octa::each(v), ", ", ToString>()); + ret += "}"; + return octa::move(ret); + } - template - static String __octa_to_str(const _U &__v, - octa::EnableIf::value && - octa::IsScalar<_U>::value, bool> = true - ) { - return ToString<_U>()(__v); - } + template + static String to_str(const _U &v, + octa::EnableIf::value && + octa::IsScalar<_U>::value, bool> = true + ) { + return ToString<_U>()(v); + } - String operator()(const _T &__v) { - return octa::move(__octa_to_str - >>(__v)); - } - }; + String operator()(const _T &v) { + return octa::move(to_str + >>(v)); + } +}; +namespace detail { template - void __octa_str_printf(octa::Vector *__s, const char *__fmt, _T __v) { - char __buf[256]; - int __n = snprintf(__buf, sizeof(__buf), __fmt, __v); - __s->clear(); - __s->reserve(__n + 1); - if (__n >= (int)sizeof(__buf)) - snprintf(__s->data(), __n + 1, __fmt, __v); - else if (__n > 0) - memcpy(__s->data(), __buf, __n + 1); + void str_printf(octa::Vector *s, const char *fmt, _T v) { + char buf[256]; + int n = snprintf(buf, sizeof(buf), fmt, v); + s->clear(); + s->reserve(n + 1); + if (n >= (int)sizeof(buf)) + snprintf(s->data(), n + 1, fmt, v); + else if (n > 0) + memcpy(s->data(), buf, n + 1); else { - __n = 0; - *(__s->data()) = '\0'; + n = 0; + *(s->data()) = '\0'; } - *(((size_t *)__s) + 1) = __n + 1; - } - - template<> struct ToString { - typedef bool Argument; - typedef String Result; - String operator()(bool __b) { - return __b ? "true" : "false"; - } - }; - - template<> struct ToString { - typedef char Argument; - typedef String Result; - String operator()(char __c) { - String __ret; - __ret.push(__c); - return octa::move(__ret); - } - }; - -#define __OCTA_TOSTR_NUM(_T, __fmt) \ - template<> struct ToString<_T> { \ - typedef _T Argument; \ - typedef String Result; \ - String operator()(_T __v) { \ - String __ret; \ - __octa_str_printf((octa::Vector *)&__ret, __fmt, __v); \ - return octa::move(__ret); \ - } \ - }; - - __OCTA_TOSTR_NUM(int, "%d") - __OCTA_TOSTR_NUM(int &, "%d") - __OCTA_TOSTR_NUM(uint, "%u") - __OCTA_TOSTR_NUM(long, "%ld") - __OCTA_TOSTR_NUM(ulong, "%lu") - __OCTA_TOSTR_NUM(llong, "%lld") - __OCTA_TOSTR_NUM(ullong, "%llu") - __OCTA_TOSTR_NUM(float, "%f") - __OCTA_TOSTR_NUM(double, "%f") - __OCTA_TOSTR_NUM(ldouble, "%Lf") - -#undef __OCTA_TOSTR_NUM - - template struct ToString<_T *> { - typedef _T *Argument; - typedef String Result; - String operator()(Argument __v) { - String __ret; - __octa_str_printf((octa::Vector *)&__ret, "%p", __v); - return octa::move(__ret); - } - }; - - template<> struct ToString { - typedef const String &Argument; - typedef String Result; - String operator()(Argument __s) { - return __s; - } - }; - - template struct ToString> { - typedef const octa::Pair<_T, _U> &Argument; - typedef String Result; - String operator()(Argument __v) { - String __ret("{"); - __ret += ToString>>() - (__v.first); - __ret += ", "; - __ret += ToString>>() - (__v.second); - __ret += "}"; - return octa::move(__ret); - } - }; - - template - String to_string(const _T &__v) { - return octa::move(ToString>> - ()(__v)); - } - - template - String to_string(std::initializer_list<_T> __init) { - return octa::move(ToString>()(__init)); + *(((size_t *)s) + 1) = n + 1; } } +template<> struct ToString { + typedef bool Argument; + typedef String Result; + String operator()(bool b) { + return b ? "true" : "false"; + } +}; + +template<> struct ToString { + typedef char Argument; + typedef String Result; + String operator()(char c) { + String ret; + ret.push(c); + return octa::move(ret); + } +}; + +#define OCTA_TOSTR_NUM(_T, fmt) \ +template<> struct ToString<_T> { \ + typedef _T Argument; \ + typedef String Result; \ + String operator()(_T v) { \ + String ret; \ + octa::detail::str_printf((octa::Vector *)&ret, fmt, v); \ + return octa::move(ret); \ + } \ +}; + +OCTA_TOSTR_NUM(int, "%d") +OCTA_TOSTR_NUM(int &, "%d") +OCTA_TOSTR_NUM(uint, "%u") +OCTA_TOSTR_NUM(long, "%ld") +OCTA_TOSTR_NUM(ulong, "%lu") +OCTA_TOSTR_NUM(llong, "%lld") +OCTA_TOSTR_NUM(ullong, "%llu") +OCTA_TOSTR_NUM(float, "%f") +OCTA_TOSTR_NUM(double, "%f") +OCTA_TOSTR_NUM(ldouble, "%Lf") + +#undef OCTA_TOSTR_NUM + +template struct ToString<_T *> { + typedef _T *Argument; + typedef String Result; + String operator()(Argument v) { + String ret; + octa::detail::str_printf((octa::Vector *)&ret, "%p", v); + return octa::move(ret); + } +}; + +template<> struct ToString { + typedef const String &Argument; + typedef String Result; + String operator()(Argument s) { + return s; + } +}; + +template struct ToString> { + typedef const octa::Pair<_T, _U> &Argument; + typedef String Result; + String operator()(Argument v) { + String ret("{"); + ret += ToString>>() + (v.first); + ret += ", "; + ret += ToString>>() + (v.second); + ret += "}"; + return octa::move(ret); + } +}; + +template +String to_string(const _T &v) { + return octa::move(ToString>> + ()(v)); +} + +template +String to_string(std::initializer_list<_T> init) { + return octa::move(ToString>()(init)); +} + +} /* namespace octa */ + #endif \ No newline at end of file