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;
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=;
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;
}
};

View File

@ -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<class L, class R>

View File

@ -22,12 +22,16 @@
#include <utility> //forward, move, swap, etc
#include <cstdlib> //memcpy
#include <cstring> //strlen, strcpy
#include <algorithm> //max
namespace raii{
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(char* data, size_t len):
string_base(data, len){}
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_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_base(data ? strlen(data) : 0)
{
if(m_length)
m_data = reinterpret_cast<char*>(Allocator::copy(data, m_length+1));
if(m_cap){
m_data = reinterpret_cast<char*>(Allocator::copy(data, m_cap+1));
m_length = m_cap;
}
}
template<class Allocator>
string_intermediary<Allocator>::string_intermediary(size_t len):
@ -46,18 +52,24 @@ namespace raii{
{
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
template<class Allocator>
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>
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>
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
template<class Allocator>
@ -67,6 +79,11 @@ namespace raii{
template<class Allocator>
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);
return (*this = std::move(tmp));
}
@ -74,6 +91,7 @@ namespace raii{
string_intermediary<Allocator>& string_intermediary<Allocator>::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<class Allocator>
void string_intermediary<Allocator>::reset(char* val, size_t len){
Allocator::free(m_data);
m_data = val;
m_length = len;
m_cap = len;
}
template<class Allocator>
bool string_intermediary<Allocator>::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<class Allocator>
void string_intermediary<Allocator>::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<class Allocator>
void string_intermediary<Allocator>::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<class Allocator>
void string_intermediary<Allocator>::append(const string_base& s){
append(s.get());
append(s.get(), s.length());
}
template<class Allocator>
@ -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<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){
m_length = 0;
m_cap = 0;
return *this;
}
}
@ -174,9 +201,8 @@ namespace raii{
template<class Left, class Right>
template<class Alloc>
string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){
string_intermediary<Alloc> ret(length());
for(size_t i = 0;i < length();++i)
ret[i] = 'n';
size_t len = length();
string_intermediary<Alloc> ret(len);
detail::appender<string_intermediary<Alloc>> append(ret);
append(*this);
return ret;
@ -193,13 +219,13 @@ namespace raii{
template<size_t 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):
string_base(const_cast<char*>(str), len){}
string_base(const_cast<char*>(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<class Targ>
@ -212,8 +238,7 @@ namespace raii{
}
template<class Targ>
void appender<Targ>::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());
}
}

View File

@ -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)

View File

@ -34,7 +34,7 @@ namespace raii{
}
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){
m_data = const_cast<char*>(c);
m_length = strlen(c);

View File

@ -87,7 +87,7 @@ namespace raii{
char* tmp = reinterpret_cast<char*>(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){