forked from boostorg/beast
basic_fields uses intrusive base hooks:
fix #1270 basic_fields::value_type uses base hooks instead of member hooks, otherwise MSVC can sometimes produce undefined behavior when attempting to recover the base class from a data member in certain build configurations.
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
Version 186:
|
||||||
|
|
||||||
|
* basic_fields uses intrusive base hooks
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 185:
|
Version 185:
|
||||||
|
|
||||||
* Remove extraneous function
|
* Remove extraneous function
|
||||||
|
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
* ([issue 1091]) Fix timer on websocket upgrade in examples
|
* ([issue 1091]) Fix timer on websocket upgrade in examples
|
||||||
|
|
||||||
|
* ([issue 1270]) `basic_fields` uses intrusive base hooks
|
||||||
|
|
||||||
* Workaround for http-server-fast and libstdc++
|
* Workaround for http-server-fast and libstdc++
|
||||||
|
|
||||||
|
|
||||||
|
@@ -65,6 +65,8 @@ class basic_fields
|
|||||||
|
|
||||||
static std::size_t constexpr max_static_buffer = 4096;
|
static std::size_t constexpr max_static_buffer = 4096;
|
||||||
|
|
||||||
|
struct element;
|
||||||
|
|
||||||
using off_t = std::uint16_t;
|
using off_t = std::uint16_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -76,24 +78,20 @@ public:
|
|||||||
{
|
{
|
||||||
friend class basic_fields;
|
friend class basic_fields;
|
||||||
|
|
||||||
boost::asio::const_buffer
|
|
||||||
buffer() const;
|
|
||||||
|
|
||||||
value_type(field name,
|
|
||||||
string_view sname, string_view value);
|
|
||||||
|
|
||||||
boost::intrusive::list_member_hook<
|
|
||||||
boost::intrusive::link_mode<
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
list_hook_;
|
|
||||||
boost::intrusive::set_member_hook<
|
|
||||||
boost::intrusive::link_mode<
|
|
||||||
boost::intrusive::normal_link>>
|
|
||||||
set_hook_;
|
|
||||||
off_t off_;
|
off_t off_;
|
||||||
off_t len_;
|
off_t len_;
|
||||||
field f_;
|
field f_;
|
||||||
|
|
||||||
|
char*
|
||||||
|
data() const;
|
||||||
|
|
||||||
|
boost::asio::const_buffer
|
||||||
|
buffer() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
value_type(field name,
|
||||||
|
string_view sname, string_view value);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor (deleted)
|
/// Constructor (deleted)
|
||||||
value_type(value_type const&) = delete;
|
value_type(value_type const&) = delete;
|
||||||
@@ -118,13 +116,16 @@ public:
|
|||||||
|
|
||||||
The case-comparison operation is defined only for low-ASCII characters.
|
The case-comparison operation is defined only for low-ASCII characters.
|
||||||
*/
|
*/
|
||||||
|
#if BOOST_BEAST_DOXYGEN
|
||||||
|
using key_compare = implementation_defined;
|
||||||
|
#else
|
||||||
struct key_compare : beast::iless
|
struct key_compare : beast::iless
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
/// Returns `true` if lhs is less than rhs using a strict ordering
|
/// Returns `true` if lhs is less than rhs using a strict ordering
|
||||||
template<class String>
|
|
||||||
bool
|
bool
|
||||||
operator()(
|
operator()(
|
||||||
String const& lhs,
|
string_view lhs,
|
||||||
value_type const& rhs) const noexcept
|
value_type const& rhs) const noexcept
|
||||||
{
|
{
|
||||||
if(lhs.size() < rhs.name_string().size())
|
if(lhs.size() < rhs.name_string().size())
|
||||||
@@ -135,11 +136,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if lhs is less than rhs using a strict ordering
|
/// Returns `true` if lhs is less than rhs using a strict ordering
|
||||||
template<class String>
|
|
||||||
bool
|
bool
|
||||||
operator()(
|
operator()(
|
||||||
value_type const& lhs,
|
value_type const& lhs,
|
||||||
String const& rhs) const noexcept
|
string_view rhs) const noexcept
|
||||||
{
|
{
|
||||||
if(lhs.name_string().size() < rhs.size())
|
if(lhs.name_string().size() < rhs.size())
|
||||||
return true;
|
return true;
|
||||||
@@ -170,30 +170,36 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using list_t = typename boost::intrusive::make_list<
|
struct element
|
||||||
value_type, boost::intrusive::member_hook<
|
: public boost::intrusive::list_base_hook<
|
||||||
value_type, boost::intrusive::list_member_hook<
|
|
||||||
boost::intrusive::link_mode<
|
boost::intrusive::link_mode<
|
||||||
boost::intrusive::normal_link>>,
|
boost::intrusive::normal_link>>
|
||||||
&value_type::list_hook_>,
|
, public boost::intrusive::set_base_hook<
|
||||||
boost::intrusive::constant_time_size<
|
boost::intrusive::link_mode<
|
||||||
false>>::type;
|
boost::intrusive::normal_link>>
|
||||||
|
, public value_type
|
||||||
|
{
|
||||||
|
element(field name,
|
||||||
|
string_view sname, string_view value);
|
||||||
|
};
|
||||||
|
|
||||||
|
using list_t = typename boost::intrusive::make_list<
|
||||||
|
element,
|
||||||
|
boost::intrusive::constant_time_size<false>
|
||||||
|
>::type;
|
||||||
|
|
||||||
using set_t = typename boost::intrusive::make_multiset<
|
using set_t = typename boost::intrusive::make_multiset<
|
||||||
value_type, boost::intrusive::member_hook<value_type,
|
element,
|
||||||
boost::intrusive::set_member_hook<
|
|
||||||
boost::intrusive::link_mode<
|
|
||||||
boost::intrusive::normal_link>>,
|
|
||||||
&value_type::set_hook_>,
|
|
||||||
boost::intrusive::constant_time_size<true>,
|
boost::intrusive::constant_time_size<true>,
|
||||||
boost::intrusive::compare<key_compare>>::type;
|
boost::intrusive::compare<key_compare>
|
||||||
|
>::type;
|
||||||
|
|
||||||
using align_type = typename
|
using align_type = typename
|
||||||
boost::type_with_alignment<alignof(value_type)>::type;
|
boost::type_with_alignment<alignof(element)>::type;
|
||||||
|
|
||||||
using rebind_type = typename
|
using rebind_type = typename
|
||||||
beast::detail::allocator_traits<Allocator>::
|
beast::detail::allocator_traits<Allocator>::
|
||||||
template rebind_alloc<align_type>;
|
template rebind_alloc<element>;
|
||||||
|
|
||||||
using alloc_traits =
|
using alloc_traits =
|
||||||
beast::detail::allocator_traits<rebind_type>;
|
beast::detail::allocator_traits<rebind_type>;
|
||||||
@@ -704,15 +710,15 @@ private:
|
|||||||
template<class OtherAlloc>
|
template<class OtherAlloc>
|
||||||
friend class basic_fields;
|
friend class basic_fields;
|
||||||
|
|
||||||
value_type&
|
element&
|
||||||
new_element(field name,
|
new_element(field name,
|
||||||
string_view sname, string_view value);
|
string_view sname, string_view value);
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_element(value_type& e);
|
delete_element(element& e);
|
||||||
|
|
||||||
void
|
void
|
||||||
set_element(value_type& e);
|
set_element(element& e);
|
||||||
|
|
||||||
void
|
void
|
||||||
realloc_string(string_view& dest, string_view s);
|
realloc_string(string_view& dest, string_view s);
|
||||||
|
@@ -271,19 +271,38 @@ writer(basic_fields const& f,
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
|
char*
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
value_type::
|
value_type::
|
||||||
value_type(
|
data() const
|
||||||
field name,
|
{
|
||||||
string_view sname,
|
return const_cast<char*>(
|
||||||
string_view value)
|
reinterpret_cast<char const*>(
|
||||||
|
static_cast<element const*>(this) + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
boost::asio::const_buffer
|
||||||
|
basic_fields<Allocator>::
|
||||||
|
value_type::
|
||||||
|
buffer() const
|
||||||
|
{
|
||||||
|
return boost::asio::const_buffer{data(),
|
||||||
|
static_cast<std::size_t>(off_) + len_ + 2};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
basic_fields<Allocator>::
|
||||||
|
value_type::
|
||||||
|
value_type(field name,
|
||||||
|
string_view sname, string_view value)
|
||||||
: off_(static_cast<off_t>(sname.size() + 2))
|
: off_(static_cast<off_t>(sname.size() + 2))
|
||||||
, len_(static_cast<off_t>(value.size()))
|
, len_(static_cast<off_t>(value.size()))
|
||||||
, f_(name)
|
, f_(name)
|
||||||
{
|
{
|
||||||
//BOOST_ASSERT(name == field::unknown ||
|
//BOOST_ASSERT(name == field::unknown ||
|
||||||
// iequals(sname, to_string(name)));
|
// iequals(sname, to_string(name)));
|
||||||
char* p = reinterpret_cast<char*>(this + 1);
|
char* p = data();
|
||||||
p[off_-2] = ':';
|
p[off_-2] = ':';
|
||||||
p[off_-1] = ' ';
|
p[off_-1] = ' ';
|
||||||
p[off_ + len_] = '\r';
|
p[off_ + len_] = '\r';
|
||||||
@@ -293,7 +312,6 @@ value_type(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
|
||||||
field
|
field
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
value_type::
|
value_type::
|
||||||
@@ -303,39 +321,32 @@ name() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
|
||||||
string_view const
|
string_view const
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
value_type::
|
value_type::
|
||||||
name_string() const
|
name_string() const
|
||||||
{
|
{
|
||||||
return {reinterpret_cast<
|
return {data(),
|
||||||
char const*>(this + 1),
|
|
||||||
static_cast<std::size_t>(off_ - 2)};
|
static_cast<std::size_t>(off_ - 2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
|
||||||
string_view const
|
string_view const
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
value_type::
|
value_type::
|
||||||
value() const
|
value() const
|
||||||
{
|
{
|
||||||
return {reinterpret_cast<
|
return {data() + off_,
|
||||||
char const*>(this + 1) + off_,
|
|
||||||
static_cast<std::size_t>(len_)};
|
static_cast<std::size_t>(len_)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
inline
|
|
||||||
boost::asio::const_buffer
|
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
value_type::
|
element::
|
||||||
buffer() const
|
element(field name,
|
||||||
|
string_view sname, string_view value)
|
||||||
|
: value_type(name, sname, value)
|
||||||
{
|
{
|
||||||
return boost::asio::const_buffer{
|
|
||||||
reinterpret_cast<char const*>(this + 1),
|
|
||||||
static_cast<std::size_t>(off_) + len_ + 2};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -614,7 +625,7 @@ erase(const_iterator pos) ->
|
|||||||
auto& e = *next++;
|
auto& e = *next++;
|
||||||
set_.erase(e);
|
set_.erase(e);
|
||||||
list_.erase(pos);
|
list_.erase(pos);
|
||||||
delete_element(const_cast<value_type&>(e));
|
delete_element(const_cast<element&>(e));
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +645,7 @@ erase(string_view name)
|
|||||||
{
|
{
|
||||||
std::size_t n =0;
|
std::size_t n =0;
|
||||||
set_.erase_and_dispose(name, key_compare{},
|
set_.erase_and_dispose(name, key_compare{},
|
||||||
[&](value_type* e)
|
[&](element* e)
|
||||||
{
|
{
|
||||||
++n;
|
++n;
|
||||||
list_.erase(list_.iterator_to(*e));
|
list_.erase(list_.iterator_to(*e));
|
||||||
@@ -1138,7 +1149,7 @@ auto
|
|||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
new_element(field name,
|
new_element(field name,
|
||||||
string_view sname, string_view value) ->
|
string_view sname, string_view value) ->
|
||||||
value_type&
|
element&
|
||||||
{
|
{
|
||||||
if(sname.size() + 2 >
|
if(sname.size() + 2 >
|
||||||
(std::numeric_limits<off_t>::max)())
|
(std::numeric_limits<off_t>::max)())
|
||||||
@@ -1155,33 +1166,29 @@ new_element(field name,
|
|||||||
static_cast<off_t>(value.size());
|
static_cast<off_t>(value.size());
|
||||||
auto a = rebind_type{this->get()};
|
auto a = rebind_type{this->get()};
|
||||||
auto const p = alloc_traits::allocate(a,
|
auto const p = alloc_traits::allocate(a,
|
||||||
(sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) /
|
(sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
|
||||||
sizeof(align_type));
|
sizeof(align_type));
|
||||||
// VFALCO allocator can't call the constructor because its private
|
return *(new(p) element(name, sname, value));
|
||||||
//alloc_traits::construct(a, p, name, sname, value);
|
|
||||||
new(p) value_type{name, sname, value};
|
|
||||||
return *reinterpret_cast<value_type*>(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
delete_element(value_type& e)
|
delete_element(element& e)
|
||||||
{
|
{
|
||||||
auto a = rebind_type{this->get()};
|
auto a = rebind_type{this->get()};
|
||||||
auto const n =
|
auto const n =
|
||||||
(sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
|
(sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
|
||||||
sizeof(align_type);
|
sizeof(align_type);
|
||||||
//alloc_traits::destroy(a, &e);
|
e.~element();
|
||||||
e.~value_type();
|
alloc_traits::deallocate(a, &e, n);
|
||||||
alloc_traits::deallocate(a,
|
//reinterpret_cast<align_type*>(&e), n);
|
||||||
reinterpret_cast<align_type*>(&e), n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Allocator>
|
template<class Allocator>
|
||||||
void
|
void
|
||||||
basic_fields<Allocator>::
|
basic_fields<Allocator>::
|
||||||
set_element(value_type& e)
|
set_element(element& e)
|
||||||
{
|
{
|
||||||
auto it = set_.lower_bound(
|
auto it = set_.lower_bound(
|
||||||
e.name_string(), key_compare{});
|
e.name_string(), key_compare{});
|
||||||
|
Reference in New Issue
Block a user