basic_fields optimizations

This commit is contained in:
Vinnie Falco
2017-06-23 09:33:28 -07:00
parent 9f7f36a3e9
commit 522d3bf378
3 changed files with 112 additions and 123 deletions

View File

@@ -8,6 +8,7 @@ Version 66:
* Handle bad_alloc in parser * Handle bad_alloc in parser
* Tidy up message piecewise ctors * Tidy up message piecewise ctors
* Add header aliases * Add header aliases
* basic_fields optimizations
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -624,6 +624,10 @@ private:
void void
realloc_string(string_view& dest, string_view s); realloc_string(string_view& dest, string_view s);
void
realloc_target(
string_view& dest, string_view s);
template<class OtherAlloc> template<class OtherAlloc>
void void
copy_all(basic_fields<OtherAlloc> const&); copy_all(basic_fields<OtherAlloc> const&);

View File

@@ -139,26 +139,17 @@ public:
bool bool
get_keep_alive(int version) const; get_keep_alive(int version) const;
template<class String>
void
prepare(String& s, basic_fields const& f,
unsigned version, verb v);
template<class String>
void
prepare(String&s, basic_fields const& f,
unsigned version, unsigned code);
basic_fields const& f_; basic_fields const& f_;
static_string<max_static_buffer> ss_; boost::asio::const_buffer cb_[3];
string_view sv_; char buf_[13];
std::string s_;
bool chunked_; bool chunked_;
bool keep_alive_; bool keep_alive_;
public: public:
using const_buffers_type = using const_buffers_type =
buffer_cat_view< buffer_cat_view<
boost::asio::const_buffers_1,
boost::asio::const_buffers_1,
boost::asio::const_buffers_1, boost::asio::const_buffers_1,
field_range, field_range,
boost::asio::const_buffers_1>; boost::asio::const_buffers_1>;
@@ -185,7 +176,9 @@ public:
get() const get() const
{ {
return buffer_cat( return buffer_cat(
boost::asio::buffer(sv_.data(), sv_.size()), boost::asio::const_buffers_1{cb_[0]},
boost::asio::const_buffers_1{cb_[1]},
boost::asio::const_buffers_1{cb_[2]},
field_range(f_.list_.begin(), f_.list_.end()), field_range(f_.list_.begin(), f_.list_.end()),
detail::chunk_crlf()); detail::chunk_crlf());
} }
@@ -226,89 +219,6 @@ get_keep_alive(int version) const
return ! token_list{it->value()}.exists("close"); return ! token_list{it->value()}.exists("close");
} }
template<class Allocator>
template<class String>
void
basic_fields<Allocator>::reader::
prepare(String& s, basic_fields const&,
unsigned version, verb v)
{
if(v == verb::unknown)
{
auto const sv =
f_.get_method_impl();
s.append(sv.data(), sv.size());
}
else
{
auto const sv = to_string(v);
s.append(sv.data(), sv.size());
}
s.push_back(' ');
{
auto const sv = f_.get_target_impl();
s.append(sv.data(), sv.size());
}
if(version == 11)
{
s.append(" HTTP/1.1\r\n");
}
else if(version == 10)
{
s.append(" HTTP/1.0\r\n");
}
else
{
s.append(" HTTP/");
s.push_back('0' + ((version / 10) % 10));
s.push_back('.');
s.push_back('0' + (version % 10));
s.append("\r\n");
}
}
template<class Allocator>
template<class String>
void
basic_fields<Allocator>::reader::
prepare(String& s, basic_fields const&,
unsigned version, unsigned code)
{
if(version == 11)
{
s.append("HTTP/1.1 ");
}
else if(version == 10)
{
s.append("HTTP/1.0 ");
}
else
{
s.append("HTTP/");
s.push_back('0' + ((version / 10) % 10));
s.push_back('.');
s.push_back('0' + (version % 10));
s.push_back(' ');
}
{
auto const ss = to_static_string(code);
s.append(ss.data(), ss.size());
}
s.push_back(' ');
if(int_to_status(code) == status::unknown)
{
auto const sv = f_.get_reason_impl();
s.append(sv.data(), sv.size());
}
else
{
auto const sv =
obsolete_reason(int_to_status(code));
s.append(sv.data(), sv.size());
}
s.append("\r\n");
}
template<class Allocator> template<class Allocator>
basic_fields<Allocator>::reader:: basic_fields<Allocator>::reader::
reader(basic_fields const& f, reader(basic_fields const& f,
@@ -317,16 +227,36 @@ reader(basic_fields const& f,
, chunked_(get_chunked()) , chunked_(get_chunked())
, keep_alive_(get_keep_alive(version)) , keep_alive_(get_keep_alive(version))
{ {
try /*
{ request
prepare(ss_, f, version, v); "<method>"
sv_ = ss_; " <target>"
} " HTTP/X.Y\r\n" (11 chars)
catch(std::length_error const&) */
{ string_view sv;
prepare(s_, f, version, v); if(v == verb::unknown)
sv_ = s_; sv = f_.get_method_impl();
} else
sv = to_string(v);
cb_[0] = {sv.data(), sv.size()};
// target_or_reason_ has a leading SP
cb_[1] = {
f_.target_or_reason_.data(),
f_.target_or_reason_.size()};
buf_[0] = ' ';
buf_[1] = 'H';
buf_[2] = 'T';
buf_[3] = 'T';
buf_[4] = 'P';
buf_[5] = '/';
buf_[6] = '0' + static_cast<char>(version / 10);
buf_[7] = '.';
buf_[8] = '0' + static_cast<char>(version % 10);
buf_[9] = '\r';
buf_[10]= '\n';
cb_[2] = {buf_, 11};
} }
template<class Allocator> template<class Allocator>
@@ -337,16 +267,35 @@ reader(basic_fields const& f,
, chunked_(get_chunked()) , chunked_(get_chunked())
, keep_alive_(get_keep_alive(version)) , keep_alive_(get_keep_alive(version))
{ {
try /*
{ response
prepare(ss_, f, version, code); "HTTP/X.Y ### " (13 chars)
sv_ = ss_; "<reason>"
} "\r\n"
catch(std::length_error const&) */
{ buf_[0] = 'H';
prepare(s_, f, version, code); buf_[1] = 'T';
sv_ = s_; buf_[2] = 'T';
} buf_[3] = 'P';
buf_[4] = '/';
buf_[5] = '0' + static_cast<char>(version / 10);
buf_[6] = '.';
buf_[7] = '0' + static_cast<char>(version % 10);
buf_[8] = ' ';
buf_[9] = '0' + static_cast<char>(code / 100);
buf_[10]= '0' + static_cast<char>((code / 10) % 10);
buf_[11]= '0' + static_cast<char>(code % 10);
buf_[12]= ' ';
cb_[0] = {buf_, 13};
string_view sv;
if(! f_.target_or_reason_.empty())
sv = f_.target_or_reason_;
else
sv = obsolete_reason(static_cast<status>(code));
cb_[1] = {sv.data(), sv.size()};
cb_[2] = detail::chunk_crlf();
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -425,7 +374,8 @@ basic_fields<Allocator>::
{ {
delete_list(); delete_list();
realloc_string(method_, {}); realloc_string(method_, {});
realloc_string(target_or_reason_, {}); realloc_string(
target_or_reason_, {});
} }
template<class Allocator> template<class Allocator>
@@ -828,7 +778,8 @@ void
basic_fields<Allocator>:: basic_fields<Allocator>::
set_target_impl(string_view s) set_target_impl(string_view s)
{ {
realloc_string(target_or_reason_, s); realloc_target(
target_or_reason_, s);
} }
template<class Allocator> template<class Allocator>
@@ -837,7 +788,8 @@ void
basic_fields<Allocator>:: basic_fields<Allocator>::
set_reason_impl(string_view s) set_reason_impl(string_view s)
{ {
realloc_string(target_or_reason_, s); realloc_string(
target_or_reason_, s);
} }
template<class Allocator> template<class Allocator>
@@ -855,7 +807,11 @@ string_view
basic_fields<Allocator>:: basic_fields<Allocator>::
get_target_impl() const get_target_impl() const
{ {
return target_or_reason_; if(target_or_reason_.empty())
return target_or_reason_;
return {
target_or_reason_.data() + 1,
target_or_reason_.size() - 1};
} }
template<class Allocator> template<class Allocator>
@@ -869,7 +825,7 @@ get_reason_impl() const
namespace detail { namespace detail {
// Builds a new string with "chunked" maybe taken off the end // Builds a new string with "chunked" taken off the end if present
template<class String> template<class String>
void void
without_chunked_last(String& s, string_view const& tokens) without_chunked_last(String& s, string_view const& tokens)
@@ -1059,7 +1015,6 @@ void
basic_fields<Allocator>:: basic_fields<Allocator>::
realloc_string(string_view& dest, string_view s) realloc_string(string_view& dest, string_view s)
{ {
s = detail::trim(s);
if(dest.empty() && s.empty()) if(dest.empty() && s.empty())
return; return;
auto a = typename std::allocator_traits< auto a = typename std::allocator_traits<
@@ -1079,6 +1034,35 @@ realloc_string(string_view& dest, string_view s)
} }
} }
template<class Allocator>
void
basic_fields<Allocator>::
realloc_target(
string_view& dest, string_view s)
{
// The target string are stored with an
// extra space at the beginning to help
// the reader class.
if(dest.empty() && s.empty())
return;
auto a = typename std::allocator_traits<
Allocator>::template rebind_alloc<
char>(alloc_);
if(! dest.empty())
{
a.deallocate(const_cast<char*>(
dest.data()), dest.size());
dest.clear();
}
if(! s.empty())
{
auto const p = a.allocate(1 + s.size());
p[0] = ' ';
std::memcpy(p + 1, s.data(), s.size());
dest = {p, 1 + s.size()};
}
}
template<class Allocator> template<class Allocator>
template<class OtherAlloc> template<class OtherAlloc>
void void