diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2014-02-08 15:09:25 -0800 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2014-02-08 16:18:22 -0800 |
commit | 730e5dde39333cb2f63c72a7d7152bee5c4dbb05 (patch) | |
tree | 510ef3e0ad46ecf1f2bee1fa42f26e6377b51686 /src/strings | |
parent | 7a15a3efe85837d52d950cc9f895eadcc9eb6be1 (diff) | |
download | tmwa-730e5dde39333cb2f63c72a7d7152bee5c4dbb05.tar.gz tmwa-730e5dde39333cb2f63c72a7d7152bee5c4dbb05.tar.bz2 tmwa-730e5dde39333cb2f63c72a7d7152bee5c4dbb05.tar.xz tmwa-730e5dde39333cb2f63c72a7d7152bee5c4dbb05.zip |
Implement AString
Diffstat (limited to 'src/strings')
26 files changed, 740 insertions, 181 deletions
diff --git a/src/strings/all.hpp b/src/strings/all.hpp index 7fd543f..46d5366 100644 --- a/src/strings/all.hpp +++ b/src/strings/all.hpp @@ -21,7 +21,8 @@ # include "base.hpp" # include "mstring.hpp" -# include "fstring.hpp" +# include "rstring.hpp" +# include "astring.hpp" # include "tstring.hpp" # include "sstring.hpp" # include "zstring.hpp" diff --git a/src/strings/astring.cpp b/src/strings/astring.cpp new file mode 100644 index 0000000..f7cfa2e --- /dev/null +++ b/src/strings/astring.cpp @@ -0,0 +1,229 @@ +#include "astring.hpp" +// strings/astring.cpp - Functions for astring.hpp +// +// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "mstring.hpp" +#include "tstring.hpp" +#include "sstring.hpp" +#include "zstring.hpp" +#include "xstring.hpp" +#include "vstring.hpp" + +namespace strings +{ + static_assert(sizeof(AString) == 256, "AString"); + + static + void acpy(char (&dst)[255], const char (&src)[255]) + { + std::copy(src + 0, src + 255, dst); + } + + // TODO dedup all this code once I drop gcc 4.6 support + AString::AString() + : data{}, special() + { + new(r_ptr()) RString(); + special = 255; + } + + AString::AString(const AString& a) + : data(), special(a.special) + { + acpy(data, a.data); + if (special == 255) + new(r_ptr()) RString(*a.r_ptr()); + } + AString::AString(AString&& a) + : data(), special(a.special) + { + acpy(data, a.data); + if (special == 255) + new(r_ptr()) RString(std::move(*a.r_ptr())); + } + AString& AString::operator = (const AString& a) + { + if (this == &a) + return *this; + if (special == 255) + r_ptr()->~RString(); + acpy(data, a.data); + special = a.special; + if (special == 255) + new(r_ptr()) RString(*a.r_ptr()); + return *this; + } + AString& AString::operator = (AString&& a) + { + std::swap(data, a.data); + std::swap(special, a.special); + return *this; + } + AString::AString(RString r) + : data{}, special() + { + new(r_ptr()) RString(std::move(r)); + special = 255; + } + AString::~AString() + { + if (special == 255) + r_ptr()->~RString(); + } + + AString::AString(const MString& s) + : data{}, special() + { + if (s.size() > 255 || s.size() == 0) + { + new(r_ptr()) RString(s); + special = 255; + } + else + { + *std::copy(s.begin(), s.end(), data) = '\0'; + special = 255 - s.size(); + } + } + + AString::AString(XPair p) + : data{}, special() + { + new(r_ptr()) RString(); + special = 255; + *this = XString(p); + } + + AString::AString(const TString& t) + : data{}, special() + { + new(r_ptr()) RString(); + special = 255; + *this = XString(t); + } + AString::AString(const SString& s) + : data{}, special() + { + new(r_ptr()) RString(); + special = 255; + *this = XString(s); + } + AString::AString(ZString z) + : data{}, special() + { + new(r_ptr()) RString(); + special = 255; + *this = XString(z); + } + AString::AString(XString x) + : data{}, special() + { + if (const RString *r = x.base()) + { + if (&*r->begin() == &*x.begin() && &*r->end() == &*x.end()) + { + new(r_ptr()) RString(*r); + special = 255; + return; + } + } + if (x.size() > 255 || x.size() == 0) + { + new(r_ptr()) RString(x); + special = 255; + } + else + { + *std::copy(x.begin(), x.end(), data) = '\0'; + special = 255 - x.size(); + } + } + + AString::iterator AString::begin() const + { + if (special == 255) + return &*r_ptr()->begin(); + else + return data + 0; + } + AString::iterator AString::end() const + { + if (special == 255) + return &*r_ptr()->end(); + else + return data + (255 - special); + } + const RString *AString::base() const + { + if (special == 255) + return r_ptr(); + else + return nullptr; + } + const char *AString::c_str() const + { + return &*begin(); + } + + const char *decay_for_printf(const AString& as) + { + return as.c_str(); + } + + int do_vprint(AString& out, const char *fmt, va_list ap) + { + // TODO try with a fixed-size buffer first, then write + // directory into the allocated output? + int len; + { + va_list ap2; + va_copy(ap2, ap); + len = vsnprintf(nullptr, 0, fmt, ap2); + va_end(ap2); + } + char buffer[len + 1]; + vsnprintf(buffer, len + 1, fmt, ap); + + out = AString(buffer, buffer + len); + return len; + } + + AStringConverter::AStringConverter(AString& s) + : out(s), mid(nullptr) + {} + + AStringConverter::~AStringConverter() + { + if (mid) + { + out = ZString(really_construct_from_a_pointer, mid, nullptr); + free(mid); + } + } + + char **AStringConverter::operator &() + { + return ∣ + } + + AStringConverter convert_for_scanf(AString& s) + { + return AStringConverter(s); + } +} // namespace strings diff --git a/src/strings/astring.hpp b/src/strings/astring.hpp new file mode 100644 index 0000000..e682ef0 --- /dev/null +++ b/src/strings/astring.hpp @@ -0,0 +1,98 @@ +#ifndef TMWA_STRINGS_ASTRING_HPP +#define TMWA_STRINGS_ASTRING_HPP +// strings/astring.hpp - An owned, reference-counted immutable string. +// +// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +# include <cstdarg> +# include <cstring> + +# include "base.hpp" +# include "rstring.hpp" + +namespace strings +{ + /// An owning string that has reached its final contents. + /// The storage is NUL-terminated + class AString : public _crtp_string<AString, AString, ZPair> + { + RString *align[0]; + char data[255]; + unsigned char special; + RString *r_ptr() { return reinterpret_cast<RString *>(data); } + const RString *r_ptr() const { return reinterpret_cast<const RString *>(data); } + public: + AString(); + AString(const AString&); + AString(AString&&); + AString& operator = (const AString&); + AString& operator = (AString&&); + AString(RString); + ~AString(); + + explicit AString(const MString& s); + + template<size_t n> + AString(char (&s)[n]) = delete; + + template<size_t n> + AString(const char (&s)[n]); + + template<class It> + AString(It b, It e); + + AString(XPair p); + //AString(const AString&) + AString(const TString&); + AString(const SString&); + AString(ZString); + AString(XString); + template<uint8_t n> + AString(const VString<n>& v); + + iterator begin() const; + iterator end() const; + const RString *base() const; + const char *c_str() const; + }; + + // cxxstdio helpers + // I think the conversion will happen automatically. TODO test this. + // Nope, it doesn't, since there's a template + // Actually, it might now. + const char *decay_for_printf(const AString& fs); + + __attribute__((format(printf, 2, 0))) + int do_vprint(AString& out, const char *fmt, va_list ap); + + class AStringConverter + { + AString& out; + char *mid; + public: + AStringConverter(AString& s); + ~AStringConverter(); + char **operator &(); + }; + + AStringConverter convert_for_scanf(AString& s); +} // namespace strings + +# include "astring.tcc" + +#endif // TMWA_STRINGS_ASTRING_HPP diff --git a/src/strings/astring.py b/src/strings/astring.py new file mode 100644 index 0000000..ec1dafe --- /dev/null +++ b/src/strings/astring.py @@ -0,0 +1,24 @@ +class AString(object): + ''' print an AString + ''' + __slots__ = ('_value') + name = 'strings::AString' + enabled = True + + def __init__(self, value): + self._value = value + + def to_string(self): + return None + + def children(self): + b = self._value['data'] + s = self._value['special'] + if s == 255: + b = b.cast(gdb.lookup_type('strings::RString').pointer()) + yield 'allocated', b.dereference() + else: + b = b.cast(b.type.target().pointer()) + n = 255 + d = n - s + yield 'contained', b.lazy_string(length=d) diff --git a/src/strings/astring.tcc b/src/strings/astring.tcc new file mode 100644 index 0000000..ed07bd9 --- /dev/null +++ b/src/strings/astring.tcc @@ -0,0 +1,76 @@ +// strings/astring.tcc - Inline functions for astring.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include "mstring.hpp" + +namespace strings +{ + template<size_t n> + AString::AString(const char (&s)[n]) + : data{}, special() + { + XPair x = s; + if (x.size() > 255 || x.size() == 0) + { + new(r_ptr()) RString(x); + special = 255; + } + else + { + *std::copy(x.begin(), x.end(), data) = '\0'; + special = 255 - x.size(); + } + } + + template<class It> + AString::AString(It b, It e) + : data{}, special() + { + if (!std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) + { + // can't use std::distance + MString m; + for (; b != e; ++b) + m += *b; + *this = AString(m); // will recurse + return; + } + auto d = std::distance(b, e); + if (d > 255 || d == 0) + { + new(r_ptr()) RString(b, e); + special = 255; + } + else + { + *std::copy(b, e, data) = '\0'; + special = 255 - d; + } + } + + template<uint8_t n> + AString::AString(const VString<n>& v) + : data{}, special() + { + *std::copy(v.begin(), v.end(), data) = '\0'; + special = 255 - v.size(); + if (!v) + new(r_ptr()) RString(); + } +} // namespace strings diff --git a/src/strings/base.hpp b/src/strings/base.hpp index 7461872..c081f70 100644 --- a/src/strings/base.hpp +++ b/src/strings/base.hpp @@ -88,7 +88,7 @@ namespace strings const T& _ref() const; iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; public: size_t size() const; reverse_iterator rbegin() const; diff --git a/src/strings/base.tcc b/src/strings/base.tcc index 491b4ca..a5a57d0 100644 --- a/src/strings/base.tcc +++ b/src/strings/base.tcc @@ -104,7 +104,7 @@ namespace strings return _ref().end(); } template<class T, class O, class P> - const FString *_crtp_string<T, O, P>::base() const + const RString *_crtp_string<T, O, P>::base() const { return _ref().base(); } diff --git a/src/strings/base_test.cpp b/src/strings/base_test.cpp index cb41fa9..3f9900e 100644 --- a/src/strings/base_test.cpp +++ b/src/strings/base_test.cpp @@ -4,7 +4,7 @@ #include "vstring.hpp" #include "xstring.hpp" -#include "fstring.hpp" +#include "rstring.hpp" using namespace strings; @@ -18,7 +18,7 @@ static_assert(!string_comparison_allowed<_test, VString<1>>::value, "tv"); static_assert(!string_comparison_allowed<_test, _test2>::value, "t2"); static_assert(string_comparison_allowed<VString<1>, XString>::value, "vx"); static_assert(string_comparison_allowed<XString, XString>::value, "xx"); -static_assert(string_comparison_allowed<XString, FString>::value, "xf"); +static_assert(string_comparison_allowed<XString, RString>::value, "xf"); TEST(strings, contains) { diff --git a/src/strings/fwd.hpp b/src/strings/fwd.hpp index a865fc4..f2b4037 100644 --- a/src/strings/fwd.hpp +++ b/src/strings/fwd.hpp @@ -28,7 +28,8 @@ namespace strings { // owning class MString; - class FString; + class RString; + class AString; class TString; // C legacy version of SString class SString; // is this one really worth it? @@ -46,7 +47,8 @@ namespace strings } // namespace strings using strings::MString; -using strings::FString; +using strings::RString; +using strings::AString; using strings::TString; using strings::SString; diff --git a/src/strings/fstring.cpp b/src/strings/rstring.cpp index 97ef4b0..eb9d88a 100644 --- a/src/strings/fstring.cpp +++ b/src/strings/rstring.cpp @@ -1,5 +1,5 @@ -#include "fstring.hpp" -// strings/fstring.cpp - Functions for fstring.hpp +#include "rstring.hpp" +// strings/rstring.cpp - Functions for rstring.hpp // // Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> // @@ -27,26 +27,28 @@ namespace strings { - uint8_t FString::empty_string_rep[sizeof(Rep) + 1]; + static_assert(sizeof(RString) == sizeof(const char *), "RString"); - FString::FString() + uint8_t RString::empty_string_rep[sizeof(Rep) + 1]; + + RString::RString() : owned(reinterpret_cast<Rep *>(&empty_string_rep)) { owned->count++; } - FString::FString(const FString& r) + RString::RString(const RString& r) : owned(r.owned) { owned->count++; } - FString::FString(FString&& r) + RString::RString(RString&& r) : owned(reinterpret_cast<Rep *>(&empty_string_rep)) { std::swap(owned, r.owned); r.owned->count++; } - FString& FString::operator = (const FString& r) + RString& RString::operator = (const RString& r) { // order important for self-assign r.owned->count++; @@ -57,49 +59,61 @@ namespace strings owned = r.owned; return *this; } - FString& FString::operator = (FString&& r) + RString& RString::operator = (RString&& r) { std::swap(owned, r.owned); return *this; } - FString::~FString() + RString::RString(AString a) + : owned(nullptr) + { + if (RString *r = const_cast<RString *>(a.base())) + { + *this = std::move(*r); + } + else + { + *this = XPair(a); + } + } + RString::~RString() { if (owned && !owned->count--) ::operator delete(owned); owned = nullptr; } - FString::FString(const MString& s) + RString::RString(const MString& s) : owned(nullptr) { _assign(s.begin(), s.end()); } - FString::FString(XPair p) + RString::RString(XPair p) : owned(nullptr) { _assign(p.begin(), p.end()); } - FString::FString(const TString& t) + RString::RString(const TString& t) : owned(nullptr) { *this = XString(t); } - FString::FString(const SString& s) + RString::RString(const SString& s) : owned(nullptr) { *this = XString(s); } - FString::FString(ZString z) + RString::RString(ZString z) : owned(nullptr) { *this = XString(z); } - FString::FString(XString x) + RString::RString(XString x) : owned(nullptr) { - const FString *f = x.base(); + const RString *f = x.base(); const char *xb = &*x.begin(); const char *xe = &*x.end(); const char *fb = f ? &*f->begin() : nullptr; @@ -110,29 +124,29 @@ namespace strings _assign(x.begin(), x.end()); } - FString::iterator FString::begin() const + RString::iterator RString::begin() const { return owned->body; } - FString::iterator FString::end() const + RString::iterator RString::end() const { return owned->body + owned->size; } - const FString *FString::base() const + const RString *RString::base() const { return this; } - const char *FString::c_str() const + const char *RString::c_str() const { return &*begin(); } - const char *decay_for_printf(const FString& fs) + const char *decay_for_printf(const RString& fs) { return fs.c_str(); } - int do_vprint(FString& out, const char *fmt, va_list ap) + int do_vprint(RString& out, const char *fmt, va_list ap) { int len; { @@ -144,30 +158,7 @@ namespace strings char buffer[len + 1]; vsnprintf(buffer, len + 1, fmt, ap); - out = FString(buffer, buffer + len); + out = RString(buffer, buffer + len); return len; } - - StringConverter::StringConverter(FString& s) - : out(s), mid(nullptr) - {} - - StringConverter::~StringConverter() - { - if (mid) - { - out = ZString(really_construct_from_a_pointer, mid, nullptr); - free(mid); - } - } - - char **StringConverter::operator &() - { - return ∣ - } - - StringConverter convert_for_scanf(FString& s) - { - return StringConverter(s); - } } // namespace strings diff --git a/src/strings/fstring.hpp b/src/strings/rstring.hpp index 48da326..b79c7f6 100644 --- a/src/strings/fstring.hpp +++ b/src/strings/rstring.hpp @@ -1,6 +1,6 @@ -#ifndef TMWA_STRINGS_FSTRING_HPP -#define TMWA_STRINGS_FSTRING_HPP -// strings/fstring.hpp - An owned, reference-counted immutable string. +#ifndef TMWA_STRINGS_RSTRING_HPP +#define TMWA_STRINGS_RSTRING_HPP +// strings/rstring.hpp - An owned, reference-counted immutable string. // // Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com> // @@ -28,7 +28,7 @@ namespace strings { /// An owning string that has reached its final contents. /// The storage is NUL-terminated - class FString : public _crtp_string<FString, FString, ZPair> + class RString : public _crtp_string<RString, RString, ZPair> { struct Rep { @@ -44,36 +44,37 @@ namespace strings template<class It> void _assign(It b, It e); public: - FString(); - FString(const FString&); - FString(FString&&); - FString& operator = (const FString&); - FString& operator = (FString&&); - ~FString(); + RString(); + RString(const RString&); + RString(RString&&); + RString& operator = (const RString&); + RString& operator = (RString&&); + RString(AString); + ~RString(); - explicit FString(const MString& s); + explicit RString(const MString& s); template<size_t n> - FString(char (&s)[n]) = delete; + RString(char (&s)[n]) = delete; template<size_t n> - FString(const char (&s)[n]); + RString(const char (&s)[n]); template<class It> - FString(It b, It e); - - FString(XPair p); - //FString(const FString&) - FString(const TString&); - FString(const SString&); - FString(ZString); - FString(XString); + RString(It b, It e); + + RString(XPair p); + //RString(const RString&) + RString(const TString&); + RString(const SString&); + RString(ZString); + RString(XString); template<uint8_t n> - FString(const VString<n>& v); + RString(const VString<n>& v); iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; const char *c_str() const; }; @@ -81,24 +82,12 @@ namespace strings // I think the conversion will happen automatically. TODO test this. // Nope, it doesn't, since there's a template // Actually, it might now. - const char *decay_for_printf(const FString& fs); + const char *decay_for_printf(const RString& fs); __attribute__((format(printf, 2, 0))) - int do_vprint(FString& out, const char *fmt, va_list ap); - - class StringConverter - { - FString& out; - char *mid; - public: - StringConverter(FString& s); - ~StringConverter(); - char **operator &(); - }; - - StringConverter convert_for_scanf(FString& s); + int do_vprint(RString& out, const char *fmt, va_list ap); } // namespace strings -# include "fstring.tcc" +# include "rstring.tcc" -#endif // TMWA_STRINGS_FSTRING_HPP +#endif // TMWA_STRINGS_RSTRING_HPP diff --git a/src/strings/fstring.py b/src/strings/rstring.py index 5418300..f0618d6 100644 --- a/src/strings/fstring.py +++ b/src/strings/rstring.py @@ -1,8 +1,8 @@ -class FString(object): - ''' print a FString +class RString(object): + ''' print a RString ''' __slots__ = ('_value') - name = 'strings::FString' + name = 'strings::RString' enabled = True def __init__(self, value): diff --git a/src/strings/fstring.tcc b/src/strings/rstring.tcc index 8072fb0..8b4c0c0 100644 --- a/src/strings/fstring.tcc +++ b/src/strings/rstring.tcc @@ -1,4 +1,4 @@ -// strings/fstring.tcc - Inline functions for fstring.hpp +// strings/rstring.tcc - Inline functions for rstring.hpp // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> // @@ -22,12 +22,12 @@ namespace strings { template<class It> - void FString::_assign(It b, It e) + void RString::_assign(It b, It e) { owned = nullptr; if (b == e) { - *this = FString(); + *this = RString(); return; } if (!std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) @@ -36,7 +36,7 @@ namespace strings MString m; for (; b != e; ++b) m += *b; - *this = FString(m); // will recurse + *this = RString(m); // will recurse return; } size_t diff = std::distance(b, e); @@ -48,19 +48,19 @@ namespace strings } template<size_t n> - FString::FString(const char (&s)[n]) + RString::RString(const char (&s)[n]) { _assign(s, s + strlen(s)); } template<class It> - FString::FString(It b, It e) + RString::RString(It b, It e) { _assign(b, e); } template<uint8_t n> - FString::FString(const VString<n>& v) + RString::RString(const VString<n>& v) { _assign(v.begin(), v.end()); } diff --git a/src/strings/sstring.cpp b/src/strings/sstring.cpp index 99f91ed..fee98f9 100644 --- a/src/strings/sstring.cpp +++ b/src/strings/sstring.cpp @@ -27,8 +27,11 @@ namespace strings SString::SString() : _s(), _b(), _e() {} - SString::SString(FString f) - : _s(std::move(f)), _b(), _e(_s.size()) + SString::SString(RString r) + : _s(std::move(r)), _b(), _e(_s.size()) + {} + SString::SString(AString a) + : _s(std::move(a)), _b(), _e(_s.size()) {} SString::SString(TString t) : _s(t._s), _b(0), _e(_s.size()) @@ -39,19 +42,39 @@ namespace strings } SString::SString(const XString& x) { - const FString *f = x.base(); + const RString *r = x.base(); const char *xb = &*x.begin(); const char *xe = &*x.end(); - const char *fb = f ? &*f->begin() : nullptr; - //const char *fe = f ? &*f->end() : nullptr; - if (f) - *this = SString(*f, xb - fb, xe - fb); + const char *rb = r ? &*r->begin() : nullptr; + //const char *re = r ? &*r->end() : nullptr; + if (r) + *this = SString(*r, xb - rb, xe - rb); else - *this = FString(x); + *this = RString(x); } - SString::SString(FString f, size_t b, size_t e) - : _s(std::move(f)), _b(b), _e(e) + SString::SString(RString r, size_t b, size_t e) + : _s(std::move(r)), _b(b), _e(e) + {} + static + RString get_owned_slice(AString a, size_t *b, size_t *e) + { + if (a.base()) + { + // it's futile + return std::move(a); + } + // have to allocate anyway, so cut first + size_t ob = *b; + size_t oe = *e; + *e -= *b; + *b = 0; + return a.xpslice(ob, oe); + } + SString::SString(AString a, size_t b, size_t e) + : _s(get_owned_slice(std::move(a), &b, &e)) + , _b(b) + , _e(e) {} SString::SString(XPair p) : _s(p), _b(0), _e(p.size()) @@ -65,7 +88,7 @@ namespace strings { return &_s.begin()[_e]; } - const FString *SString::base() const + const RString *SString::base() const { return &_s; } diff --git a/src/strings/sstring.hpp b/src/strings/sstring.hpp index 12fb96d..1836d69 100644 --- a/src/strings/sstring.hpp +++ b/src/strings/sstring.hpp @@ -1,6 +1,6 @@ #ifndef TMWA_STRINGS_SSTRING_HPP #define TMWA_STRINGS_SSTRING_HPP -// strings/sstring.hpp - A full slice of an FString. +// strings/sstring.hpp - A full slice of an RString. // // Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> // @@ -20,19 +20,20 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. # include "base.hpp" -# include "fstring.hpp" +# include "rstring.hpp" namespace strings { - /// An owning string that represents a arbitrary slice of an FString. + /// An owning string that represents a arbitrary slice of an RString. /// Not guaranteed to be NUL-terminated. class SString : public _crtp_string<SString, SString, XPair> { - FString _s; + RString _s; size_t _b, _e; public: SString(); - SString(FString f); + SString(RString f); + SString(AString f); SString(TString t); //SString(const SString&); SString(const ZString&); @@ -45,12 +46,13 @@ namespace strings SString(const char (&s)[n]); //template<class It> //SString(It b, It e) : _s(b, e), _b(0), _e(_s.size()) {} - SString(FString f, size_t b, size_t e); + SString(RString f, size_t b, size_t e); + SString(AString f, size_t b, size_t e); SString(XPair p); iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; }; } // namespace strings diff --git a/src/strings/strings2_test.cpp b/src/strings/strings2_test.cpp index 3f8662a..24bfc0c 100644 --- a/src/strings/strings2_test.cpp +++ b/src/strings/strings2_test.cpp @@ -6,7 +6,7 @@ TEST(StringTests, traits2) { ZString print_non = "\t\e"; ZString print_mix = "n\t"; - FString print_all = "n "; + RString print_all = "n "; EXPECT_FALSE(print_non.has_print()); EXPECT_TRUE(print_mix.has_print()); EXPECT_TRUE(print_all.has_print()); @@ -20,7 +20,7 @@ TEST(StringTests, traits2) ZString graph_non = " \e"; ZString graph_mix = "n "; - FString graph_all = "n."; + RString graph_all = "n."; EXPECT_FALSE(graph_non.has_graph()); EXPECT_TRUE(graph_mix.has_graph()); EXPECT_TRUE(graph_all.has_graph()); @@ -30,7 +30,7 @@ TEST(StringTests, traits2) ZString lower_non = "0A"; ZString lower_mix = "Oa"; - FString lower_all = "oa"; + RString lower_all = "oa"; EXPECT_FALSE(lower_non.has_lower()); EXPECT_TRUE(lower_mix.has_lower()); EXPECT_TRUE(lower_all.has_lower()); @@ -44,7 +44,7 @@ TEST(StringTests, traits2) ZString upper_non = "0a"; ZString upper_mix = "oA"; - FString upper_all = "OA"; + RString upper_all = "OA"; EXPECT_FALSE(upper_non.has_upper()); EXPECT_TRUE(upper_mix.has_upper()); EXPECT_TRUE(upper_all.has_upper()); @@ -58,7 +58,7 @@ TEST(StringTests, traits2) ZString alpha_non = " 0"; ZString alpha_mix = "n "; - FString alpha_all = "nA"; + RString alpha_all = "nA"; EXPECT_FALSE(alpha_non.has_alpha()); EXPECT_TRUE(alpha_mix.has_alpha()); EXPECT_TRUE(alpha_all.has_alpha()); @@ -68,7 +68,7 @@ TEST(StringTests, traits2) ZString digit2_non = "a9"; ZString digit2_mix = "20"; - FString digit2_all = "01"; + RString digit2_all = "01"; EXPECT_FALSE(digit2_non.has_digit2()); EXPECT_TRUE(digit2_mix.has_digit2()); EXPECT_TRUE(digit2_all.has_digit2()); @@ -78,7 +78,7 @@ TEST(StringTests, traits2) ZString digit8_non = "a9"; ZString digit8_mix = "80"; - FString digit8_all = "37"; + RString digit8_all = "37"; EXPECT_FALSE(digit8_non.has_digit8()); EXPECT_TRUE(digit8_mix.has_digit8()); EXPECT_TRUE(digit8_all.has_digit8()); @@ -88,7 +88,7 @@ TEST(StringTests, traits2) ZString digit10_non = "az"; ZString digit10_mix = "a9"; - FString digit10_all = "42"; + RString digit10_all = "42"; EXPECT_FALSE(digit10_non.has_digit10()); EXPECT_TRUE(digit10_mix.has_digit10()); EXPECT_TRUE(digit10_all.has_digit10()); @@ -98,7 +98,7 @@ TEST(StringTests, traits2) ZString digit16_non = "gz"; ZString digit16_mix = "ao"; - FString digit16_all = "be"; + RString digit16_all = "be"; EXPECT_FALSE(digit16_non.has_digit16()); EXPECT_TRUE(digit16_mix.has_digit16()); EXPECT_TRUE(digit16_all.has_digit16()); @@ -108,7 +108,7 @@ TEST(StringTests, traits2) ZString alnum_non = " ."; ZString alnum_mix = "n "; - FString alnum_all = "n0"; + RString alnum_all = "n0"; EXPECT_FALSE(alnum_non.has_alnum()); EXPECT_TRUE(alnum_mix.has_alnum()); EXPECT_TRUE(alnum_all.has_alnum()); @@ -116,3 +116,89 @@ TEST(StringTests, traits2) EXPECT_FALSE(alnum_mix.is_alnum()); EXPECT_TRUE(alnum_all.is_alnum()); } + +TEST(StringTests, rempty) +{ + const char empty_text[] = ""; + RString r = empty_text; + EXPECT_EQ(r.size(), 0); + AString a = empty_text; + EXPECT_EQ(r, a); + AString r2 = r, r3; + RString a2 = a, a3; + XString r1 = r2; + XString a1 = a2; + r3 = r1; + a3 = a1; + EXPECT_EQ(r, r1); + EXPECT_EQ(a, a1); + EXPECT_EQ(r, r2); + EXPECT_EQ(a, a2); + EXPECT_EQ(r, r3); + EXPECT_EQ(a, a3); + EXPECT_EQ(&*r.begin(), &*r1.begin()); + EXPECT_EQ(&*a.begin(), &*a1.begin()); + EXPECT_EQ(&*r.begin(), &*r2.begin()); + EXPECT_EQ(&*a.begin(), &*a2.begin()); + EXPECT_EQ(&*r.begin(), &*r3.begin()); + EXPECT_EQ(&*a.begin(), &*a3.begin()); +} +TEST(StringTests, rshort) +{ + const char short_text[] = "0123456789"; + RString r = short_text; + EXPECT_EQ(r.size(), 10); + AString a = short_text; + EXPECT_EQ(r, a); + AString r2 = r, r3; + RString a2 = a, a3; + XString r1 = r2; + XString a1 = a2; + r3 = r1; + a3 = a1; + EXPECT_EQ(r, r1); + EXPECT_EQ(a, a1); + EXPECT_EQ(r, r2); + EXPECT_EQ(a, a2); + EXPECT_EQ(r, r3); + EXPECT_EQ(a, a3); + EXPECT_EQ(&*r.begin(), &*r1.begin()); + EXPECT_NE(&*a.begin(), &*a1.begin()); + EXPECT_EQ(&*r.begin(), &*r2.begin()); + EXPECT_NE(&*a.begin(), &*a2.begin()); + EXPECT_EQ(&*r.begin(), &*r3.begin()); + EXPECT_NE(&*a.begin(), &*a3.begin()); +} + +TEST(StringTests, rlong) +{ + const char long_text[] = + "01234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345 100" + "01234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345 200" + "01234567890123456789012345678901234567890123456789" + "0123456789012345678901234567890123456789012345 300"; + RString r = long_text; + EXPECT_EQ(r.size(), 300); + AString a = long_text; + EXPECT_EQ(r, a); + AString r2 = r, r3; + RString a2 = a, a3; + XString r1 = r2; + XString a1 = a2; + r3 = r1; + a3 = a1; + EXPECT_EQ(r, r1); + EXPECT_EQ(a, a1); + EXPECT_EQ(r, r2); + EXPECT_EQ(a, a2); + EXPECT_EQ(r, r3); + EXPECT_EQ(a, a3); + EXPECT_EQ(&*r.begin(), &*r1.begin()); + EXPECT_EQ(&*a.begin(), &*a1.begin()); + EXPECT_EQ(&*r.begin(), &*r2.begin()); + EXPECT_EQ(&*a.begin(), &*a2.begin()); + EXPECT_EQ(&*r.begin(), &*r3.begin()); + EXPECT_EQ(&*a.begin(), &*a3.begin()); +} diff --git a/src/strings/strings_test.cpp b/src/strings/strings_test.cpp index 82d39d8..55a2ffa 100644 --- a/src/strings/strings_test.cpp +++ b/src/strings/strings_test.cpp @@ -21,7 +21,7 @@ TYPED_TEST_P(StringTest, basic) EXPECT_EQ(0, hi0.size()); __attribute__((unused)) - const FString *base = hi.base(); + const RString *base = hi.base(); } TYPED_TEST_P(StringTest, order) @@ -168,7 +168,8 @@ TYPED_TEST_P(StringTest, convert) constexpr bool is_zstring = std::is_same<TypeParam, ZString>::value; typedef typename std::conditional<is_zstring, TString, SString>::type Sstring; typedef typename std::conditional<is_zstring, ZString, XString>::type Xstring; - FString f = "f"; + RString r = "r"; + AString a = "a"; TString t = "t"; Sstring s = "s"; ZString z = "z"; @@ -177,7 +178,8 @@ TYPED_TEST_P(StringTest, convert) const char l[] = "l"; VString<5> hi = "hello"; - TypeParam f2 = f; + TypeParam r2 = r; + TypeParam a2 = a; TypeParam t2 = t; TypeParam s2 = s; TypeParam z2 = z; @@ -186,7 +188,8 @@ TYPED_TEST_P(StringTest, convert) TypeParam l2 = l; TypeParam hi2 = hi; - EXPECT_EQ(f, f2); + EXPECT_EQ(r, r2); + EXPECT_EQ(a, a2); EXPECT_EQ(t, t2); EXPECT_EQ(s, s2); EXPECT_EQ(z, z2); @@ -195,8 +198,9 @@ TYPED_TEST_P(StringTest, convert) EXPECT_EQ(l, l2); EXPECT_EQ(hi, hi2); - TypeParam f3, t3, s3, z3, x3, v3, l3, hi3; - f3 = f; + TypeParam r3, a3, t3, s3, z3, x3, v3, l3, hi3; + r3 = r; + a3 = a; t3 = t; s3 = s; z3 = z; @@ -205,7 +209,8 @@ TYPED_TEST_P(StringTest, convert) l3 = l; hi3 = hi; - EXPECT_EQ(f, f3); + EXPECT_EQ(r, r3); + EXPECT_EQ(a, a3); EXPECT_EQ(t, t3); EXPECT_EQ(s, s3); EXPECT_EQ(z, z3); @@ -214,7 +219,8 @@ TYPED_TEST_P(StringTest, convert) EXPECT_EQ(l, l3); EXPECT_EQ(hi, hi3); - TypeParam f4(f); + TypeParam r4(r); + TypeParam a4(a); TypeParam t4(t); TypeParam s4(s); TypeParam z4(z); @@ -223,7 +229,8 @@ TYPED_TEST_P(StringTest, convert) TypeParam l4(l); TypeParam hi4(hi); - EXPECT_EQ(f, f4); + EXPECT_EQ(r, r4); + EXPECT_EQ(a, a4); EXPECT_EQ(t, t4); EXPECT_EQ(s, s4); EXPECT_EQ(z, z4); @@ -237,7 +244,7 @@ REGISTER_TYPED_TEST_CASE_P(StringTest, basic, order, iterators, xslice, convert); typedef ::testing::Types< - FString, TString, SString, ZString, XString, VString<255> + RString, AString, TString, SString, ZString, XString, VString<255> > MostStringTypes; INSTANTIATE_TYPED_TEST_CASE_P(StringStuff, StringTest, MostStringTypes); @@ -274,6 +281,6 @@ REGISTER_TYPED_TEST_CASE_P(NulStringTest, basic); typedef ::testing::Types< - FString, TString, ZString, VString<255> + RString, AString, TString, ZString, VString<255> > NulStringTypes; INSTANTIATE_TYPED_TEST_CASE_P(NulStringStuff, NulStringTest, NulStringTypes); diff --git a/src/strings/tstring.cpp b/src/strings/tstring.cpp index 2d13888..8be7112 100644 --- a/src/strings/tstring.cpp +++ b/src/strings/tstring.cpp @@ -27,9 +27,24 @@ namespace strings TString::TString() : _s(), _o() {} - TString::TString(FString b, size_t i) + TString::TString(RString b, size_t i) : _s(std::move(b)), _o(i) {} + static + RString get_owned_tlice(AString a, size_t *i) + { + if (a.base()) + { + return std::move(a); + } + size_t oi = *i; + *i = 0; + return a.xslice_t(oi); + } + TString::TString(AString b, size_t i) + : _s(get_owned_tlice(std::move(b), &i)) + , _o(i) + {} TString::TString(const SString& s) { *this = XString(s); @@ -40,15 +55,15 @@ namespace strings } TString::TString(const XString& x) { - const FString *f = x.base(); + const RString *r = x.base(); const char *xb = &*x.begin(); const char *xe = &*x.end(); - const char *fb = f ? &*f->begin() : nullptr; - const char *fe = f ? &*f->end() : nullptr; - if (f && xe == fe) - *this = TString(*f, xb - fb); + const char *rb = r ? &*r->begin() : nullptr; + const char *re = r ? &*r->end() : nullptr; + if (r && xe == re) + *this = TString(*r, xb - rb); else - *this = FString(x); + *this = RString(x); } TString::TString(XPair p) @@ -63,7 +78,7 @@ namespace strings { return &*_s.end(); } - const FString *TString::base() const + const RString *TString::base() const { return &_s; } diff --git a/src/strings/tstring.hpp b/src/strings/tstring.hpp index 49ec4ab..700ec3d 100644 --- a/src/strings/tstring.hpp +++ b/src/strings/tstring.hpp @@ -20,20 +20,21 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. # include "base.hpp" -# include "fstring.hpp" +# include "rstring.hpp" namespace strings { - /// An owning string that represents a tail slice of an FString. + /// An owning string that represents a tail slice of an RString. /// Guaranteed to be NUL-terminated. class TString : public _crtp_string<TString, TString, ZPair> { friend class SString; - FString _s; + RString _s; size_t _o; public: TString(); - TString(FString b, size_t i=0); + TString(RString b, size_t i=0); + TString(AString b, size_t i=0); //TString(const TString&) TString(const SString&); TString(const ZString&); @@ -50,7 +51,7 @@ namespace strings iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; const char *c_str() const; }; diff --git a/src/strings/vstring.hpp b/src/strings/vstring.hpp index c07c32a..183e782 100644 --- a/src/strings/vstring.hpp +++ b/src/strings/vstring.hpp @@ -31,7 +31,8 @@ namespace strings public: typedef typename _crtp_string<VString<n>, VString<n>, ZPair>::iterator iterator; VString(XString x); - VString(FString f); + VString(RString f); + VString(AString f); VString(TString t); VString(SString s); VString(ZString z); @@ -48,7 +49,7 @@ namespace strings iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; const char *c_str() const; }; diff --git a/src/strings/vstring.tcc b/src/strings/vstring.tcc index 674b21d..69729d4 100644 --- a/src/strings/vstring.tcc +++ b/src/strings/vstring.tcc @@ -21,7 +21,8 @@ #include "../common/utils2.hpp" -#include "fstring.hpp" +#include "rstring.hpp" +#include "astring.hpp" #include "tstring.hpp" #include "sstring.hpp" #include "zstring.hpp" @@ -43,11 +44,16 @@ namespace strings // poor man's delegated constructors // needed for gcc 4.6 compatibility template<uint8_t n> - VString<n>::VString(FString f) + VString<n>::VString(RString f) { *this = XString(f); } template<uint8_t n> + VString<n>::VString(AString a) + { + *this = XString(a); + } + template<uint8_t n> VString<n>::VString(TString t) { *this = XString(t); @@ -109,7 +115,7 @@ namespace strings return std::end(_data) - _special; } template<uint8_t n> - const FString *VString<n>::base() const + const RString *VString<n>::base() const { return nullptr; } diff --git a/src/strings/xstring.cpp b/src/strings/xstring.cpp index 107217b..8a604c7 100644 --- a/src/strings/xstring.cpp +++ b/src/strings/xstring.cpp @@ -23,7 +23,10 @@ namespace strings XString::XString() : _b(""), _e(_b), _base() {} - XString::XString(const FString& s) + XString::XString(const RString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + XString::XString(const AString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} XString::XString(const TString& s) @@ -36,10 +39,10 @@ namespace strings : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - XString::XString(const char *b, const char *e, const FString *base_) + XString::XString(const char *b, const char *e, const RString *base_) : _b(b), _e(e), _base(base_) {} - XString::XString(decltype(really_construct_from_a_pointer) e, const char *s, const FString *base_) + XString::XString(decltype(really_construct_from_a_pointer) e, const char *s, const RString *base_) { *this = ZString(e, s, base_); } @@ -55,7 +58,7 @@ namespace strings { return _e; } - const FString *XString::base() const + const RString *XString::base() const { return _base; } diff --git a/src/strings/xstring.hpp b/src/strings/xstring.hpp index e96ef8a..2766810 100644 --- a/src/strings/xstring.hpp +++ b/src/strings/xstring.hpp @@ -25,17 +25,18 @@ namespace strings { /// A non-owning string that is not guaranteed to be NUL-terminated. /// This should be only used as a parameter. - class XString : public _crtp_string<XString, FString, XPair> + class XString : public _crtp_string<XString, AString, XPair> { iterator _b, _e; // optional - const FString *_base; + const RString *_base; public: // do I really want this? XString(); XString(std::nullptr_t) = delete; // no MString - XString(const FString& s); + XString(const RString& s); + XString(const AString& s); XString(const TString& s); XString(const SString& s); XString(const ZString& s); @@ -46,13 +47,13 @@ namespace strings template<size_t n> XString(const char (&s)[n]); // mostly internal - XString(const char *b, const char *e, const FString *base_); - XString(decltype(really_construct_from_a_pointer) e, const char *s, const FString *base_); + XString(const char *b, const char *e, const RString *base_); + XString(decltype(really_construct_from_a_pointer) e, const char *s, const RString *base_); XString(XPair p); iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; }; } // namespace strings diff --git a/src/strings/zstring.cpp b/src/strings/zstring.cpp index 0de836c..bfc0c96 100644 --- a/src/strings/zstring.cpp +++ b/src/strings/zstring.cpp @@ -26,16 +26,19 @@ namespace strings { *this = ZString(""); } - ZString::ZString(const FString& s) + ZString::ZString(const RString& s) + : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) + {} + ZString::ZString(const AString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} ZString::ZString(const TString& s) : _b(&*s.begin()), _e(&*s.end()), _base(s.base()) {} - ZString::ZString(const char *b, const char *e, const FString *base_) + ZString::ZString(const char *b, const char *e, const RString *base_) : _b(b), _e(e), _base(base_) {} - ZString::ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_) + ZString::ZString(decltype(really_construct_from_a_pointer), const char *s, const RString *base_) : _b(s), _e(s + strlen(s)), _base(base_) {} @@ -47,7 +50,7 @@ namespace strings { return _e; } - const FString *ZString::base() const + const RString *ZString::base() const { return _base; } diff --git a/src/strings/zstring.hpp b/src/strings/zstring.hpp index 72a227c..96aadc0 100644 --- a/src/strings/zstring.hpp +++ b/src/strings/zstring.hpp @@ -27,15 +27,16 @@ namespace strings { /// A non-owning string that is guaranteed to be NUL-terminated. /// This should be only used as a parameter. - class ZString : public _crtp_string<ZString, FString, ZPair> + class ZString : public _crtp_string<ZString, AString, ZPair> { iterator _b, _e; // optional - const FString *_base; + const RString *_base; public: ZString(); // no MString - ZString(const FString& s); + ZString(const RString& s); + ZString(const AString& s); ZString(const TString& s); ZString(const SString&) = delete; //ZString(ZString); @@ -43,16 +44,16 @@ namespace strings template<uint8_t n> ZString(const VString<n>& s); // dangerous - ZString(const char *b, const char *e, const FString *base_); - ZString(decltype(really_construct_from_a_pointer), const char *s, const FString *base_); + ZString(const char *b, const char *e, const RString *base_); + ZString(decltype(really_construct_from_a_pointer), const char *s, const RString *base_); template<size_t n> ZString(char (&s)[n]) = delete; template<size_t n> - ZString(const char (&s)[n], const FString *base_=nullptr); + ZString(const char (&s)[n], const RString *base_=nullptr); iterator begin() const; iterator end() const; - const FString *base() const; + const RString *base() const; const char *c_str() const; }; diff --git a/src/strings/zstring.tcc b/src/strings/zstring.tcc index 1065b7c..fe0e9f3 100644 --- a/src/strings/zstring.tcc +++ b/src/strings/zstring.tcc @@ -29,7 +29,7 @@ namespace strings {} template<size_t n> - ZString::ZString(const char (&s)[n], const FString *base_) + ZString::ZString(const char (&s)[n], const RString *base_) : _b(s), _e(s + strlen(s)), _base(base_) {} } // namespace strings |