summaryrefslogtreecommitdiff
path: root/boost/beast/http/impl/field.ipp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast/http/impl/field.ipp')
-rw-r--r--boost/beast/http/impl/field.ipp174
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)
{