From c6862892b484132fc81bd0feadbd90e85a36d8e9 Mon Sep 17 00:00:00 2001 From: Ivan Baidakou Date: Tue, 8 Jul 2025 12:49:01 +0300 Subject: [PATCH] Improve decode performance --- include/protopuf/array.h | 10 ++++++---- include/protopuf/byte.h | 5 ----- include/protopuf/coder_mode.h | 6 +++++- include/protopuf/int.h | 12 ++++++++---- include/protopuf/message.h | 10 ++++++---- include/protopuf/skip.h | 24 ++++++++++++++++-------- include/protopuf/varint.h | 18 ++++++++++++------ 7 files changed, 53 insertions(+), 32 deletions(-) diff --git a/include/protopuf/array.h b/include/protopuf/array.h index 25ef22b..b021713 100644 --- a/include/protopuf/array.h +++ b/include/protopuf/array.h @@ -81,11 +81,11 @@ namespace pp { con.reserve(len); } - const auto origin_b = b; decode_value decode_v; - while(begin_diff(b, origin_b) < len) { + while(len) { if (Mode::get_value_from_result(C::template decode(b), decode_v)) { std::tie(*std::inserter(con, con.end()), b) = std::move(decode_v); + --len; } else { return {}; } @@ -122,8 +122,10 @@ namespace pp { uint<8> n = 0; std::tie(n, b) = decode_len; - if (!Mode::check_bytes_span(b, n)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, n)) { + return {}; + } } return Mode::template make_result>(b.subspan(n)); diff --git a/include/protopuf/byte.h b/include/protopuf/byte.h index 856d2d4..6f4b799 100644 --- a/include/protopuf/byte.h +++ b/include/protopuf/byte.h @@ -32,11 +32,6 @@ namespace pp { /// A byte (contiguous) sequence reference (no ownership). using bytes = std::span; - /// Returns the byte-distance between `begin(a)` and `begin(b)`. - inline constexpr std::size_t begin_diff(bytes a, bytes b) { - // `std::to_address` is used here for MSVC, ref to https://github.com/microsoft/STL/issues/1435 - return static_cast(std::to_address(a.begin()) - std::to_address(b.begin())); - } } #endif //PROTOPUF_BYTE_H diff --git a/include/protopuf/coder_mode.h b/include/protopuf/coder_mode.h index f83fbbf..21ddec2 100644 --- a/include/protopuf/coder_mode.h +++ b/include/protopuf/coder_mode.h @@ -73,6 +73,8 @@ namespace pp { template using result_type = std::remove_reference_t; + static constexpr bool need_checks = false; + template static constexpr R make_result(Args&&... args) { return R{std::forward(args)...}; @@ -98,6 +100,8 @@ namespace pp { template using result_type = std::optional>; + static constexpr bool need_checks = true; + template static constexpr R make_result(Args&&... args) { return R{std::in_place, std::forward(args)...}; @@ -124,4 +128,4 @@ namespace pp { } -#endif //PROTOPUF_CODER_MODE_H \ No newline at end of file +#endif //PROTOPUF_CODER_MODE_H diff --git a/include/protopuf/int.h b/include/protopuf/int.h index 3a759e0..f6be255 100644 --- a/include/protopuf/int.h +++ b/include/protopuf/int.h @@ -199,8 +199,10 @@ namespace pp { template static constexpr encode_result encode(T i, bytes b) { - if (!Mode::check_bytes_span(b, N)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, N)) { + return {}; + } } int_to_bytes(i, b.subspan<0, N>()); @@ -209,8 +211,10 @@ namespace pp { template static constexpr decode_result decode(bytes b) { - if (!Mode::check_bytes_span(b, N)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, N)) { + return {}; + } } return Mode::template make_result>(bytes_to_int(b.subspan<0, N>()), b.subspan()); diff --git a/include/protopuf/message.h b/include/protopuf/message.h index 6906cca..cf2c7ca 100644 --- a/include/protopuf/message.h +++ b/include/protopuf/message.h @@ -489,13 +489,13 @@ namespace pp { std::size_t len = 0; std::tie(len, b) = decod_len; - const auto origin_b = b; - while(begin_diff(b, origin_b) < len) { + while(len) { std::pair bytes_with_next; if (!Mode::get_value_from_result(decode_map.decode(v, b), bytes_with_next)) { return {}; } + --len; bool next = true; std::tie(b, next) = bytes_with_next; @@ -528,8 +528,10 @@ namespace pp { uint<8> n = 0; std::tie(n, b) = decode_len; - if (!Mode::check_bytes_span(b, n)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, n)) { + return {}; + } } return Mode::template make_result>(b.subspan(n)); diff --git a/include/protopuf/skip.h b/include/protopuf/skip.h index 3f1f5d5..441b3f3 100644 --- a/include/protopuf/skip.h +++ b/include/protopuf/skip.h @@ -82,8 +82,10 @@ namespace pp { template static constexpr decode_skip_result decode_skip(bytes b) { - if (!Mode::check_bytes_span(b, sizeof(T))) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, sizeof(T))) { + return {}; + } } return Mode::template make_result>(b.subspan()); } @@ -100,8 +102,10 @@ namespace pp { template static constexpr decode_skip_result decode_skip(bytes b) { - if (!Mode::check_bytes_span(b, sizeof(T))) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_bytes_span(b, sizeof(T))) { + return {}; + } } return Mode::template make_result>(b.subspan()); } @@ -127,13 +131,17 @@ namespace pp { auto iter = b.begin(); const auto end = b.end(); - if (!Mode::check_iterator(iter, end)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_iterator(iter, end)) { + return {}; + } } while((*iter++ >> 7) == 1_b) { - if (!Mode::check_iterator(iter, end)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_iterator(iter, end)) { + return {}; + } } } diff --git a/include/protopuf/varint.h b/include/protopuf/varint.h index 3e9d01c..96b6098 100644 --- a/include/protopuf/varint.h +++ b/include/protopuf/varint.h @@ -49,8 +49,10 @@ namespace pp { const auto end = s.end(); do { - if (!Mode::check_iterator(iter, end)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_iterator(iter, end)) { + return {}; + } } *iter = 0b1000'0000_b | std::byte(n); @@ -69,8 +71,10 @@ namespace pp { auto iter = s.begin(); const auto end = s.end(); - if (!Mode::check_iterator(iter, end)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_iterator(iter, end)) { + return {}; + } } std::size_t i = 0; @@ -78,8 +82,10 @@ namespace pp { n |= static_cast(static_cast(*iter & 0b0111'1111_b) << 7*i); ++iter, ++i; - if (!Mode::check_iterator(iter, end)) { - return {}; + if constexpr (Mode::need_checks) { + if (!Mode::check_iterator(iter, end)) { + return {}; + } } } n |= static_cast(static_cast(*iter++) << 7 * i);