diff options
Diffstat (limited to 'boost/beast/http/impl/field.ipp')
-rw-r--r-- | boost/beast/http/impl/field.ipp | 174 |
1 files changed, 82 insertions, 92 deletions
diff --git a/boost/beast/http/impl/field.ipp b/boost/beast/http/impl/field.ipp index b61a0ba8a2..46af6f8552 100644 --- a/boost/beast/http/impl/field.ipp +++ b/boost/beast/http/impl/field.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,11 +10,10 @@ #ifndef BOOST_BEAST_HTTP_IMPL_FIELD_IPP #define BOOST_BEAST_HTTP_IMPL_FIELD_IPP -#include <boost/beast/core/string.hpp> +#include <boost/beast/http/field.hpp> #include <algorithm> #include <array> -#include <unordered_map> -#include <vector> +#include <cstring> #include <boost/assert.hpp> namespace boost { @@ -28,58 +27,66 @@ struct field_table using array_type = std::array<string_view, 353>; - struct hash + // Strings are converted to lowercase + static + std::uint32_t + digest(string_view s) { - std::size_t - operator()(string_view s) const + std::uint32_t r = 0; + std::size_t n = s.size(); + unsigned char const* p =reinterpret_cast< + unsigned char const*>(s.data()); + while(n >= 4) { - auto const n = s.size(); - return - beast::detail::ascii_tolower(s[0]) * - beast::detail::ascii_tolower(s[n/2]) ^ - beast::detail::ascii_tolower(s[n-1]); // hist[] = 331, 10, max_load_factor = 0.15f + std::uint32_t v; + std::memcpy(&v, p, 4); + r = r * 5 + ( v | 0x20202020 ); + p += 4; + n -= 4; } - }; + while( n > 0 ) + { + r = r * 5 + ( *p | 0x20 ); + ++p; + --n; + } + return r; + } - struct iequal + // This comparison is case-insensitive, and the + // strings must contain only valid http field characters. + static + bool + equals(string_view lhs, string_view rhs) { - // assumes inputs have equal length - bool - operator()( - string_view lhs, - string_view rhs) const + using Int = std::uint32_t; // or std::size_t + auto n = lhs.size(); + if(n != rhs.size()) + return false; + auto p1 = lhs.data(); + auto p2 = rhs.data(); + auto constexpr S = sizeof(Int); + auto constexpr Mask = static_cast<Int>( + 0xDFDFDFDFDFDFDFDF & ~Int{0}); + for(; n >= S; p1 += S, p2 += S, n -= S) { - auto p1 = lhs.data(); - auto p2 = rhs.data(); - auto pend = p1 + lhs.size(); - char a, b; - while(p1 < pend) - { - a = *p1++; - b = *p2++; - if(a != b) - goto slow; - } - return true; - - while(p1 < pend) - { - slow: - if( beast::detail::ascii_tolower(a) != - beast::detail::ascii_tolower(b)) - return false; - a = *p1++; - b = *p2++; - } - return true; + Int v1, v2; + std::memcpy( &v1, p1, S ); + std::memcpy( &v2, p2, S ); + if((v1 ^ v2) & Mask) + return false; } - }; - - using map_type = std::unordered_map< - string_view, field, hash, iequal>; + for(; n; ++p1, ++p2, --n) + if(( *p1 ^ *p2) & 0xDF) + return false; + return true; + } array_type by_name_; - std::vector<map_type> by_size_; + + enum { N = 5155 }; + unsigned char map_[ N ][ 2 ] = {}; + /* From: @@ -442,58 +449,43 @@ struct field_table "Xref" }}) { - // find the longest field length - std::size_t high = 0; - for(auto const& s : by_name_) - if(high < s.size()) - high = s.size(); - // build by_size map - // skip field::unknown - by_size_.resize(high + 1); - for(auto& map : by_size_) - map.max_load_factor(.15f); - for(std::size_t i = 1; - i < by_name_.size(); ++i) + for(std::size_t i = 1, n = 256; i < n; ++i) { - auto const& s = by_name_[i]; - by_size_[s.size()].emplace( - s, static_cast<field>(i)); + auto sv = by_name_[ i ]; + auto h = digest(sv); + auto j = h % N; + BOOST_ASSERT(map_[j][0] == 0); + map_[j][0] = static_cast<unsigned char>(i); } -#if 0 - // This snippet calculates the performance - // of the hash function and map settings + for(std::size_t i = 256, n = by_name_.size(); i < n; ++i) { - std::vector<std::size_t> hist; - for(auto const& map : by_size_) - { - for(std::size_t i = 0; i < map.bucket_count(); ++i) - { - auto const n = map.bucket_size(i); - if(n > 0) - { - if(hist.size() < n) - hist.resize(n); - ++hist[n-1]; - } - } - } + auto sv = by_name_[i]; + auto h = digest(sv); + auto j = h % N; + BOOST_ASSERT(map_[j][1] == 0); + map_[j][1] = static_cast<unsigned char>(i - 255); } -#endif } field string_to_field(string_view s) const { - if(s.size() >= by_size_.size()) + auto h = digest(s); + auto j = h % N; + int i = map_[j][0]; + string_view s2 = by_name_[i]; + if(i != 0 && equals(s, s2)) + return static_cast<field>(i); + i = map_[j][1]; + if(i == 0) return field::unknown; - auto const& map = by_size_[s.size()]; - if(map.empty()) - return field::unknown; - auto it = map.find(s); - if(it == map.end()) - return field::unknown; - return it->second; + i += 255; + s2 = by_name_[i]; + + if(equals(s, s2)) + return static_cast<field>(i); + return field::unknown; } // @@ -522,7 +514,7 @@ struct field_table } }; -inline +BOOST_BEAST_DECL field_table const& get_field_table() { @@ -530,7 +522,7 @@ get_field_table() return tab; } -template<class = void> +BOOST_BEAST_DECL string_view to_string(field f) { @@ -541,14 +533,12 @@ to_string(field f) } // detail -inline string_view to_string(field f) { return detail::to_string(f); } -inline field string_to_field(string_view s) { |