Line data Source code
1 : #include "source/common/buffer/buffer_util.h" 2 : 3 : #include <charconv> 4 : #include <cstddef> 5 : 6 : #include "source/common/common/macros.h" 7 : 8 : namespace Envoy { 9 : namespace Buffer { 10 : 11 0 : void Util::serializeDouble(double number, Buffer::Instance& buffer) { 12 : // Converting a double to a string: who would think it would be so complex? 13 : // It's easy if you don't care about speed or accuracy :). Here we are measuring 14 : // the speed with test/server/admin/stats_handler_speed_test --benchmark_filter=BM_HistogramsJson 15 : // Here are some options: 16 : // * absl::StrCat(number) -- fast (19ms on speed test) but loses precision (drops decimals). 17 : // * absl::StrFormat("%.15g") -- works great but a bit slow (24ms on speed test) 18 : // * `snprintf`(buf, sizeof(buf), "%.15g", ...) -- works but slow as molasses: 30ms. 19 : // * fmt::format("{}") -- works great and is a little faster than absl::StrFormat: 21ms. 20 : // * fmt::to_string -- works great and is a little faster than fmt::format: 19ms. 21 : // * std::to_chars -- fast (16ms) and precise, but requires a few lines to 22 : // generate the string_view, and does not work on all platforms yet. 23 : // 24 : // The accuracy is checked in buffer_util_test. 25 0 : #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 14000 26 : // This version is awkward, and doesn't work on all platforms used in Envoy CI 27 : // as of August 2023, but it is the fastest correct option on modern compilers. 28 0 : char buf[100]; 29 0 : std::to_chars_result result = std::to_chars(buf, buf + sizeof(buf), number); 30 0 : ENVOY_BUG(result.ec == std::errc{}, std::make_error_code(result.ec).message()); 31 0 : buffer.addFragments({absl::string_view(buf, result.ptr - buf)}); 32 : 33 : // Note: there is room to speed this up further by serializing the number directly 34 : // into the buffer. However, buffer does not currently make it easy and fast 35 : // to get (say) 100 characters of raw buffer to serialize into. 36 : #else 37 : // On older compilers, such as those found on Apple, and gcc, std::to_chars 38 : // does not work with 'double', so we revert to the next fastest correct 39 : // implementation. 40 : buffer.addFragments({fmt::to_string(number)}); 41 : #endif 42 0 : } 43 : 44 : } // namespace Buffer 45 : } // namespace Envoy