diff --git a/CHANGELOG.md b/CHANGELOG.md index e5219f99..de04b991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Version 58: * Specification for http read * Avoid `std::string` in websocket * Fix basic_fields insert ordering +* basic_fields::set optimization API Changes: diff --git a/include/beast/http/fields.hpp b/include/beast/http/fields.hpp index 3a29bf8f..8948692d 100644 --- a/include/beast/http/fields.hpp +++ b/include/beast/http/fields.hpp @@ -115,7 +115,7 @@ public: operator()(value_type const& lhs, value_type const& rhs) const { return ci_less::operator()( - lhs.name(), rhs.name()); + lhs.name_string(), rhs.name_string()); } }; @@ -633,6 +633,9 @@ private: void delete_element(value_type& e); + void + set_element(value_type& e); + void realloc_string(string_view& dest, string_view s); diff --git a/include/beast/http/impl/fields.ipp b/include/beast/http/impl/fields.ipp index bde28110..5d7b3b60 100644 --- a/include/beast/http/impl/fields.ipp +++ b/include/beast/http/impl/fields.ipp @@ -507,8 +507,8 @@ basic_fields:: set(field name, string_param const& value) { BOOST_ASSERT(name != field::unknown); - erase(name); - insert(name, value); + set_element(new_element(name, + to_string(name), value.str())); } template @@ -516,9 +516,9 @@ void basic_fields:: set(string_view sname, string_param const& value) { - auto const name = string_to_field(sname); - erase(sname); - insert(name, sname, value); + set_element(new_element( + string_to_field(sname), + sname, value.str())); } template @@ -774,9 +774,9 @@ set_chunked_impl(bool v) BOOST_ASSERT(v); auto it = find(field::transfer_encoding); if(it == end()) - this->insert(field::transfer_encoding, "chunked"); + insert(field::transfer_encoding, "chunked"); else - this->set(field::transfer_encoding, + set(field::transfer_encoding, it->value().to_string() + ", chunked"); } @@ -816,13 +816,43 @@ void basic_fields:: delete_element(value_type& e) { - auto const n = 1 + - (e.off_ + e.len_ + 2 + - sizeof(value_type) - 1) / sizeof(value_type); + auto const n = 1 + (e.off_ + e.len_ + 2 + + sizeof(value_type) - 1) / sizeof(value_type); alloc_traits::destroy(alloc_, &e); alloc_traits::deallocate(alloc_, &e, n); } +template +void +basic_fields:: +set_element(value_type& e) +{ + auto it = set_.lower_bound( + e.name_string(), key_compare{}); + if(it == set_.end() || ! beast::detail::ci_equal( + e.name_string(), it->name_string())) + { + set_.insert_before(it, e); + list_.push_back(e); + return; + } + for(;;) + { + auto next = it; + ++next; + set_.erase(it); + list_.erase(list_.iterator_to(*it)); + delete_element(*it); + it = next; + if(it == set_.end() || + ! beast::detail::ci_equal( + e.name_string(), it->name_string())) + break; + } + set_.insert_before(it, e); + list_.push_back(e); +} + template void basic_fields::