Change string management to improve appending performance

This commit is contained in:
rexy712 2020-01-18 19:59:04 -08:00
parent a73c9940fe
commit 8a4cae1ccf
6 changed files with 67 additions and 35 deletions

View File

@ -48,7 +48,7 @@ namespace raii{
using string_intermediary<detail::rjp_allocator>::string_intermediary; using string_intermediary<detail::rjp_allocator>::string_intermediary;
rjp_string(RJP_value* r): rjp_string(RJP_value* r):
string_intermediary<detail::rjp_allocator>(r ? std::exchange(r->string.value, nullptr) : nullptr, r ? r->string.length : 0){} string_intermediary<detail::rjp_allocator>(r ? std::exchange(r->string.value, nullptr) : nullptr, r ? r->string.length : 0, r ? r->string.length : 0){}
using string_intermediary<detail::rjp_allocator>::operator=; using string_intermediary<detail::rjp_allocator>::operator=;
rjp_string& operator=(RJP_value* r){ rjp_string& operator=(RJP_value* r){
if(!r) if(!r)
@ -56,6 +56,7 @@ namespace raii{
reset(); reset();
m_data = std::exchange(r->string.value, nullptr); m_data = std::exchange(r->string.value, nullptr);
m_length = r->string.length; m_length = r->string.length;
m_cap = r->string.length;
return *this; return *this;
} }
}; };

View File

@ -32,15 +32,18 @@ namespace raii{
{ {
protected: protected:
size_t m_length = 0; size_t m_length = 0;
size_t m_cap = 0;
char* m_data = nullptr; char* m_data = nullptr;
protected: protected:
constexpr string_base(void) = default; constexpr string_base(void) = default;
constexpr string_base(size_t len): constexpr string_base(size_t len):
m_length(len){} m_cap(len){}
//Initialize without copying //Initialize without copying
constexpr string_base(char* data, size_t len): 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) //Copy ctor (do nothing)
string_base(const string_base&){} string_base(const string_base&){}
~string_base(void) = default; ~string_base(void) = default;
@ -51,6 +54,7 @@ namespace raii{
//Length of string not including null terminator //Length of string not including null terminator
constexpr size_t length(void)const{return m_length;} constexpr size_t length(void)const{return m_length;}
constexpr size_t capacity(void)const{return m_cap;}
//direct access to managed pointer //direct access to managed pointer
constexpr char* get(void){return m_data;} constexpr char* get(void){return m_data;}
constexpr const char* get(void)const{return m_data;} constexpr const char* get(void)const{return m_data;}
@ -75,8 +79,10 @@ namespace raii{
string_intermediary(void) = default; string_intermediary(void) = default;
string_intermediary(char* data, size_t len); string_intermediary(char* data, size_t len);
string_intermediary(const 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(const char* data);
string_intermediary(size_t len); string_intermediary(size_t len);
string_intermediary(size_t len, size_t cap);
//normal copy and move ctors //normal copy and move ctors
string_intermediary(const string_intermediary& b); string_intermediary(const string_intermediary& b);
@ -184,7 +190,6 @@ namespace raii{
{ {
private: private:
Targ& m_targ; Targ& m_targ;
size_t m_pos = 0;
public: public:
appender(Targ& t); appender(Targ& t);
template<class L, class R> template<class L, class R>

View File

@ -22,12 +22,16 @@
#include <utility> //forward, move, swap, etc #include <utility> //forward, move, swap, etc
#include <cstdlib> //memcpy #include <cstdlib> //memcpy
#include <cstring> //strlen, strcpy #include <cstring> //strlen, strcpy
#include <algorithm> //max
namespace raii{ namespace raii{
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(char* data, size_t len): string_intermediary<Allocator>::string_intermediary(char* data, size_t len):
string_base(data, len){} string_base(data, len){}
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap):
string_base(data, len, cap){}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const char* data, size_t len): string_intermediary<Allocator>::string_intermediary(const char* data, size_t len):
string_base(reinterpret_cast<char*>(len ? Allocator::copy(data, len+1) : nullptr), len) string_base(reinterpret_cast<char*>(len ? Allocator::copy(data, len+1) : nullptr), len)
{ {
@ -37,8 +41,10 @@ namespace raii{
string_intermediary<Allocator>::string_intermediary(const char* data): string_intermediary<Allocator>::string_intermediary(const char* data):
string_base(data ? strlen(data) : 0) string_base(data ? strlen(data) : 0)
{ {
if(m_length) if(m_cap){
m_data = reinterpret_cast<char*>(Allocator::copy(data, m_length+1)); m_data = reinterpret_cast<char*>(Allocator::copy(data, m_cap+1));
m_length = m_cap;
}
} }
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(size_t len): string_intermediary<Allocator>::string_intermediary(size_t len):
@ -46,18 +52,24 @@ namespace raii{
{ {
m_data[len] = 0; m_data[len] = 0;
} }
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(size_t len, size_t cap):
string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len, cap)
{
m_data[len] = 0;
}
//normal copy and move ctors //normal copy and move ctors
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const string_intermediary& b): string_intermediary<Allocator>::string_intermediary(const string_intermediary& b):
string_base(reinterpret_cast<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length){} string_base(reinterpret_cast<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){}
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(string_intermediary&& s): string_intermediary<Allocator>::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<class Allocator> template<class Allocator>
string_intermediary<Allocator>::string_intermediary(const string_base& b): string_intermediary<Allocator>::string_intermediary(const string_base& b):
string_base(reinterpret_cast<char*>(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length()){} string_base(reinterpret_cast<char*>(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){}
//dtor //dtor
template<class Allocator> template<class Allocator>
@ -67,6 +79,11 @@ namespace raii{
template<class Allocator> template<class Allocator>
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_intermediary& s){ string_intermediary<Allocator>& string_intermediary<Allocator>::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); string_intermediary tmp(s);
return (*this = std::move(tmp)); return (*this = std::move(tmp));
} }
@ -74,6 +91,7 @@ namespace raii{
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){ string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){
std::swap(m_data, s.m_data); std::swap(m_data, s.m_data);
m_length = s.m_length; m_length = s.m_length;
m_cap = s.m_cap;
return *this; return *this;
} }
//Copy from c string //Copy from c string
@ -93,16 +111,18 @@ namespace raii{
Allocator::free(m_data); Allocator::free(m_data);
m_data = val; m_data = val;
m_length = val ? strlen(val) : 0; m_length = val ? strlen(val) : 0;
m_cap = m_length;
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::reset(char* val, size_t len){ void string_intermediary<Allocator>::reset(char* val, size_t len){
Allocator::free(m_data); Allocator::free(m_data);
m_data = val; m_data = val;
m_length = len; m_length = len;
m_cap = len;
} }
template<class Allocator> template<class Allocator>
bool string_intermediary<Allocator>::resize(size_t newsize){ bool string_intermediary<Allocator>::resize(size_t newsize){
if(newsize < m_length) if(newsize < m_cap)
return false; return false;
string_intermediary tmp(newsize); string_intermediary tmp(newsize);
memcpy(tmp.get(), m_data, m_length); memcpy(tmp.get(), m_data, m_length);
@ -112,23 +132,27 @@ namespace raii{
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const char* data, size_t len){ void string_intermediary<Allocator>::append(const char* data, size_t len){
string_intermediary tmp(m_length + len); if(len+m_length <= m_cap){
memcpy(tmp.m_data, m_data, m_length); memcpy(m_data+m_length, data, len);
memcpy(tmp.m_data+m_length, data, len); m_length += len;
tmp[m_length+len] = 0; m_data[m_length] = 0;
*this = std::move(tmp); }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<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const char* data){ void string_intermediary<Allocator>::append(const char* data){
size_t len = strlen(data); if(data)
resize(m_length+len); append(data, strlen(data));
memcpy(m_data+m_length, data, len);
m_length += len;
m_data[m_length] = 0;
} }
template<class Allocator> template<class Allocator>
void string_intermediary<Allocator>::append(const string_base& s){ void string_intermediary<Allocator>::append(const string_base& s){
append(s.get()); append(s.get(), s.length());
} }
template<class Allocator> template<class Allocator>
@ -136,15 +160,18 @@ namespace raii{
if(!len){ if(!len){
Allocator::free(m_data); Allocator::free(m_data);
m_length = 0; m_length = 0;
m_cap = 0;
return *this; return *this;
} }
if(len <= m_length){ if(len <= m_length){
strcpy(m_data, s); strcpy(m_data, s);
}else{ }else{
Allocator::free(m_data); Allocator::free(m_data);
m_data = reinterpret_cast<char*>(Allocator::copy(s, len+1)); m_cap = std::max(len, m_cap*2);
m_data = reinterpret_cast<char*>(Allocator::copy(s, m_cap+1));
if(!m_data){ if(!m_data){
m_length = 0; m_length = 0;
m_cap = 0;
return *this; return *this;
} }
} }
@ -174,9 +201,8 @@ namespace raii{
template<class Left, class Right> template<class Left, class Right>
template<class Alloc> template<class Alloc>
string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){ string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){
string_intermediary<Alloc> ret(length()); size_t len = length();
for(size_t i = 0;i < length();++i) string_intermediary<Alloc> ret(len);
ret[i] = 'n';
detail::appender<string_intermediary<Alloc>> append(ret); detail::appender<string_intermediary<Alloc>> append(ret);
append(*this); append(*this);
return ret; return ret;
@ -193,13 +219,13 @@ namespace raii{
template<size_t N> template<size_t N>
constexpr static_string::static_string(const char(&str)[N]): constexpr static_string::static_string(const char(&str)[N]):
string_base(const_cast<char*>(str), N){} string_base(const_cast<char*>(str), N, N){}
constexpr static_string::static_string(const char* str, size_t len): constexpr static_string::static_string(const char* str, size_t len):
string_base(const_cast<char*>(str), len){} string_base(const_cast<char*>(str), len, len){}
constexpr static_string::static_string(const static_string& s): 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): 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{ namespace detail{
template<class Targ> template<class Targ>
@ -212,8 +238,7 @@ namespace raii{
} }
template<class Targ> template<class Targ>
void appender<Targ>::operator()(const string_base& str){ void appender<Targ>::operator()(const string_base& str){
memcpy(m_targ.get()+m_pos, str.get(), str.length()); m_targ.append(str.get(), str.length());
m_pos += str.length();
} }
} }

View File

@ -114,7 +114,8 @@ namespace raii{
curl_string curler::encode(const char* data, int len){ curl_string curler::encode(const char* data, int len){
char* tmp = curl_easy_escape(m_curl, data, 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){ curl_string curler::decode(const char* data, int* outlen, int len){
if(outlen) if(outlen)

View File

@ -34,7 +34,7 @@ namespace raii{
} }
static_string::static_string(const char* c): static_string::static_string(const char* c):
string_base(const_cast<char*>(c), strlen(c)){} static_string(const_cast<char*>(c), strlen(c)){}
static_string& static_string::operator=(const char* c){ static_string& static_string::operator=(const char* c){
m_data = const_cast<char*>(c); m_data = const_cast<char*>(c);
m_length = strlen(c); m_length = strlen(c);

View File

@ -87,7 +87,7 @@ namespace raii{
char* tmp = reinterpret_cast<char*>(string::allocator_type::allocate(len+1)); char* tmp = reinterpret_cast<char*>(string::allocator_type::allocate(len+1));
detail::_sanitize_json_copy(tmp, str); detail::_sanitize_json_copy(tmp, str);
tmp[len] = 0; tmp[len] = 0;
return string(tmp, len); return string(tmp, len, len);
} }
@ -116,7 +116,7 @@ namespace raii{
if(i == 0) if(i == 0)
return raii::string("0"); return raii::string("0");
int place = intlen(i); int place = intlen(i);
raii::string ret(place); raii::string ret(place, place);
char* buf = ret.get(); char* buf = ret.get();
buf[place] = 0; buf[place] = 0;
while(i != 0){ while(i != 0){