diff --git a/include/co/fast.h b/include/co/fast.h index 68bda7c86..d6e014ed2 100644 --- a/include/co/fast.h +++ b/include/co/fast.h @@ -123,10 +123,6 @@ class __coapi stream { _p = cap > 0 ? (char*)co::alloc(cap) : 0; } - stream(char* p, size_t cap, size_t size) noexcept - : _cap(cap), _size(size), _p(p) { - } - ~stream() { this->reset(); } stream(const stream&) = delete; @@ -146,6 +142,7 @@ class __coapi stream { return *this; } + char* data() noexcept { return _p; } const char* data() const noexcept { return _p; } size_t size() const noexcept { return _size; } bool empty() const noexcept { return _size == 0; } @@ -159,30 +156,33 @@ class __coapi stream { } const char* c_str() const { - ((stream*)this)->reserve(_size + 1); - if (_p[_size] != '\0') _p[_size] = '\0'; - return _p; + if (_p) { + assert(_size < _cap); + if (_p[_size] != '\0') _p[_size] = '\0'; + return _p; + } + return ""; } char& back() { return _p[_size - 1]; } - const char& back() const { return ((stream*)this)->back(); } + const char& back() const { return _p[_size - 1]; } char& front() { return _p[0]; } - const char& front() const { return ((stream*)this)->front(); } + const char& front() const { return _p[0]; } char& operator[](size_t i) { return _p[i]; } - const char& operator[](size_t i) const { return ((stream*)this)->operator[](i); } + const char& operator[](size_t i) const { return _p[i]; } // resize only, will not fill the expanded memory with zeros void resize(size_t n) { - this->reserve(n); + this->reserve(n + 1); _size = n; } // resize and fill the expanded memory with character @c void resize(size_t n, char c) { if (_size < n) { - this->reserve(n); + this->reserve(n + 1); memset(_p + _size, c, n - _size); } _size = n; @@ -204,9 +204,9 @@ class __coapi stream { } void ensure(size_t n) { - if (_cap < _size + n) { + if (_cap < _size + n + 1) { const size_t cap = _cap; - _cap += ((_cap >> 1) + n); + _cap += ((_cap >> 1) + n + 1); _p = (char*) co::realloc(_p, cap, _cap); assert(_p); } } diff --git a/include/co/fastream.h b/include/co/fastream.h index 88fb8e9aa..b75e247d8 100644 --- a/include/co/fastream.h +++ b/include/co/fastream.h @@ -56,9 +56,10 @@ class __coapi fastream : public fast::stream { return this->append_nomchk(s.data(), s.size()); } + // append the fastream itself is ok fastream& append(const fastream& s) { if (&s != this) return this->append_nomchk(s.data(), s.size()); - this->reserve(_size << 1); + this->reserve((_size << 1) + !!_size); memcpy(_p + _size, _p, _size); // append itself _size <<= 1; return *this; @@ -69,10 +70,6 @@ class __coapi fastream : public fast::stream { return (fastream&) fast::stream::append(n, c); } - fastream& append(char c, size_t n) { - return this->append(n, c); - } - fastream& append(char c) { return (fastream&) fast::stream::append(c); } diff --git a/include/co/fastring.h b/include/co/fastring.h index 0c4a3df17..c5bbbdc44 100644 --- a/include/co/fastring.h +++ b/include/co/fastring.h @@ -34,22 +34,15 @@ class __coapi fastring : public fast::stream { : fast::stream(cap) { } - // @p: memory allocated by co::alloc() - fastring(char* p, size_t cap, size_t size) noexcept - : fast::stream(p, cap, size) { - } - ~fastring() = default; fastring(size_t n, char c) - : fast::stream(n, n) { + : fast::stream(n + 1, n) { memset(_p, c, n); } - fastring(char c, size_t n) : fastring(n, c) {} - fastring(const void* s, size_t n) - : fast::stream(n, n) { + : fast::stream(n + !!n, n) { memcpy(_p, s, n); } @@ -93,6 +86,13 @@ class __coapi fastring : public fast::stream { return *this; } + fastring& assign(size_t n, char c) { + this->reserve(n + 1); + memset(_p, c, n); + _size = n; + return *this; + } + template fastring& assign(S&& s) { return this->operator=(std::forward(s)); @@ -118,7 +118,7 @@ class __coapi fastring : public fast::stream { fastring& append(const fastring& s) { if (&s != this) return this->append_nomchk(s.data(), s.size()); - this->reserve(_size << 1); + this->reserve((_size << 1) + !!_size); memcpy(_p + _size, _p, _size); // append itself _size <<= 1; return *this; @@ -132,10 +132,6 @@ class __coapi fastring : public fast::stream { return (fastring&) fast::stream::append(n, c); } - fastring& append(char c, size_t n) { - return this->append(n, c); - } - fastring& append(char c) { return (fastring&) fast::stream::append(c); } @@ -439,15 +435,11 @@ class __coapi fastring : public fast::stream { fastring& toupper(); fastring lower() const { - fastring s(*this); - s.tolower(); - return s; + fastring s(*this); s.tolower(); return s; } fastring upper() const { - fastring s(*this); - s.toupper(); - return s; + fastring s(*this); s.toupper(); return s; } fastring substr(size_t pos) const { @@ -693,7 +685,7 @@ class __coapi fastring : public fast::stream { fastring& _assign(const void* s, size_t n) { _size = n; if (n > 0) { - this->reserve(n); + this->reserve(n + 1); memcpy(_p, s, n); } return *this; diff --git a/src/fastring.cc b/src/fastring.cc index d423e7f22..69af3f3c5 100644 --- a/src/fastring.cc +++ b/src/fastring.cc @@ -246,7 +246,7 @@ fastring& fastring::replace(const char* sub, size_t n, const char* to, size_t m, if (!p) return *this; const char* const e = _p + _size; - fastring s(_size); + fastring s(_size + 1); do { s.append(from, p - from).append(to, m); diff --git a/unitest/fastream.cc b/unitest/fastream.cc index 7c2daabb7..32f03d677 100644 --- a/unitest/fastream.cc +++ b/unitest/fastream.cc @@ -51,6 +51,9 @@ DEF_test(fastream) { EXPECT_EQ(fs.size(), 1); fs.clear(); EXPECT_EQ(fs.size(), 0); + + fs.reset(); + EXPECT_EQ(fs.capacity(), 0); } DEF_case(cat) { @@ -157,9 +160,14 @@ DEF_test(fastream) { fs.clear(); fs << fs; EXPECT_EQ(fs.str(), ""); - fs << "x"; + + fs.reset(); + fs << "xx"; + EXPECT_EQ(fs.capacity(), 3); + fs << fs; - EXPECT_EQ(fs.str(), "xx"); + EXPECT_EQ(fs.str(), "xxxx"); + EXPECT_EQ(fs.capacity(), 5); } DEF_case(ptr) { diff --git a/unitest/fastring.cc b/unitest/fastring.cc index 373ea49a8..5374108ba 100644 --- a/unitest/fastring.cc +++ b/unitest/fastring.cc @@ -18,6 +18,7 @@ DEF_test(fastring) { { fastring s(4, 'x'); EXPECT_EQ(s.size(), 4); + EXPECT_EQ(s.capacity(), 5); EXPECT_EQ(s, "xxxx"); } { @@ -29,11 +30,13 @@ DEF_test(fastring) { fastring s("helloworld", 5); EXPECT_EQ(s.size(), 5); EXPECT_EQ(s, "hello"); + EXPECT_LT(s.size(), s.capacity()); } { fastring s("helloworld"); EXPECT_EQ(s.size(), 10); EXPECT_EQ(s, "helloworld"); + EXPECT_LT(s.size(), s.capacity()); } } @@ -91,9 +94,10 @@ DEF_test(fastring) { s.append(s); EXPECT_EQ(s, ""); - s.append('x', 3); + s.append(3, 'x'); EXPECT_EQ(s.size(), 3); EXPECT_EQ(s, "xxx"); + EXPECT_LT(s.size(), s.capacity()); s.append(s); // append self EXPECT_EQ(s, "xxxxxx"); @@ -156,6 +160,12 @@ DEF_test(fastring) { s = s.c_str() + 1; EXPECT_EQ(s, "345"); + + s.assign(3, '0'); + EXPECT_EQ(s, "000"); + + s.assign(31, '0'); + EXPECT_EQ(s, fastring(31, '0')); } DEF_case(cat) { @@ -165,6 +175,60 @@ DEF_test(fastring) { EXPECT_EQ(s.cat(' ', "hello ", false), "123 hello false"); } + DEF_case(c_str) { + { + fastring s; + EXPECT_EQ(fastring(s.c_str()), ""); + } + { + fastring s("xxx", 3); + EXPECT_LT(s.size(), s.capacity()); + const char* p = s.data(); + EXPECT_EQ(p, s.c_str()) + + fastring x(7, 'x'); + EXPECT_LT(x.size(), x.capacity()); + + s.assign(x.data(), x.size()); + EXPECT_LT(s.size(), s.capacity()); + EXPECT_EQ(s, "xxxxxxx"); + EXPECT_EQ(s.capacity(), 8); + + s.append('x'); + EXPECT_LT(s.size(), s.capacity()); + p = s.data(); + EXPECT_EQ(p, s.c_str()) + + s.append(s.capacity() - s.size(), 'x'); + EXPECT_LT(s.size(), s.capacity()); + p = s.data(); + EXPECT_EQ(p, s.c_str()) + + x.assign(s.capacity() - s.size() + 3, 'x'); + s.append(x.data(), x.size()); + EXPECT_LT(s.size(), s.capacity()); + p = s.data(); + EXPECT_EQ(p, s.c_str()); + } + { + const char* p; + fastring s; + s << false; + EXPECT_LT(s.size(), s.capacity()); + + s.reset(); + s << 1234567; + EXPECT_LT(s.size(), s.capacity()); + + s.reset(); + s << 3.1415926; + EXPECT_LT(s.size(), s.capacity()); + + p = s.data(); + EXPECT_EQ(p, s.c_str()); + } + } + DEF_case(operator<<) { fastring s; { @@ -543,6 +607,7 @@ DEF_test(fastring) { fastring s(256); (s = "hello world").shrink(); EXPECT_LT(s.capacity(), 256); + EXPECT_EQ(s.capacity(), 12); EXPECT_EQ(s, "hello world"); }