forked from boostorg/beast
basic_fields optimizations
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -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&);
|
||||||
|
@@ -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());
|
||||||
}
|
}
|
||||||
@@ -227,106 +220,43 @@ get_keep_alive(int version) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
template<class String>
|
|
||||||
void
|
|
||||||
basic_fields<Allocator>::reader::
|
basic_fields<Allocator>::reader::
|
||||||
prepare(String& s, basic_fields const&,
|
reader(basic_fields const& f,
|
||||||
unsigned version, verb v)
|
unsigned version, verb v)
|
||||||
|
: f_(f)
|
||||||
|
, chunked_(get_chunked())
|
||||||
|
, keep_alive_(get_keep_alive(version))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
request
|
||||||
|
"<method>"
|
||||||
|
" <target>"
|
||||||
|
" HTTP/X.Y\r\n" (11 chars)
|
||||||
|
*/
|
||||||
|
string_view sv;
|
||||||
if(v == verb::unknown)
|
if(v == verb::unknown)
|
||||||
{
|
sv = f_.get_method_impl();
|
||||||
auto const sv =
|
|
||||||
f_.get_method_impl();
|
|
||||||
s.append(sv.data(), sv.size());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
sv = to_string(v);
|
||||||
auto const sv = to_string(v);
|
cb_[0] = {sv.data(), sv.size()};
|
||||||
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>
|
// target_or_reason_ has a leading SP
|
||||||
template<class String>
|
cb_[1] = {
|
||||||
void
|
f_.target_or_reason_.data(),
|
||||||
basic_fields<Allocator>::reader::
|
f_.target_or_reason_.size()};
|
||||||
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>
|
buf_[0] = ' ';
|
||||||
basic_fields<Allocator>::reader::
|
buf_[1] = 'H';
|
||||||
reader(basic_fields const& f,
|
buf_[2] = 'T';
|
||||||
unsigned version, verb v)
|
buf_[3] = 'T';
|
||||||
: f_(f)
|
buf_[4] = 'P';
|
||||||
, chunked_(get_chunked())
|
buf_[5] = '/';
|
||||||
, keep_alive_(get_keep_alive(version))
|
buf_[6] = '0' + static_cast<char>(version / 10);
|
||||||
{
|
buf_[7] = '.';
|
||||||
try
|
buf_[8] = '0' + static_cast<char>(version % 10);
|
||||||
{
|
buf_[9] = '\r';
|
||||||
prepare(ss_, f, version, v);
|
buf_[10]= '\n';
|
||||||
sv_ = ss_;
|
cb_[2] = {buf_, 11};
|
||||||
}
|
|
||||||
catch(std::length_error const&)
|
|
||||||
{
|
|
||||||
prepare(s_, f, version, v);
|
|
||||||
sv_ = s_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
|
if(target_or_reason_.empty())
|
||||||
return target_or_reason_;
|
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
|
||||||
|
Reference in New Issue
Block a user