mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 21:34:46 +02:00
string_param optimizations
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
Version 66:
|
||||
|
||||
* string_param optimizations
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Version 65:
|
||||
|
||||
* Enable narrowing warning on msvc cmake
|
||||
|
@@ -27,17 +27,20 @@ class static_ostream_buffer
|
||||
using traits_type = typename
|
||||
std::basic_streambuf<CharT, Traits>::traits_type;
|
||||
|
||||
char buf_[128];
|
||||
std::string s_;
|
||||
char* data_;
|
||||
std::size_t size_;
|
||||
std::size_t len_ = 0;
|
||||
std::string s_;
|
||||
|
||||
public:
|
||||
static_ostream_buffer(static_ostream_buffer&&) = delete;
|
||||
static_ostream_buffer(static_ostream_buffer const&) = delete;
|
||||
|
||||
static_ostream_buffer()
|
||||
static_ostream_buffer(char* data, std::size_t size)
|
||||
: data_(data)
|
||||
, size_(size)
|
||||
{
|
||||
this->setp(buf_, buf_ + sizeof(buf_) - 1);
|
||||
this->setp(data_, data_ + size - 1);
|
||||
}
|
||||
|
||||
~static_ostream_buffer() noexcept
|
||||
@@ -49,7 +52,7 @@ public:
|
||||
{
|
||||
if(! s_.empty())
|
||||
return {s_.data(), len_};
|
||||
return {buf_, len_};
|
||||
return {data_, len_};
|
||||
}
|
||||
|
||||
int_type
|
||||
@@ -81,17 +84,17 @@ private:
|
||||
{
|
||||
static auto const growth_factor = 1.5;
|
||||
|
||||
if(len_ < sizeof(buf_) - 1)
|
||||
if(len_ < size_ - 1)
|
||||
{
|
||||
this->setp(&buf_[len_],
|
||||
&buf_[sizeof(buf_) - 2]);
|
||||
this->setp(
|
||||
data_ + len_, data_ + size_ - 2);
|
||||
return;
|
||||
}
|
||||
if(s_.empty())
|
||||
{
|
||||
s_.resize(static_cast<std::size_t>(
|
||||
growth_factor * len_));
|
||||
Traits::copy(&s_[0], buf_, len_);
|
||||
Traits::copy(&s_[0], data_, len_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,8 +118,9 @@ class static_ostream : public std::basic_ostream<char>
|
||||
static_ostream_buffer osb_;
|
||||
|
||||
public:
|
||||
static_ostream()
|
||||
static_ostream(char* data, std::size_t size)
|
||||
: std::basic_ostream<char>(&this->osb_)
|
||||
, osb_(data, size)
|
||||
{
|
||||
imbue(std::locale::classic());
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#define BEAST_DETAIL_STATIC_STRING_HPP
|
||||
|
||||
#include <beast/core/string.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -59,13 +60,68 @@ lexicographical_compare(
|
||||
}
|
||||
|
||||
// Maximum number of characters in the decimal
|
||||
// representation of a binary number
|
||||
// representation of a binary number. This includes
|
||||
// the potential minus sign.
|
||||
//
|
||||
inline
|
||||
std::size_t constexpr
|
||||
max_digits(std::size_t bytes)
|
||||
{
|
||||
return static_cast<std::size_t>(
|
||||
bytes * 2.41) + 1;
|
||||
bytes * 2.41) + 1 + 1;
|
||||
}
|
||||
|
||||
template<class CharT, class Integer, class Traits>
|
||||
CharT*
|
||||
raw_to_string(
|
||||
CharT* buf, Integer x, std::true_type)
|
||||
{
|
||||
if(x == 0)
|
||||
{
|
||||
Traits::assign(*--buf, '0');
|
||||
return buf;
|
||||
}
|
||||
if(x < 0)
|
||||
{
|
||||
x = -x;
|
||||
for(;x > 0; x /= 10)
|
||||
Traits::assign(*--buf ,
|
||||
"0123456789"[x % 10]);
|
||||
Traits::assign(*--buf, '-');
|
||||
return buf;
|
||||
}
|
||||
for(;x > 0; x /= 10)
|
||||
Traits::assign(*--buf ,
|
||||
"0123456789"[x % 10]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<class CharT, class Integer, class Traits>
|
||||
CharT*
|
||||
raw_to_string(
|
||||
CharT* buf, Integer x, std::false_type)
|
||||
{
|
||||
if(x == 0)
|
||||
{
|
||||
*--buf = '0';
|
||||
return buf;
|
||||
}
|
||||
for(;x > 0; x /= 10)
|
||||
Traits::assign(*--buf ,
|
||||
"0123456789"[x % 10]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
template<
|
||||
class CharT,
|
||||
class Integer,
|
||||
class Traits = std::char_traits<CharT>>
|
||||
CharT*
|
||||
raw_to_string(CharT* last, std::size_t size, Integer i)
|
||||
{
|
||||
BOOST_ASSERT(size >= max_digits(sizeof(Integer)));
|
||||
return raw_to_string<CharT, Integer, Traits>(
|
||||
last, i, std::is_signed<Integer>{});
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#ifndef BEAST_IMPL_STATIC_STRING_IPP
|
||||
#define BEAST_IMPL_STATIC_STRING_IPP
|
||||
|
||||
#include <beast/core/detail/static_string.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
@@ -534,12 +535,12 @@ assign_char(CharT, std::false_type) ->
|
||||
namespace detail {
|
||||
|
||||
template<class Integer>
|
||||
static_string<1+max_digits(sizeof(Integer))>
|
||||
static_string<max_digits(sizeof(Integer))>
|
||||
to_static_string(Integer x, std::true_type)
|
||||
{
|
||||
if(x == 0)
|
||||
return {'0'};
|
||||
static_string<1 + detail::max_digits(
|
||||
static_string<detail::max_digits(
|
||||
sizeof(Integer))> s;
|
||||
if(x < 0)
|
||||
{
|
||||
@@ -593,10 +594,19 @@ template<class Integer>
|
||||
static_string<detail::max_digits(sizeof(Integer))>
|
||||
to_static_string(Integer x)
|
||||
{
|
||||
using CharT = char;
|
||||
using Traits = std::char_traits<CharT>;
|
||||
BOOST_STATIC_ASSERT(std::is_integral<Integer>::value);
|
||||
return detail::to_static_string(
|
||||
x, std::integral_constant<bool,
|
||||
std::is_signed<Integer>::value>{});
|
||||
char buf[detail::max_digits(sizeof(Integer))];
|
||||
auto last = buf + sizeof(buf);
|
||||
auto it = detail::raw_to_string<
|
||||
CharT, Integer, Traits>(last, sizeof(buf), x);
|
||||
static_string<detail::max_digits(sizeof(Integer))> s;
|
||||
s.resize(static_cast<std::size_t>(last - it));
|
||||
auto p = s.data();
|
||||
while(it < last)
|
||||
Traits::assign(*p++, *it++);
|
||||
return s;
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
104
include/beast/core/impl/string_param.ipp
Normal file
104
include/beast/core/impl/string_param.ipp
Normal file
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_IMPL_STRING_PARAM_IPP
|
||||
#define BEAST_IMPL_STRING_PARAM_IPP
|
||||
|
||||
namespace beast {
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value>::type
|
||||
string_param::
|
||||
print(T const& t)
|
||||
{
|
||||
auto const last = buf_ + sizeof(buf_);
|
||||
auto const it = detail::raw_to_string<
|
||||
char, T, std::char_traits<char>>(
|
||||
last, sizeof(buf_), t);
|
||||
sv_ = {it, static_cast<std::size_t>(
|
||||
last - it)};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_integral<T>::value &&
|
||||
! std::is_convertible<T, string_view>::value
|
||||
>::type
|
||||
string_param::
|
||||
print(T const& t)
|
||||
{
|
||||
os_.emplace(buf_, sizeof(buf_));
|
||||
*os_ << t;
|
||||
os_->flush();
|
||||
sv_ = os_->str();
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
string_param::
|
||||
print(string_view const& sv)
|
||||
{
|
||||
sv_ = sv;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value>::type
|
||||
string_param::
|
||||
print_1(T const& t)
|
||||
{
|
||||
char buf[detail::max_digits(sizeof(T))];
|
||||
auto const last = buf + sizeof(buf);
|
||||
auto const it = detail::raw_to_string<
|
||||
char, T, std::char_traits<char>>(
|
||||
last, sizeof(buf), t);
|
||||
*os_ << string_view{it,
|
||||
static_cast<std::size_t>(last - it)};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_integral<T>::value>::type
|
||||
string_param::
|
||||
print_1(T const& t)
|
||||
{
|
||||
*os_ << t;
|
||||
}
|
||||
|
||||
template<class T0, class... TN>
|
||||
void
|
||||
string_param::
|
||||
print_n(T0 const& t0, TN const&... tn)
|
||||
{
|
||||
print_1(t0);
|
||||
print_n(tn...);
|
||||
}
|
||||
|
||||
template<class T0, class T1, class... TN>
|
||||
void
|
||||
string_param::
|
||||
print(T0 const& t0, T1 const& t1, TN const&... tn)
|
||||
{
|
||||
os_.emplace(buf_, sizeof(buf_));
|
||||
print_1(t0);
|
||||
print_1(t1);
|
||||
print_n(tn...);
|
||||
os_->flush();
|
||||
sv_ = os_->str();
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
string_param::
|
||||
string_param(Args const&... args)
|
||||
{
|
||||
print(args...);
|
||||
}
|
||||
|
||||
} // beast
|
||||
|
||||
#endif
|
@@ -10,8 +10,10 @@
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/string.hpp>
|
||||
#include <beast/core/static_string.hpp>
|
||||
#include <beast/core/detail/static_ostream.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace beast {
|
||||
|
||||
@@ -26,34 +28,47 @@ namespace beast {
|
||||
*/
|
||||
class string_param
|
||||
{
|
||||
template<class T, class = void>
|
||||
struct is_streamable : std::false_type{};
|
||||
|
||||
#if ! BEAST_DOXYGEN
|
||||
template<class T>
|
||||
struct is_streamable<T, detail::void_t<decltype(
|
||||
std::declval<std::ostream&>() << std::declval<T const&>()
|
||||
)>> : std::true_type {};
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
void
|
||||
assign(T const& t, std::true_type)
|
||||
{
|
||||
sv_ = t;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
assign(T const& t, std::false_type)
|
||||
{
|
||||
os_ << t;
|
||||
os_.flush();
|
||||
sv_ = os_.str();
|
||||
}
|
||||
|
||||
detail::static_ostream os_;
|
||||
string_view sv_;
|
||||
char buf_[128];
|
||||
boost::optional<detail::static_ostream> os_;
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value>::type
|
||||
print(T const&);
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_integral<T>::value &&
|
||||
! std::is_convertible<T, string_view>::value
|
||||
>::type
|
||||
print(T const&);
|
||||
|
||||
void
|
||||
print(string_view const&);
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
std::is_integral<T>::value>::type
|
||||
print_1(T const&);
|
||||
|
||||
template<class T>
|
||||
typename std::enable_if<
|
||||
! std::is_integral<T>::value>::type
|
||||
print_1(T const&);
|
||||
|
||||
void
|
||||
print_n()
|
||||
{
|
||||
}
|
||||
|
||||
template<class T0, class... TN>
|
||||
void
|
||||
print_n(T0 const&, TN const&...);
|
||||
|
||||
template<class T0, class T1, class... TN>
|
||||
void
|
||||
print(T0 const&, T1 const&, TN const&...);
|
||||
|
||||
public:
|
||||
/// Copy constructor (disallowed)
|
||||
@@ -64,62 +79,31 @@ public:
|
||||
|
||||
/** Constructor
|
||||
|
||||
This function constructs a string from the specified
|
||||
parameter.
|
||||
|
||||
If @ref string_view is constructible from `T` then
|
||||
the complexity is O(1), and no dynamic allocation
|
||||
takes place.
|
||||
This function constructs a string as if by concatenating
|
||||
the result of streaming each argument in order into an
|
||||
output stream. It is used as a notational convenience
|
||||
at call sites which expect a parameter with the semantics
|
||||
of a @ref string_view.
|
||||
|
||||
Otherwise, the argument is converted to a string
|
||||
as if by a call to `boost::lexical_cast<std::string>(t)`.
|
||||
An attempt is made to store this string in a reasonably
|
||||
sized buffer inside the class, to avoid dynamic allocation.
|
||||
The implementation uses a small, internal static buffer
|
||||
to avoid memory allocations especially for the case where
|
||||
the list of arguments to be converted consists of a single
|
||||
integral type.
|
||||
|
||||
If the argument could not be converted given the space
|
||||
of the class buffer, a final attempt is made to convert
|
||||
the argument to a `std::string`. This attempt may cause
|
||||
a memory allocation.
|
||||
|
||||
@param t The argument to convert to string.
|
||||
|
||||
@note This function participates in overload resolution
|
||||
only if `T` is convertible to @ref string_view, or if
|
||||
`operator<<(std::ostream&, T)` is defined.
|
||||
@param args One or more arguments to convert
|
||||
*/
|
||||
#if BEAST_DOXYGEN
|
||||
template<class T>
|
||||
#else
|
||||
template<class T, class = typename std::enable_if<
|
||||
std::is_convertible<T, string_view>::value ||
|
||||
is_streamable<T>::value
|
||||
>::type>
|
||||
#endif
|
||||
string_param(T const& t);
|
||||
template<class... Args>
|
||||
string_param(Args const&... args);
|
||||
|
||||
/// Conversion to @ref string_view for the converted argument.
|
||||
string_view const
|
||||
str() const
|
||||
{
|
||||
return sv_;
|
||||
}
|
||||
|
||||
/// Conversion to @ref string_view operator
|
||||
/// Implicit conversion to @ref string_view
|
||||
operator string_view const() const
|
||||
{
|
||||
return sv_;
|
||||
}
|
||||
};
|
||||
|
||||
#if ! BEAST_DOXYGEN
|
||||
template<class T, class>
|
||||
string_param::
|
||||
string_param(T const& t)
|
||||
{
|
||||
assign(t, std::is_convertible<T, string_view>{});
|
||||
}
|
||||
#endif
|
||||
|
||||
} // beast
|
||||
|
||||
#include <beast/core/impl/string_param.ipp>
|
||||
|
||||
#endif
|
||||
|
@@ -635,8 +635,8 @@ basic_fields<Allocator>::
|
||||
insert(field name,
|
||||
string_view sname, string_param const& value)
|
||||
{
|
||||
auto& e = new_element(
|
||||
name, sname, value.str());
|
||||
auto& e = new_element(name, sname,
|
||||
static_cast<string_view>(value));
|
||||
auto const before =
|
||||
set_.upper_bound(sname, key_compare{});
|
||||
if(before == set_.begin())
|
||||
@@ -666,8 +666,8 @@ basic_fields<Allocator>::
|
||||
set(field name, string_param const& value)
|
||||
{
|
||||
BOOST_ASSERT(name != field::unknown);
|
||||
set_element(new_element(name,
|
||||
to_string(name), value.str()));
|
||||
set_element(new_element(name, to_string(name),
|
||||
static_cast<string_view>(value)));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@@ -676,8 +676,8 @@ basic_fields<Allocator>::
|
||||
set(string_view sname, string_param const& value)
|
||||
{
|
||||
set_element(new_element(
|
||||
string_to_field(sname),
|
||||
sname, value.str()));
|
||||
string_to_field(sname), sname,
|
||||
static_cast<string_view>(value)));
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
|
@@ -18,12 +18,10 @@ class string_param_test : public unit_test::suite
|
||||
public:
|
||||
struct nop {};
|
||||
|
||||
static_assert(! std::is_constructible<string_param, nop>::value, "");
|
||||
|
||||
void
|
||||
check(string_param const& v, string_view s)
|
||||
{
|
||||
BEAST_EXPECT(v.str() == s);
|
||||
BEAST_EXPECT(static_cast<string_view>(v) == s);
|
||||
}
|
||||
|
||||
class repeater
|
||||
@@ -56,6 +54,8 @@ public:
|
||||
check(123, "123");
|
||||
check(1234, "1234");
|
||||
check(12345, "12345");
|
||||
check({"a", "b"}, "ab");
|
||||
check({1, 2, 3}, "123");
|
||||
}
|
||||
|
||||
void
|
||||
|
Reference in New Issue
Block a user