diff options
Diffstat (limited to 'src/util.h')
-rw-r--r-- | src/util.h | 230 |
1 files changed, 88 insertions, 142 deletions
@@ -46,6 +46,7 @@ #include <chrono> #include <map> #include <random> +#include <optional> #ifdef HAVE_LIBEV # include <ev.h> @@ -59,20 +60,20 @@ namespace nghttp2 { -constexpr auto NGHTTP2_H2_ALPN = StringRef::from_lit("\x2h2"); -constexpr auto NGHTTP2_H2 = StringRef::from_lit("h2"); +constexpr auto NGHTTP2_H2_ALPN = "\x2h2"_sr; +constexpr auto NGHTTP2_H2 = "h2"_sr; // The additional HTTP/2 protocol ALPN protocol identifier we also // supports for our applications to make smooth migration into final // h2 ALPN ID. -constexpr auto NGHTTP2_H2_16_ALPN = StringRef::from_lit("\x5h2-16"); -constexpr auto NGHTTP2_H2_16 = StringRef::from_lit("h2-16"); +constexpr auto NGHTTP2_H2_16_ALPN = "\x5h2-16"_sr; +constexpr auto NGHTTP2_H2_16 = "h2-16"_sr; -constexpr auto NGHTTP2_H2_14_ALPN = StringRef::from_lit("\x5h2-14"); -constexpr auto NGHTTP2_H2_14 = StringRef::from_lit("h2-14"); +constexpr auto NGHTTP2_H2_14_ALPN = "\x5h2-14"_sr; +constexpr auto NGHTTP2_H2_14 = "h2-14"_sr; -constexpr auto NGHTTP2_H1_1_ALPN = StringRef::from_lit("\x8http/1.1"); -constexpr auto NGHTTP2_H1_1 = StringRef::from_lit("http/1.1"); +constexpr auto NGHTTP2_H1_1_ALPN = "\x8http/1.1"_sr; +constexpr auto NGHTTP2_H1_1 = "http/1.1"_sr; constexpr size_t NGHTTP2_MAX_UINT64_DIGITS = str_size("18446744073709551615"); @@ -185,35 +186,42 @@ OutputIt quote_string(OutputIt it, const StringRef &target) { // NUL byte. size_t quote_stringlen(const StringRef &target); -std::string format_hex(const unsigned char *s, size_t len); +static constexpr char LOWER_XDIGITS[] = "0123456789abcdef"; + +template <std::weakly_incrementable OutputIt> +OutputIt format_hex(OutputIt it, std::span<const uint8_t> s) { + for (auto c : s) { + *it++ = LOWER_XDIGITS[c >> 4]; + *it++ = LOWER_XDIGITS[c & 0xf]; + } -template <size_t N> std::string format_hex(const unsigned char (&s)[N]) { - return format_hex(s, N); + return it; } -template <size_t N> std::string format_hex(const std::array<uint8_t, N> &s) { - return format_hex(s.data(), s.size()); +template <typename T, size_t N = std::dynamic_extent, + std::weakly_incrementable OutputIt> +OutputIt format_hex(OutputIt it, std::span<T, N> s) { + return format_hex(it, std::span<const uint8_t>{as_uint8_span(s)}); } -StringRef format_hex(BlockAllocator &balloc, const StringRef &s); +std::string format_hex(std::span<const uint8_t> s); -static constexpr char LOWER_XDIGITS[] = "0123456789abcdef"; +template <typename T, size_t N = std::dynamic_extent> +std::string format_hex(std::span<T, N> s) { + return format_hex(std::span<const uint8_t>{as_uint8_span(s)}); +} -template <typename OutputIt> -OutputIt format_hex(OutputIt it, const StringRef &s) { - for (auto cc : s) { - uint8_t c = cc; - *it++ = LOWER_XDIGITS[c >> 4]; - *it++ = LOWER_XDIGITS[c & 0xf]; - } +StringRef format_hex(BlockAllocator &balloc, std::span<const uint8_t> s); - return it; +template <typename T, size_t N = std::dynamic_extent> +StringRef format_hex(BlockAllocator &balloc, std::span<T, N> s) { + return format_hex(balloc, std::span<const uint8_t>{as_uint8_span(s)}); } // decode_hex decodes hex string |s|, returns the decoded byte string. // This function assumes |s| is hex string, that is is_hex_string(s) // == true. -StringRef decode_hex(BlockAllocator &balloc, const StringRef &s); +std::span<const uint8_t> decode_hex(BlockAllocator &balloc, const StringRef &s); template <typename OutputIt> OutputIt decode_hex(OutputIt d_first, const StringRef &s) { @@ -289,14 +297,12 @@ inline char lowcase(char c) { template <typename InputIterator1, typename InputIterator2> bool starts_with(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - if (last1 - first1 < last2 - first2) { - return false; - } - return std::equal(first2, last2, first1); + return std::distance(first1, last1) >= std::distance(first2, last2) && + std::equal(first2, last2, first1); } template <typename S, typename T> bool starts_with(const S &a, const T &b) { - return starts_with(a.begin(), a.end(), b.begin(), b.end()); + return starts_with(std::begin(a), std::end(a), std::begin(b), std::end(b)); } struct CaseCmp { @@ -308,107 +314,60 @@ struct CaseCmp { template <typename InputIterator1, typename InputIterator2> bool istarts_with(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - if (last1 - first1 < last2 - first2) { - return false; - } - return std::equal(first2, last2, first1, CaseCmp()); + return std::distance(first1, last1) >= std::distance(first2, last2) && + std::equal(first2, last2, first1, CaseCmp()); } template <typename S, typename T> bool istarts_with(const S &a, const T &b) { - return istarts_with(a.begin(), a.end(), b.begin(), b.end()); -} - -template <typename T, typename CharT, size_t N> -bool istarts_with_l(const T &a, const CharT (&b)[N]) { - return istarts_with(a.begin(), a.end(), b, b + N - 1); + return istarts_with(std::begin(a), std::end(a), std::begin(b), std::end(b)); } template <typename InputIterator1, typename InputIterator2> bool ends_with(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - if (last1 - first1 < last2 - first2) { - return false; - } - return std::equal(first2, last2, last1 - (last2 - first2)); -} + auto len1 = std::distance(first1, last1); + auto len2 = std::distance(first2, last2); -template <typename T, typename S> bool ends_with(const T &a, const S &b) { - return ends_with(a.begin(), a.end(), b.begin(), b.end()); + return len1 >= len2 && std::equal(first2, last2, first1 + (len1 - len2)); } -template <typename T, typename CharT, size_t N> -bool ends_with_l(const T &a, const CharT (&b)[N]) { - return ends_with(a.begin(), a.end(), b, b + N - 1); +template <typename T, typename S> bool ends_with(const T &a, const S &b) { + return ends_with(std::begin(a), std::end(a), std::begin(b), std::end(b)); } template <typename InputIterator1, typename InputIterator2> bool iends_with(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { - if (last1 - first1 < last2 - first2) { - return false; - } - return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp()); -} + auto len1 = std::distance(first1, last1); + auto len2 = std::distance(first2, last2); -template <typename T, typename S> bool iends_with(const T &a, const S &b) { - return iends_with(a.begin(), a.end(), b.begin(), b.end()); + return len1 >= len2 && + std::equal(first2, last2, first1 + (len1 - len2), CaseCmp()); } -template <typename T, typename CharT, size_t N> -bool iends_with_l(const T &a, const CharT (&b)[N]) { - return iends_with(a.begin(), a.end(), b, b + N - 1); +template <typename T, typename S> bool iends_with(const T &a, const S &b) { + return iends_with(std::begin(a), std::end(a), std::begin(b), std::end(b)); } template <typename InputIt1, typename InputIt2> bool strieq(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) { - if (std::distance(first1, last1) != std::distance(first2, last2)) { - return false; - } - - return std::equal(first1, last1, first2, CaseCmp()); + return std::equal(first1, last1, first2, last2, CaseCmp()); } template <typename T, typename S> bool strieq(const T &a, const S &b) { - return strieq(a.begin(), a.end(), b.begin(), b.end()); -} - -template <typename CharT, typename InputIt, size_t N> -bool strieq_l(const CharT (&a)[N], InputIt b, size_t blen) { - return strieq(a, a + (N - 1), b, b + blen); -} - -template <typename CharT, size_t N, typename T> -bool strieq_l(const CharT (&a)[N], const T &b) { - return strieq(a, a + (N - 1), b.begin(), b.end()); -} - -template <typename InputIt1, typename InputIt2> -bool streq(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) { - if (std::distance(first1, last1) != std::distance(first2, last2)) { - return false; - } - return std::equal(first1, last1, first2); -} - -template <typename T, typename S> bool streq(const T &a, const S &b) { - return streq(a.begin(), a.end(), b.begin(), b.end()); + return strieq(std::begin(a), std::end(a), std::begin(b), std::end(b)); } -template <typename CharT, typename InputIt, size_t N> -bool streq_l(const CharT (&a)[N], InputIt b, size_t blen) { - return streq(a, a + (N - 1), b, b + blen); +template <typename T, typename S> +bool strieq(const T &a, const S &b, size_t blen) { + return std::equal(std::begin(a), std::end(a), std::begin(b), + std::next(std::begin(b), blen), CaseCmp()); } -template <typename CharT, size_t N, typename T> -bool streq_l(const CharT (&a)[N], const T &b) { - return streq(a, a + (N - 1), b.begin(), b.end()); -} - -// Returns true if |a| contains |b|. If both |a| and |b| are empty, -// this function returns false. -template <typename S, typename T> bool strifind(const S &a, const T &b) { - return std::search(a.begin(), a.end(), b.begin(), b.end(), CaseCmp()) != - a.end(); +template <typename T, typename S> +bool streq(const T &a, const S &b, size_t blen) { + return std::equal(std::begin(a), std::end(a), std::begin(b), + std::next(std::begin(b), blen)); } template <typename InputIt> void inp_strlower(InputIt first, InputIt last) { @@ -458,10 +417,10 @@ template <typename T, typename OutputIt> OutputIt utos(OutputIt dst, T n) { template <typename T> StringRef make_string_ref_uint(BlockAllocator &balloc, T n) { auto iov = make_byte_ref(balloc, NGHTTP2_MAX_UINT64_DIGITS + 1); - auto p = iov.base; + auto p = std::begin(iov); p = util::utos(p, n); *p = '\0'; - return StringRef{iov.base, p}; + return StringRef{std::span{std::begin(iov), p}}; } template <typename T> std::string utos_unit(T n) { @@ -735,35 +694,22 @@ int get_socket_error(int fd); // Returns true if |host| is IPv6 numeric address (e.g., ::1) bool ipv6_numeric_addr(const char *host); -// Parses NULL terminated string |s| as unsigned integer and returns -// the parsed integer. Additionally, if |s| ends with 'k', 'm', 'g' -// and its upper case characters, multiply the integer by 1024, 1024 * -// 1024 and 1024 * 1024 respectively. If there is an error, returns -// -1. -int64_t parse_uint_with_unit(const char *s); -// The following overload does not require |s| is NULL terminated. -int64_t parse_uint_with_unit(const uint8_t *s, size_t len); -int64_t parse_uint_with_unit(const StringRef &s); - -// Parses NULL terminated string |s| as unsigned integer and returns -// the parsed integer. If there is an error, returns -1. -int64_t parse_uint(const char *s); -// The following overload does not require |s| is NULL terminated. -int64_t parse_uint(const uint8_t *s, size_t len); -int64_t parse_uint(const std::string &s); -int64_t parse_uint(const StringRef &s); - -// Parses NULL terminated string |s| as unsigned integer and returns -// the parsed integer casted to double. If |s| ends with "s", the -// parsed value's unit is a second. If |s| ends with "ms", the unit -// is millisecond. Similarly, it also supports 'm' and 'h' for -// minutes and hours respectively. If none of them are given, the -// unit is second. This function returns -// std::numeric_limits<double>::infinity() if error occurs. -double parse_duration_with_unit(const char *s); -// The following overload does not require |s| is NULL terminated. -double parse_duration_with_unit(const uint8_t *s, size_t len); -double parse_duration_with_unit(const StringRef &s); +// Parses |s| as unsigned integer and returns the parsed integer. +// Additionally, if |s| ends with 'k', 'm', 'g' and its upper case +// characters, multiply the integer by 1024, 1024 * 1024 and 1024 * +// 1024 respectively. If there is an error, returns no value. +std::optional<int64_t> parse_uint_with_unit(const StringRef &s); + +// Parses |s| as unsigned integer and returns the parsed integer.. +std::optional<int64_t> parse_uint(const StringRef &s); + +// Parses |s| as unsigned integer and returns the parsed integer +// casted to double. If |s| ends with "s", the parsed value's unit is +// a second. If |s| ends with "ms", the unit is millisecond. +// Similarly, it also supports 'm' and 'h' for minutes and hours +// respectively. If none of them are given, the unit is second. This +// function returns no value if error occurs. +std::optional<double> parse_duration_with_unit(const StringRef &s); // Returns string representation of time duration |t|. If t has // fractional part (at least more than or equal to 1e-3), |t| is @@ -792,7 +738,7 @@ StringRef make_hostport(BlockAllocator &balloc, const StringRef &host, template <typename OutputIt> StringRef make_hostport(OutputIt first, const StringRef &host, uint16_t port) { - auto ipv6 = ipv6_numeric_addr(host.c_str()); + auto ipv6 = ipv6_numeric_addr(host.data()); auto serv = utos(port); auto p = first; @@ -812,7 +758,7 @@ StringRef make_hostport(OutputIt first, const StringRef &host, uint16_t port) { *p = '\0'; - return StringRef{first, p}; + return StringRef{std::span{first, p}}; } // Creates "host:port" string using given |host| and |port|. If @@ -828,7 +774,7 @@ StringRef make_http_hostport(OutputIt first, const StringRef &host, return make_hostport(first, host, port); } - auto ipv6 = ipv6_numeric_addr(host.c_str()); + auto ipv6 = ipv6_numeric_addr(host.data()); auto p = first; if (ipv6) { @@ -843,7 +789,7 @@ StringRef make_http_hostport(OutputIt first, const StringRef &host, *p = '\0'; - return StringRef{first, p}; + return StringRef{std::span{first, p}}; } // hexdump dumps |data| of length |datalen| in the format similar to @@ -909,13 +855,13 @@ void shuffle(RandomIt first, RandomIt last, Generator &&gen, SwapFun fun) { return; } - for (unsigned int i = 0; i < static_cast<unsigned int>(len - 1); ++i) { - auto dis = std::uniform_int_distribution<unsigned int>(i, len - 1); - auto j = dis(gen); - if (i == j) { - continue; - } - fun(first + i, first + j); + using dist_type = std::uniform_int_distribution<size_t>; + using param_type = dist_type::param_type; + + dist_type d; + + for (decltype(len) i = 0; i < len - 1; ++i) { + fun(first + i, first + d(gen, param_type(i, len - 1))); } } |