Coverage Report

Created: 2024-09-19 09:45

/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