/proc/self/cwd/source/common/buffer/buffer_util.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include <charconv> |
4 | | #include <cstddef> |
5 | | |
6 | | #include "envoy/buffer/buffer.h" |
7 | | |
8 | | #include "source/common/common/macros.h" |
9 | | |
10 | | namespace Envoy { |
11 | | namespace Buffer { |
12 | | |
13 | | class Util { |
14 | | public: |
15 | | /** |
16 | | * Serializes double to a buffer with high precision and high performance. |
17 | | * |
18 | | * This helper function is defined on Buffer rather than working with |
19 | | * intermediate string constructs because, depending on the platform, a |
20 | | * different sort of intermediate char buffer is chosen for maximum |
21 | | * performance. It's fastest to then directly append the serialized |
22 | | * char-buffer into the Buffer::Instance, without defining the intermediate |
23 | | * char-buffer as part of the API. |
24 | | * |
25 | | * @param number the number to convert. |
26 | | * @param buffer the buffer in which to write the double. |
27 | | */ |
28 | 0 | template <class Output> static void serializeDouble(double number, Output& buffer) { |
29 | | // Converting a double to a string: who would think it would be so complex? |
30 | | // It's easy if you don't care about speed or accuracy :). Here we are measuring |
31 | | // the speed with test/server/admin/stats_handler_speed_test |
32 | | // --benchmark_filter=BM_HistogramsJson Here are some options: |
33 | | // * absl::StrCat(number) -- fast (19ms on speed test) but loses precision (drops decimals). |
34 | | // * absl::StrFormat("%.15g") -- works great but a bit slow (24ms on speed test) |
35 | | // * `snprintf`(buf, sizeof(buf), "%.15g", ...) -- works but slow as molasses: 30ms. |
36 | | // * fmt::format("{}") -- works great and is a little faster than absl::StrFormat: 21ms. |
37 | | // * fmt::to_string -- works great and is a little faster than fmt::format: 19ms. |
38 | | // * std::to_chars -- fast (16ms) and precise, but requires a few lines to |
39 | | // generate the string_view, and does not work on all platforms yet. |
40 | | // |
41 | | // The accuracy is checked in buffer_util_test. |
42 | 0 | #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 14000 |
43 | | // This version is awkward, and doesn't work on all platforms used in Envoy CI |
44 | | // as of August 2023, but it is the fastest correct option on modern compilers. |
45 | 0 | char buf[100]; |
46 | 0 | std::to_chars_result result = std::to_chars(buf, buf + sizeof(buf), number); |
47 | 0 | ENVOY_BUG(result.ec == std::errc{}, std::make_error_code(result.ec).message()); |
48 | 0 | buffer.add(absl::string_view(buf, result.ptr - buf)); |
49 | | |
50 | | // Note: there is room to speed this up further by serializing the number directly |
51 | | // into the buffer. However, buffer does not currently make it easy and fast |
52 | | // to get (say) 100 characters of raw buffer to serialize into. |
53 | | #else |
54 | | // On older compilers, such as those found on Apple, and gcc, std::to_chars |
55 | | // does not work with 'double', so we revert to the next fastest correct |
56 | | // implementation. |
57 | | buffer.add(fmt::to_string(number)); |
58 | | #endif |
59 | 0 | } |
60 | | }; |
61 | | |
62 | | } // namespace Buffer |
63 | | } // namespace Envoy |