diff --git a/include/raii/rjp_string.hpp b/include/raii/rjp_string.hpp index 9ae7612..72bec3a 100644 --- a/include/raii/rjp_string.hpp +++ b/include/raii/rjp_string.hpp @@ -48,7 +48,7 @@ namespace raii{ using string_intermediary::string_intermediary; rjp_string(RJP_value* r): - string_intermediary(r ? std::exchange(r->string.value, nullptr) : nullptr, r ? r->string.length : 0){} + string_intermediary(r ? std::exchange(r->string.value, nullptr) : nullptr, r ? r->string.length : 0, r ? r->string.length : 0){} using string_intermediary::operator=; rjp_string& operator=(RJP_value* r){ if(!r) @@ -56,6 +56,7 @@ namespace raii{ reset(); m_data = std::exchange(r->string.value, nullptr); m_length = r->string.length; + m_cap = r->string.length; return *this; } }; diff --git a/include/raii/string_base.hpp b/include/raii/string_base.hpp index d6728ef..0373060 100644 --- a/include/raii/string_base.hpp +++ b/include/raii/string_base.hpp @@ -32,15 +32,18 @@ namespace raii{ { protected: size_t m_length = 0; + size_t m_cap = 0; char* m_data = nullptr; protected: constexpr string_base(void) = default; constexpr string_base(size_t len): - m_length(len){} + m_cap(len){} //Initialize without copying constexpr string_base(char* data, size_t len): - m_length(len), m_data(data){} + m_cap(len), m_data(data){} + constexpr string_base(char* data, size_t len, size_t cap): + m_length(len), m_cap(cap), m_data(data){} //Copy ctor (do nothing) string_base(const string_base&){} ~string_base(void) = default; @@ -51,6 +54,7 @@ namespace raii{ //Length of string not including null terminator constexpr size_t length(void)const{return m_length;} + constexpr size_t capacity(void)const{return m_cap;} //direct access to managed pointer constexpr char* get(void){return m_data;} constexpr const char* get(void)const{return m_data;} @@ -75,8 +79,10 @@ namespace raii{ string_intermediary(void) = default; string_intermediary(char* data, size_t len); string_intermediary(const char* data, size_t len); + string_intermediary(char* data, size_t len, size_t cap); string_intermediary(const char* data); string_intermediary(size_t len); + string_intermediary(size_t len, size_t cap); //normal copy and move ctors string_intermediary(const string_intermediary& b); @@ -184,7 +190,6 @@ namespace raii{ { private: Targ& m_targ; - size_t m_pos = 0; public: appender(Targ& t); template diff --git a/include/raii/string_base.tpp b/include/raii/string_base.tpp index 1279c60..682a471 100644 --- a/include/raii/string_base.tpp +++ b/include/raii/string_base.tpp @@ -22,12 +22,16 @@ #include //forward, move, swap, etc #include //memcpy #include //strlen, strcpy +#include //max namespace raii{ template string_intermediary::string_intermediary(char* data, size_t len): string_base(data, len){} template + string_intermediary::string_intermediary(char* data, size_t len, size_t cap): + string_base(data, len, cap){} + template string_intermediary::string_intermediary(const char* data, size_t len): string_base(reinterpret_cast(len ? Allocator::copy(data, len+1) : nullptr), len) { @@ -37,8 +41,10 @@ namespace raii{ string_intermediary::string_intermediary(const char* data): string_base(data ? strlen(data) : 0) { - if(m_length) - m_data = reinterpret_cast(Allocator::copy(data, m_length+1)); + if(m_cap){ + m_data = reinterpret_cast(Allocator::copy(data, m_cap+1)); + m_length = m_cap; + } } template string_intermediary::string_intermediary(size_t len): @@ -46,18 +52,24 @@ namespace raii{ { m_data[len] = 0; } + template + string_intermediary::string_intermediary(size_t len, size_t cap): + string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len, cap) + { + m_data[len] = 0; + } //normal copy and move ctors template string_intermediary::string_intermediary(const string_intermediary& b): - string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length){} + string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} template string_intermediary::string_intermediary(string_intermediary&& s): - string_base(std::exchange(s.m_data, nullptr), s.m_length){} + string_base(std::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} template string_intermediary::string_intermediary(const string_base& b): - string_base(reinterpret_cast(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length()){} + string_base(reinterpret_cast(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){} //dtor template @@ -67,6 +79,11 @@ namespace raii{ template string_intermediary& string_intermediary::operator=(const string_intermediary& s){ + if(s.m_length < m_length){ + memcpy(m_data, s.m_data, s.m_length+1); + m_length = s.m_length; + return *this; + } string_intermediary tmp(s); return (*this = std::move(tmp)); } @@ -74,6 +91,7 @@ namespace raii{ string_intermediary& string_intermediary::operator=(string_intermediary&& s){ std::swap(m_data, s.m_data); m_length = s.m_length; + m_cap = s.m_cap; return *this; } //Copy from c string @@ -93,16 +111,18 @@ namespace raii{ Allocator::free(m_data); m_data = val; m_length = val ? strlen(val) : 0; + m_cap = m_length; } template void string_intermediary::reset(char* val, size_t len){ Allocator::free(m_data); m_data = val; m_length = len; + m_cap = len; } template bool string_intermediary::resize(size_t newsize){ - if(newsize < m_length) + if(newsize < m_cap) return false; string_intermediary tmp(newsize); memcpy(tmp.get(), m_data, m_length); @@ -112,23 +132,27 @@ namespace raii{ } template void string_intermediary::append(const char* data, size_t len){ - string_intermediary tmp(m_length + len); - memcpy(tmp.m_data, m_data, m_length); - memcpy(tmp.m_data+m_length, data, len); - tmp[m_length+len] = 0; - *this = std::move(tmp); + if(len+m_length <= m_cap){ + memcpy(m_data+m_length, data, len); + m_length += len; + m_data[m_length] = 0; + }else{ + string_intermediary tmp(std::max(m_length + len, m_cap*2)); + memcpy(tmp.m_data, m_data, m_length); + memcpy(tmp.m_data+m_length, data, len); + tmp.m_length = len+m_length; + tmp[m_length+len] = 0; + *this = std::move(tmp); + } } template void string_intermediary::append(const char* data){ - size_t len = strlen(data); - resize(m_length+len); - memcpy(m_data+m_length, data, len); - m_length += len; - m_data[m_length] = 0; + if(data) + append(data, strlen(data)); } template void string_intermediary::append(const string_base& s){ - append(s.get()); + append(s.get(), s.length()); } template @@ -136,15 +160,18 @@ namespace raii{ if(!len){ Allocator::free(m_data); m_length = 0; + m_cap = 0; return *this; } if(len <= m_length){ strcpy(m_data, s); }else{ Allocator::free(m_data); - m_data = reinterpret_cast(Allocator::copy(s, len+1)); + m_cap = std::max(len, m_cap*2); + m_data = reinterpret_cast(Allocator::copy(s, m_cap+1)); if(!m_data){ m_length = 0; + m_cap = 0; return *this; } } @@ -174,9 +201,8 @@ namespace raii{ template template string_cat_expr::operator string_intermediary(void){ - string_intermediary ret(length()); - for(size_t i = 0;i < length();++i) - ret[i] = 'n'; + size_t len = length(); + string_intermediary ret(len); detail::appender> append(ret); append(*this); return ret; @@ -193,13 +219,13 @@ namespace raii{ template constexpr static_string::static_string(const char(&str)[N]): - string_base(const_cast(str), N){} + string_base(const_cast(str), N, N){} constexpr static_string::static_string(const char* str, size_t len): - string_base(const_cast(str), len){} + string_base(const_cast(str), len, len){} constexpr static_string::static_string(const static_string& s): - string_base(s.m_data, s.m_length){} + string_base(s.m_data, s.m_length, s.m_length){} constexpr static_string::static_string(static_string&& s): - string_base(s.m_data, s.m_length){} + string_base(s.m_data, s.m_length, s.m_length){} namespace detail{ template @@ -212,8 +238,7 @@ namespace raii{ } template void appender::operator()(const string_base& str){ - memcpy(m_targ.get()+m_pos, str.get(), str.length()); - m_pos += str.length(); + m_targ.append(str.get(), str.length()); } } diff --git a/src/raii/curler.cpp b/src/raii/curler.cpp index 4868ea2..5144ead 100644 --- a/src/raii/curler.cpp +++ b/src/raii/curler.cpp @@ -114,7 +114,8 @@ namespace raii{ curl_string curler::encode(const char* data, int len){ char* tmp = curl_easy_escape(m_curl, data, len); - return curl_string(tmp, strlen(tmp)); + size_t esclen = strlen(tmp); + return curl_string(tmp, esclen, esclen); } curl_string curler::decode(const char* data, int* outlen, int len){ if(outlen) diff --git a/src/raii/string_base.cpp b/src/raii/string_base.cpp index b2f2b63..1ff38a3 100644 --- a/src/raii/string_base.cpp +++ b/src/raii/string_base.cpp @@ -34,7 +34,7 @@ namespace raii{ } static_string::static_string(const char* c): - string_base(const_cast(c), strlen(c)){} + static_string(const_cast(c), strlen(c)){} static_string& static_string::operator=(const char* c){ m_data = const_cast(c); m_length = strlen(c); diff --git a/src/raii/util.cpp b/src/raii/util.cpp index 22f7c4e..7c359a2 100644 --- a/src/raii/util.cpp +++ b/src/raii/util.cpp @@ -87,7 +87,7 @@ namespace raii{ char* tmp = reinterpret_cast(string::allocator_type::allocate(len+1)); detail::_sanitize_json_copy(tmp, str); tmp[len] = 0; - return string(tmp, len); + return string(tmp, len, len); } @@ -116,7 +116,7 @@ namespace raii{ if(i == 0) return raii::string("0"); int place = intlen(i); - raii::string ret(place); + raii::string ret(place, place); char* buf = ret.get(); buf[place] = 0; while(i != 0){