From add7ff74ca25ca2c9cc591abc484f8e6d38b2c39 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Mon, 11 Aug 2014 22:52:18 -0700 Subject: Optimize string literals in refcounted strings --- src/strings/astring.cpp | 54 +++++------------------------- src/strings/astring.hpp | 2 +- src/strings/rstring.cpp | 77 ++++++++++++++++++++----------------------- src/strings/rstring.hpp | 13 ++++---- src/strings/rstring.tcc | 25 ++++++-------- src/strings/strings2_test.cpp | 6 ++-- 6 files changed, 67 insertions(+), 110 deletions(-) (limited to 'src/strings') diff --git a/src/strings/astring.cpp b/src/strings/astring.cpp index f1f12c3..e2521df 100644 --- a/src/strings/astring.cpp +++ b/src/strings/astring.cpp @@ -47,7 +47,6 @@ namespace strings std::copy(src + 0, src + 255, dst); } - // TODO dedup all this code once I drop gcc 4.6 support AString::AString() : data{}, special() { @@ -100,78 +99,43 @@ namespace strings } AString::AString(const MString& s) - : data{}, special() + : AString(s.begin(), s.end()) { - 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() + : AString(p.begin(), p.end()) { - new(r_ptr()) RString(); - special = 255; - *this = XString(p); } AString::AString(const TString& t) - : data{}, special() + : AString(XString(t)) { - new(r_ptr()) RString(); - special = 255; - *this = XString(t); } AString::AString(const SString& s) - : data{}, special() + : AString(XString(s)) { - new(r_ptr()) RString(); - special = 255; - *this = XString(s); } AString::AString(ZString z) - : data{}, special() + : AString(XString(z)) { - new(r_ptr()) RString(); - special = 255; - *this = XString(z); } AString::AString(XString x) - : data{}, special() + : AString() { if (const RString *r = x.base()) { if (&*r->begin() == &*x.begin() && &*r->end() == &*x.end()) { - new(r_ptr()) RString(*r); - special = 255; + *this = *r; 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(); - } + *this = AString(x.begin(), x.end()); } AString::AString(LString l) - : data{}, special() + : AString(RString(l)) { - new(r_ptr()) RString(); - special = 255; - *this = XString(l); } AString::iterator AString::begin() const diff --git a/src/strings/astring.hpp b/src/strings/astring.hpp index 83399f0..ccf2be6 100644 --- a/src/strings/astring.hpp +++ b/src/strings/astring.hpp @@ -35,7 +35,7 @@ namespace strings #ifdef __clang__ __attribute__((unused)) #endif - RString *align[0]; + RString align[0]; char data[255]; unsigned char special; RString *r_ptr() { return reinterpret_cast(data); } diff --git a/src/strings/rstring.cpp b/src/strings/rstring.cpp index 3e5a46d..e74d1d5 100644 --- a/src/strings/rstring.cpp +++ b/src/strings/rstring.cpp @@ -36,45 +36,46 @@ namespace tmwa { namespace strings { - static_assert(sizeof(RString) == sizeof(const char *), "RString"); - - uint8_t RString::empty_string_rep[sizeof(Rep) + 1]; - RString::RString() - : owned(reinterpret_cast(&empty_string_rep)) + : u{.begin= ""}, maybe_end(u.begin) + { + } + RString::RString(LString l) + : u{.begin= &*l.begin()}, maybe_end(&*l.end()) { - owned->count++; } RString::RString(const RString& r) - : owned(r.owned) + : u(r.u), maybe_end(r.maybe_end) { - owned->count++; + if (!maybe_end) + u.owned->count++; } RString::RString(RString&& r) - : owned(reinterpret_cast(&empty_string_rep)) + : RString() { - std::swap(owned, r.owned); - r.owned->count++; + *this = std::move(r); } RString& RString::operator = (const RString& r) { // order important for self-assign - r.owned->count++; - // owned can be nullptr from ctors - // TODO do ctors *properly* (requires gcc 4.7 to stay sane) - if (owned && !owned->count--) - ::operator delete(owned); - owned = r.owned; + if (!r.maybe_end) + r.u.owned->count++; + if (!maybe_end && !u.owned->count--) + ::operator delete(u.owned); + u = r.u; + maybe_end = r.maybe_end; return *this; } RString& RString::operator = (RString&& r) { - std::swap(owned, r.owned); + std::swap(u, r.u); + std::swap(maybe_end, r.maybe_end); return *this; } + RString::RString(AString a) - : owned(nullptr) + : RString() { if (RString *r = const_cast(a.base())) { @@ -87,41 +88,36 @@ namespace strings } RString::~RString() { - if (owned && !owned->count--) - ::operator delete(owned); - owned = nullptr; + if (!maybe_end && !u.owned->count--) + ::operator delete(u.owned); } RString::RString(const MString& s) - : owned(nullptr) + : RString(s.begin(), s.end()) { - _assign(s.begin(), s.end()); } RString::RString(XPair p) - : owned(nullptr) + : RString(p.begin(), p.end()) { - _assign(p.begin(), p.end()); } RString::RString(const TString& t) - : owned(nullptr) + : RString(XString(t)) { - *this = XString(t); } RString::RString(const SString& s) - : owned(nullptr) + : RString(XString(s)) { - *this = XString(s); } RString::RString(ZString z) - : owned(nullptr) + : RString(XString(z)) { - *this = XString(z); } RString::RString(XString x) - : owned(nullptr) + : RString() { + // long term this stuff will change again const RString *f = x.base(); const char *xb = &*x.begin(); const char *xe = &*x.end(); @@ -130,21 +126,20 @@ namespace strings if (f && xb == fb && xe == fe) *this = *f; else - _assign(x.begin(), x.end()); - } - RString::RString(LString l) - : owned(nullptr) - { - *this = XString(l); + *this = RString(x.begin(), x.end()); } RString::iterator RString::begin() const { - return owned->body; + if (maybe_end) + return u.begin; + return u.owned->body; } RString::iterator RString::end() const { - return owned->body + owned->size; + if (maybe_end) + return maybe_end; + return u.owned->body + u.owned->size; } const RString *RString::base() const { diff --git a/src/strings/rstring.hpp b/src/strings/rstring.hpp index fd3ee65..ad44beb 100644 --- a/src/strings/rstring.hpp +++ b/src/strings/rstring.hpp @@ -39,15 +39,17 @@ namespace strings size_t size; char body[]; }; - static - uint8_t empty_string_rep[sizeof(Rep) + 1]; - Rep *owned; + union + { + Rep *owned; + const char *begin; + } u; + const char *maybe_end; - template - void _assign(It b, It e); public: RString(); + RString(LString s); RString(const RString&); RString(RString&&); RString& operator = (const RString&); @@ -68,7 +70,6 @@ namespace strings RString(XString); template RString(const VString& v); - RString(LString s); iterator begin() const; iterator end() const; diff --git a/src/strings/rstring.tcc b/src/strings/rstring.tcc index c247b8f..8a85b1d 100644 --- a/src/strings/rstring.tcc +++ b/src/strings/rstring.tcc @@ -1,6 +1,6 @@ // strings/rstring.tcc - Inline functions for rstring.hpp // -// Copyright © 2013 Ben Longbons +// Copyright © 2013-2014 Ben Longbons // // This file is part of The Mana World (Athena server) // @@ -25,12 +25,11 @@ namespace tmwa namespace strings { template - void RString::_assign(It b, It e) + RString::RString(It b, It e) + : RString() { - owned = nullptr; if (b == e) { - *this = RString(); return; } if (!std::is_base_of::iterator_category>::value) @@ -43,23 +42,19 @@ namespace strings return; } size_t diff = std::distance(b, e); - owned = static_cast(::operator new(sizeof(Rep) + diff + 1)); - owned->count = 0; - owned->size = diff; - std::copy(b, e, owned->body); - owned->body[diff] = '\0'; - } + u.owned = static_cast(::operator new(sizeof(Rep) + diff + 1)); + maybe_end = nullptr; - template - RString::RString(It b, It e) - { - _assign(b, e); + u.owned->count = 0; + u.owned->size = diff; + std::copy(b, e, u.owned->body); + u.owned->body[diff] = '\0'; } template RString::RString(const VString& v) + : RString(v.begin(), v.end()) { - _assign(v.begin(), v.end()); } } // namespace strings } // namespace tmwa diff --git a/src/strings/strings2_test.cpp b/src/strings/strings2_test.cpp index 18c7db4..8ac8482 100644 --- a/src/strings/strings2_test.cpp +++ b/src/strings/strings2_test.cpp @@ -170,9 +170,11 @@ TEST(StringTests, rempty) TEST(StringTests, rshort) { LString short_text = "0123456789"_s; - RString r = short_text; + EXPECT_EQ(&*short_text.begin(), &*RString(short_text).begin()); + EXPECT_EQ(&*short_text.begin(), &*AString(short_text).begin()); + RString r = VString<255>(short_text); EXPECT_EQ(r.size(), 10); - AString a = short_text; + AString a = VString<255>(short_text); EXPECT_EQ(r, a); AString r2 = r, r3; RString a2 = a, a3; -- cgit v1.2.3-60-g2f50