From 357c42d3bdfcb257e6ee7a934ff04c13cd2e1a70 Mon Sep 17 00:00:00 2001 From: Anthony Printup <92564080+anthonyprintup@users.noreply.github.com> Date: Fri, 8 May 2026 03:21:49 +0200 Subject: [PATCH] perf: reduce protocyte benchmark parse gap Generate the Protocyte benchmark target from the shared benchmark schema and add fixtures that populate equivalent Protocyte and protobuf messages. Use staged bulk reads for hosted string and bytes parsing while preserving per-field merge_from atomicity, and avoid map entry copies in generated size and serialize loops. Add cross-library benchmark smoke coverage and malformed length-delimited field regressions. --- smoke/CMakeLists.txt | 68 +++- smoke/generated/compat.protocyte.hpp | 8 +- smoke/generated/example.protocyte.hpp | 24 +- smoke/generated/protocyte/runtime/runtime.hpp | 32 +- smoke/src/benchmark_compat_smoke.cpp | 71 ++++ smoke/src/benchmark_fixture.hpp | 53 +++ smoke/src/host_benchmark.cpp | 31 +- smoke/src/host_smoke.cpp | 30 ++ smoke/src/protobuf_benchmark.cpp | 152 +------- smoke/src/protobuf_benchmark_fixture.hpp | 120 ++++++ smoke/src/protocyte_benchmark_fixture.hpp | 345 ++++++++++++++++++ src/protocyte/cpp.py | 4 +- src/protocyte/runtime/runtime.hpp | 32 +- tests/test_plugin.py | 2 +- 14 files changed, 752 insertions(+), 220 deletions(-) create mode 100644 smoke/src/benchmark_compat_smoke.cpp create mode 100644 smoke/src/benchmark_fixture.hpp create mode 100644 smoke/src/protobuf_benchmark_fixture.hpp create mode 100644 smoke/src/protocyte_benchmark_fixture.hpp diff --git a/smoke/CMakeLists.txt b/smoke/CMakeLists.txt index 144f111..bfe0af4 100644 --- a/smoke/CMakeLists.txt +++ b/smoke/CMakeLists.txt @@ -184,6 +184,17 @@ if(PROTOCYTE_SMOKE_BUILD_BENCHMARKS) FetchContent_MakeAvailable(protobuf) set(PROTOCYTE_PROTOC_EXECUTABLE "$" CACHE INTERNAL "protoc executable for protocyte") endif() + set(PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/protocyte") + set(PROTOCYTE_PROTOCYTE_BENCHMARK_HEADER "${PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR}/benchmark.protocyte.hpp") + set(PROTOCYTE_PROTOCYTE_BENCHMARK_SOURCE "${PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR}/benchmark.protocyte.cpp") + protocyte_generate( + TARGET protocyte_smoke_benchmark_codegen + PROTO_ROOT "${PROTOCYTE_SMOKE_PROTO_DIR}" + OUT_DIR "${PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR}" + PROTOS "${PROTOCYTE_BENCHMARK_PROTO}" + OPTIONS "namespace_prefix=protocyte_smoke" + ) + set(PROTOCYTE_PROTOBUF_BENCHMARK_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated/protobuf") set(PROTOCYTE_PROTOBUF_BENCHMARK_HEADER "${PROTOCYTE_PROTOBUF_BENCHMARK_GENERATED_DIR}/benchmark.pb.h") set(PROTOCYTE_PROTOBUF_BENCHMARK_SOURCE "${PROTOCYTE_PROTOBUF_BENCHMARK_GENERATED_DIR}/benchmark.pb.cc") @@ -253,11 +264,14 @@ endif() if(PROTOCYTE_SMOKE_BUILD_BENCHMARKS) add_executable(protocyte_host_benchmark src/host_benchmark.cpp - "${PROTOCYTE_GENERATED_DIR}/example.protocyte.cpp" - "${PROTOCYTE_GENERATED_DIR}/compat.protocyte.cpp" - "${PROTOCYTE_GENERATED_DIR}/cross_package.protocyte.cpp" + "${PROTOCYTE_PROTOCYTE_BENCHMARK_SOURCE}" + ) + target_include_directories( + protocyte_host_benchmark + PRIVATE + "${PROTOCYTE_GENERATED_DIR}" + "${PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR}" ) - target_include_directories(protocyte_host_benchmark PRIVATE "${PROTOCYTE_GENERATED_DIR}") target_compile_definitions( protocyte_host_benchmark PRIVATE @@ -271,6 +285,7 @@ if(PROTOCYTE_SMOKE_BUILD_BENCHMARKS) if(PROTOCYTE_SMOKE_REGENERATE) add_dependencies(protocyte_host_benchmark protocyte_smoke_regenerate) endif() + add_dependencies(protocyte_host_benchmark protocyte_smoke_benchmark_codegen) if(MSVC) target_compile_options(protocyte_host_benchmark PRIVATE /W4 /permissive-) @@ -313,11 +328,56 @@ if(PROTOCYTE_SMOKE_BUILD_BENCHMARKS) else() target_compile_options(protocyte_host_protobuf_benchmark PRIVATE -Wall -Wextra -Wpedantic) endif() + + add_executable(protocyte_host_benchmark_smoke + src/benchmark_compat_smoke.cpp + "${PROTOCYTE_PROTOCYTE_BENCHMARK_SOURCE}" + "${PROTOCYTE_PROTOBUF_BENCHMARK_SOURCE}" + ) + target_include_directories( + protocyte_host_benchmark_smoke + PRIVATE + "${PROTOCYTE_GENERATED_DIR}" + "${PROTOCYTE_PROTOCYTE_BENCHMARK_GENERATED_DIR}" + "${PROTOCYTE_PROTOBUF_BENCHMARK_GENERATED_DIR}" + ) + target_compile_definitions( + protocyte_host_benchmark_smoke + PRIVATE + PROTOCYTE_ENABLE_HOSTED_ALLOCATOR=1 + PROTOCYTE_ENABLE_STD_STRING_VIEW=1 + ) + protocyte_smoke_enable_std_format_if_available(protocyte_host_benchmark_smoke) + target_compile_features(protocyte_host_benchmark_smoke PRIVATE cxx_std_20) + target_link_libraries( + protocyte_host_benchmark_smoke + PRIVATE + Catch2::Catch2WithMain + "${protocyte_smoke_libprotobuf_target}" + ) + add_dependencies( + protocyte_host_benchmark_smoke + protocyte_smoke_benchmark_codegen + protocyte_smoke_protobuf_benchmark_codegen + ) + + if(PROTOCYTE_SMOKE_REGENERATE) + add_dependencies(protocyte_host_benchmark_smoke protocyte_smoke_regenerate) + endif() + + if(MSVC) + target_compile_options(protocyte_host_benchmark_smoke PRIVATE /W4 /permissive-) + else() + target_compile_options(protocyte_host_benchmark_smoke PRIVATE -Wall -Wextra -Wpedantic) + endif() endif() enable_testing() include(Catch) catch_discover_tests(protocyte_host_smoke) +if(PROTOCYTE_SMOKE_BUILD_BENCHMARKS) + catch_discover_tests(protocyte_host_benchmark_smoke) +endif() if(PROTOCYTE_SMOKE_BUILD_DRIVER) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") diff --git a/smoke/generated/compat.protocyte.hpp b/smoke/generated/compat.protocyte.hpp index 1062d7a..7d7a590 100644 --- a/smoke/generated/compat.protocyte.hpp +++ b/smoke/generated/compat.protocyte.hpp @@ -1680,7 +1680,7 @@ namespace protocyte_smoke::test::compat { return st; } } - for (const auto entry : map_str_int32_) { + for (const auto &entry : map_str_int32_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -1727,7 +1727,7 @@ namespace protocyte_smoke::test::compat { return st; } } - for (const auto entry : map_int32_str_) { + for (const auto &entry : map_int32_str_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -2054,7 +2054,7 @@ namespace protocyte_smoke::test::compat { } total = *st_size; } - for (const auto entry : map_str_int32_) { + for (const auto &entry : map_str_int32_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -2092,7 +2092,7 @@ namespace protocyte_smoke::test::compat { } total = *st_size; } - for (const auto entry : map_int32_str_) { + for (const auto &entry : map_int32_str_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, diff --git a/smoke/generated/example.protocyte.hpp b/smoke/generated/example.protocyte.hpp index 5fcbd4e..049ab8b 100644 --- a/smoke/generated/example.protocyte.hpp +++ b/smoke/generated/example.protocyte.hpp @@ -1347,7 +1347,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : weird_map_) { + for (const auto &entry : weird_map_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -1425,7 +1425,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : weird_map_) { + for (const auto &entry : weird_map_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -4480,7 +4480,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : map_str_int32_) { + for (const auto &entry : map_str_int32_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -4527,7 +4527,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : map_int32_str_) { + for (const auto &entry : map_int32_str_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -4574,7 +4574,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : map_bool_bytes_) { + for (const auto &entry : map_bool_bytes_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -4621,7 +4621,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : map_uint64_msg_) { + for (const auto &entry : map_uint64_msg_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -4668,7 +4668,7 @@ namespace test::ultimate { return st; } } - for (const auto entry : very_nested_map_) { + for (const auto &entry : very_nested_map_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -5196,7 +5196,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : map_str_int32_) { + for (const auto &entry : map_str_int32_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -5234,7 +5234,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : map_int32_str_) { + for (const auto &entry : map_int32_str_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -5272,7 +5272,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : map_bool_bytes_) { + for (const auto &entry : map_bool_bytes_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -5310,7 +5310,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : map_uint64_msg_) { + for (const auto &entry : map_uint64_msg_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, @@ -5348,7 +5348,7 @@ namespace test::ultimate { } total = *st_size; } - for (const auto entry : very_nested_map_) { + for (const auto &entry : very_nested_map_) { enum struct EntryFieldNumber : ::protocyte::u32 { key = 1u, value = 2u, diff --git a/smoke/generated/protocyte/runtime/runtime.hpp b/smoke/generated/protocyte/runtime/runtime.hpp index 3c538e5..0923ec6 100644 --- a/smoke/generated/protocyte/runtime/runtime.hpp +++ b/smoke/generated/protocyte/runtime/runtime.hpp @@ -2924,6 +2924,13 @@ namespace protocyte { return {}; } + Status validate() const noexcept { + if (!validate_utf8(byte_view())) { + return protocyte::unexpected(ErrorCode::invalid_utf8, {}); + } + return {}; + } + protected: Status check_size_limit(const usize size) const noexcept { if (const auto ctx = bytes_.context(); ctx != nullptr && size > ctx->limits.max_string_bytes) { @@ -4202,12 +4209,8 @@ namespace protocyte { return st; } auto buffer = temp.mutable_view(); - for (usize i {}; i < size; ++i) { - auto byte = reader.read_byte(); - if (!byte) { - return byte.status(); - } - buffer.data()[i] = *byte; + if (const auto st = reader.read(buffer.data(), buffer.size()); !st) { + return st; } out = protocyte::move(temp); return {}; @@ -4233,20 +4236,15 @@ namespace protocyte { if (size > ctx.limits.max_string_bytes) { return protocyte::unexpected(ErrorCode::size_limit, reader.position()); } - typename Config::Bytes buffer {&ctx}; - if (const auto st = buffer.resize_for_overwrite(size); !st) { + typename Config::String temp {&ctx}; + if (const auto st = temp.resize_for_overwrite(size); !st) { return st; } - auto bytes = buffer.mutable_view(); - for (usize i {}; i < size; ++i) { - auto byte = reader.read_byte(); - if (!byte) { - return byte.status(); - } - bytes.data()[i] = *byte; + auto bytes = temp.mutable_view_for_overwrite(); + if (const auto st = reader.read(bytes.data(), bytes.size()); !st) { + return st; } - typename Config::String temp {&ctx}; - if (const auto st = temp.assign_owned(protocyte::move(buffer)); !st) { + if (const auto st = temp.validate(); !st) { return st; } out = protocyte::move(temp); diff --git a/smoke/src/benchmark_compat_smoke.cpp b/smoke/src/benchmark_compat_smoke.cpp new file mode 100644 index 0000000..6d0ccd2 --- /dev/null +++ b/smoke/src/benchmark_compat_smoke.cpp @@ -0,0 +1,71 @@ +#include +#include + +#include + +#include "protobuf_benchmark_fixture.hpp" +#include "protocyte_benchmark_fixture.hpp" + +namespace { + + template void require_success(const TStatusLike &status_like) { + if (!status_like) { + const auto error = status_like.error(); + CAPTURE(static_cast(error.code), error.offset, error.field_number); + } + REQUIRE(status_like); + } + + std::vector + serialize_protocyte(const protocyte_smoke::benchmark_fixture::ProtocyteMessage &message) { + const auto size = message.encoded_size(); + require_success(size); + std::vector encoded(*size); + protocyte::SliceWriter writer(encoded.data(), encoded.size()); + require_success(message.serialize(writer)); + REQUIRE(writer.position() == encoded.size()); + return encoded; + } + + template + bool view_equal(const protocyte::Span lhs, const std::string &rhs) { + return lhs.size() == rhs.size() && protocyte::bytes_equal(protocyte::Span {lhs.data(), lhs.size()}, + protocyte::Span {rhs.data(), rhs.size()}); + } + +} // namespace + +TEST_CASE("benchmark schema round trips between Protocyte and protobuf", "[smoke][benchmark][protobuf]") { + namespace fixture = protocyte_smoke::benchmark_fixture; + + auto ctx = fixture::make_context(); + fixture::ProtocyteMessage protocyte_message(ctx); + require_success(fixture::populate_protocyte_message(protocyte_message, ctx)); + + const auto protocyte_encoded = serialize_protocyte(protocyte_message); + fixture::ProtobufMessage protobuf_from_protocyte; + REQUIRE( + protobuf_from_protocyte.ParseFromArray(protocyte_encoded.data(), static_cast(protocyte_encoded.size()))); + CHECK(protobuf_from_protocyte.ByteSizeLong() == protocyte_encoded.size()); + CHECK(protobuf_from_protocyte.f_int32() == 42); + CHECK(protobuf_from_protocyte.oneof_bytes() == fixture::bytes_of(fixture::view_of(fixture::oneof_bytes))); + CHECK(protobuf_from_protocyte.map_str_int32().at(fixture::bytes_of(fixture::view_of(fixture::map_key))) == 301); + + fixture::ProtobufMessage protobuf_message; + fixture::populate_protobuf_message(&protobuf_message); + const auto protobuf_encoded = protobuf_message.SerializeAsString(); + + auto parse_ctx = fixture::make_context(); + fixture::ProtocyteMessage protocyte_from_protobuf(parse_ctx); + protocyte::SliceReader reader(reinterpret_cast(protobuf_encoded.data()), + protobuf_encoded.size()); + require_success(protocyte_from_protobuf.merge_from(reader)); + REQUIRE(reader.eof()); + + const auto protocyte_size = protocyte_from_protobuf.encoded_size(); + require_success(protocyte_size); + CHECK(*protocyte_size == protobuf_message.ByteSizeLong()); + CHECK(protocyte_from_protobuf.f_int32() == 42); + CHECK(view_equal(protocyte_from_protobuf.oneof_bytes(), protobuf_message.oneof_bytes())); + CHECK(protocyte_from_protobuf.map_str_int32().size() == 1u); +} diff --git a/smoke/src/benchmark_fixture.hpp b/smoke/src/benchmark_fixture.hpp new file mode 100644 index 0000000..8878c5a --- /dev/null +++ b/smoke/src/benchmark_fixture.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +#include "protocyte/runtime/runtime.hpp" + +namespace protocyte_smoke::benchmark_fixture { + + constexpr uint8_t string_bytes[] = {'s', 'm', 'o', 'k', 'e'}; + constexpr uint8_t bytes_data[] = {0x00u, 0x01u, 0x7fu, 0x80u, 0xffu}; + constexpr uint8_t nested_name[] = {'n', 'e', 's', 't', 'e', 'd'}; + constexpr uint8_t nested_description[] = {'i', 'n', 'n', 'e', 'r'}; + constexpr uint8_t oneof_bytes[] = {0xdeu, 0xadu, 0xbeu, 0xefu}; + constexpr uint8_t map_key[] = {'m', 'a', 'p', '-', 'k', 'e', 'y'}; + constexpr uint8_t map_value[] = {'m', 'a', 'p', '-', 'v', 'a', 'l'}; + constexpr uint8_t bool_bytes[] = {'b', 'o', 'o', 'l'}; + constexpr uint8_t very_nested_key[] = {'v', 'e', 'r', 'y'}; + constexpr uint8_t recursive_string[] = {'r', 'e', 'c'}; + constexpr uint8_t optional_string[] = {'o', 'p', 't'}; + constexpr uint8_t extreme_value[] = {'e', 'x', 't', 'r', 'e', 'm', 'e'}; + constexpr uint8_t deep_text[] = {'d', 'e', 'e', 'p'}; + constexpr uint8_t weird_value[] = {'w', 'e', 'i', 'r', 'd'}; + constexpr uint8_t byte_array[] = {0xa1u, 0xb2u, 0xc3u, 0xd4u}; + constexpr uint8_t float_expr_array[] = {0x91u, 0x92u}; + constexpr uint8_t repeated_bytes_0[] = {0x11u}; + constexpr uint8_t repeated_bytes_1[] = {0x22u, 0x23u}; + constexpr uint8_t repeated_bytes_2[] = {0x34u, 0x35u, 0x36u, 0x37u}; + constexpr uint8_t repeated_bytes_3[] = {0x48u, 0x49u, 0x4au}; + constexpr uint8_t sha256_bytes[] = { + 0x10u, 0x21u, 0x32u, 0x43u, 0x54u, 0x65u, 0x76u, 0x87u, 0x98u, 0xa9u, 0xbau, 0xcbu, 0xdcu, 0xedu, 0xfeu, 0x0fu, + 0x1eu, 0x2du, 0x3cu, 0x4bu, 0x5au, 0x69u, 0x78u, 0x87u, 0x96u, 0xa5u, 0xb4u, 0xc3u, 0xd2u, 0xe1u, 0xf0u, 0x0fu, + }; + constexpr int32_t integer_array_values[] = {101, 102, 103, 104, 105, 106, 107, 108}; + constexpr uint32_t fixed_integer_array_values[] = {901u, 902u, 903u}; + + inline void *benchmark_allocate(void *, const size_t size, size_t) noexcept { return malloc(size); } + + inline void benchmark_deallocate(void *, void *ptr, size_t, size_t) noexcept { free(ptr); } + + inline protocyte::DefaultConfig::Context make_context() noexcept { + return protocyte::DefaultConfig::Context { + protocyte::Allocator {nullptr, benchmark_allocate, benchmark_deallocate}, + protocyte::Limits {}, + }; + } + + template constexpr protocyte::Span view_of(const uint8_t (&data)[N]) noexcept { + return protocyte::Span {data, N}; + } + +} // namespace protocyte_smoke::benchmark_fixture diff --git a/smoke/src/host_benchmark.cpp b/smoke/src/host_benchmark.cpp index fa70363..ee6b228 100644 --- a/smoke/src/host_benchmark.cpp +++ b/smoke/src/host_benchmark.cpp @@ -3,23 +3,22 @@ #include #include -#include "host_fixture.hpp" +#include "protocyte_benchmark_fixture.hpp" namespace { - using Fixture = protocyte_smoke::fixture::Message; + using Fixture = protocyte_smoke::benchmark_fixture::ProtocyteMessage; - bool make_populated_message(Fixture &message, protocyte_smoke::fixture::Config::Context &ctx, - benchmark::State &state) { - if (const auto st = protocyte_smoke::fixture::populate_message(message, ctx); !st) { - state.SkipWithError("populate_message failed"); + bool make_populated_message(Fixture &message, protocyte::DefaultConfig::Context &ctx, benchmark::State &state) { + if (const auto st = protocyte_smoke::benchmark_fixture::populate_protocyte_message(message, ctx); !st) { + state.SkipWithError("populate_protocyte_message failed"); return false; } return true; } bool make_encoded_message(std::vector &encoded, benchmark::State &state) { - auto ctx = protocyte_smoke::fixture::make_context(); + auto ctx = protocyte_smoke::benchmark_fixture::make_context(); Fixture message(ctx); if (!make_populated_message(message, ctx, state)) { return false; @@ -44,8 +43,8 @@ namespace { return true; } - void BM_UltimateComplexMessage_EncodedSize(benchmark::State &state) { - auto ctx = protocyte_smoke::fixture::make_context(); + void BM_ProtocyteBenchmarkMessage_EncodedSize(benchmark::State &state) { + auto ctx = protocyte_smoke::benchmark_fixture::make_context(); Fixture message(ctx); if (!make_populated_message(message, ctx, state)) { return; @@ -62,8 +61,8 @@ namespace { } } - void BM_UltimateComplexMessage_Serialize(benchmark::State &state) { - auto ctx = protocyte_smoke::fixture::make_context(); + void BM_ProtocyteBenchmarkMessage_Serialize(benchmark::State &state) { + auto ctx = protocyte_smoke::benchmark_fixture::make_context(); Fixture message(ctx); if (!make_populated_message(message, ctx, state)) { return; @@ -88,14 +87,14 @@ namespace { state.SetBytesProcessed(static_cast(state.iterations()) * static_cast(buffer.size())); } - void BM_UltimateComplexMessage_MergeFrom(benchmark::State &state) { + void BM_ProtocyteBenchmarkMessage_MergeFrom(benchmark::State &state) { std::vector encoded; if (!make_encoded_message(encoded, state)) { return; } for (auto _ : state) { - auto ctx = protocyte_smoke::fixture::make_context(); + auto ctx = protocyte_smoke::benchmark_fixture::make_context(); Fixture parsed(ctx); protocyte::SliceReader reader(encoded.data(), encoded.size()); if (const auto st = parsed.merge_from(reader); !st) { @@ -108,8 +107,8 @@ namespace { state.SetBytesProcessed(static_cast(state.iterations()) * static_cast(encoded.size())); } - BENCHMARK(BM_UltimateComplexMessage_EncodedSize); - BENCHMARK(BM_UltimateComplexMessage_Serialize); - BENCHMARK(BM_UltimateComplexMessage_MergeFrom); + BENCHMARK(BM_ProtocyteBenchmarkMessage_EncodedSize); + BENCHMARK(BM_ProtocyteBenchmarkMessage_Serialize); + BENCHMARK(BM_ProtocyteBenchmarkMessage_MergeFrom); } // namespace diff --git a/smoke/src/host_smoke.cpp b/smoke/src/host_smoke.cpp index b83221d..5545f6a 100644 --- a/smoke/src/host_smoke.cpp +++ b/smoke/src/host_smoke.cpp @@ -1718,6 +1718,36 @@ TEST_CASE("merge_from keeps field state after malformed field occurrences", "[sm CHECK(view_equal(parsed.sha256(), view_of(sha256_bytes))); } + SECTION("plain bytes preserve previous contents if read fails after can_read") { + uint8_t encoded[128] = {}; + protocyte::SliceWriter writer(encoded, sizeof(encoded)); + require_success(protocyte::write_tag(writer, static_cast(Message::FieldNumber::f_bytes), + protocyte::WireType::LEN)); + require_success(protocyte::write_varint(writer, sizeof(bytes_data))); + require_success(writer.write(bytes_data, sizeof(bytes_data))); + + Message parsed(ctx); + require_success(parsed.set_f_bytes(view_of(repeated_bytes_2))); + FailingBulkReader reader(encoded, writer.position()); + require_failure(parsed.merge_from(reader), protocyte::ErrorCode::invalid_argument); + CHECK(view_equal(parsed.f_bytes(), view_of(repeated_bytes_2))); + } + + SECTION("plain string preserves previous contents if read fails after can_read") { + uint8_t encoded[128] = {}; + protocyte::SliceWriter writer(encoded, sizeof(encoded)); + require_success(protocyte::write_tag(writer, static_cast(Message::FieldNumber::f_string), + protocyte::WireType::LEN)); + require_success(protocyte::write_varint(writer, sizeof(string_bytes))); + require_success(writer.write(string_bytes, sizeof(string_bytes))); + + Message parsed(ctx); + require_success(parsed.set_f_string(view_of(optional_string))); + FailingBulkReader reader(encoded, writer.position()); + require_failure(parsed.merge_from(reader), protocyte::ErrorCode::invalid_argument); + CHECK(view_equal(parsed.f_string(), view_of(optional_string))); + } + SECTION("bounded bytes preserve previous contents if read fails after can_read") { uint8_t encoded[128] = {}; protocyte::SliceWriter writer(encoded, sizeof(encoded)); diff --git a/smoke/src/protobuf_benchmark.cpp b/smoke/src/protobuf_benchmark.cpp index 3188842..c545676 100644 --- a/smoke/src/protobuf_benchmark.cpp +++ b/smoke/src/protobuf_benchmark.cpp @@ -3,157 +3,15 @@ #include #include -#include "benchmark.pb.h" -#include "host_fixture.hpp" +#include "protobuf_benchmark_fixture.hpp" namespace { - using Message = test::benchmark::BenchmarkMessage; - using Fixture = protocyte_smoke::fixture::Message; - - std::string bytes_of(protocyte::Span view) { - return std::string {reinterpret_cast(view.data()), view.size()}; - } - - void populate_nested2(Message::NestedLevel1::NestedLevel2 *value, protocyte::Span description, - float first, float second, Message::NestedLevel1::NestedLevel2::InnerEnum mode) { - value->set_description(bytes_of(description)); - value->add_values(first); - value->add_values(second); - value->set_mode(mode); - } - - void populate_nested1(Message::NestedLevel1 *value, protocyte::Span name, int32_t id) { - value->set_name(bytes_of(name)); - value->set_id(id); - populate_nested2(value->mutable_inner(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::nested_description), 1.5f, 2.5f, - Message::NestedLevel1::NestedLevel2::B); - } - - void append_bytes(google::protobuf::RepeatedPtrField *values, - protocyte::Span view) { - values->Add(bytes_of(view)); - } - - void populate_fixed_repeated_bytes_holder(Message::FixedRepeatedBytesHolder *value) { - append_bytes(value->mutable_values(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_0)); - append_bytes(value->mutable_values(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_2)); - append_bytes(value->mutable_values(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_3)); - } - - void populate_message(Message *message) { - message->set_f_double(123.5); - message->set_f_float(12.25f); - message->set_f_int32(42); - message->set_f_int64(42000000000ll); - message->set_f_uint32(99u); - message->set_f_uint64(99000000000ull); - message->set_f_sint32(-17); - message->set_f_sint64(-17000000000ll); - message->set_f_fixed32(0x11223344u); - message->set_f_fixed64(0x1122334455667788ull); - message->set_f_sfixed32(-1234567); - message->set_f_sfixed64(-1234567890123ll); - message->set_f_bool(true); - message->set_f_string(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::string_bytes))); - message->set_f_bytes(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::bytes_data))); - message->add_r_int32_unpacked(21); - message->add_r_int32_unpacked(22); - message->add_r_int32_packed(23); - message->add_r_int32_packed(24); - message->add_r_double(23.5); - message->add_r_double(24.5); - message->set_color(Message::GREEN); - - populate_nested1(message->mutable_nested1(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::nested_name), 25); - message->set_oneof_bytes(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::oneof_bytes))); - - (*message->mutable_map_str_int32())[bytes_of( - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::map_key))] = 301; - (*message->mutable_map_int32_str())[302] = - bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::map_value)); - (*message->mutable_map_bool_bytes())[true] = - bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::bool_bytes)); - populate_nested1(&(*message->mutable_map_uint64_msg())[3300u], - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::nested_name), 330); - populate_nested2(&(*message->mutable_very_nested_map())[bytes_of( - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::very_nested_key))], - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::nested_description), 3.5f, 4.5f, - Message::NestedLevel1::NestedLevel2::C); - - auto *recursive = message->mutable_recursive_self(); - recursive->set_f_string( - bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::recursive_string))); - recursive->set_f_int32(350); - recursive->mutable_fixed_integer_array()->Add( - protocyte_smoke::fixture::fixed_integer_array_values, - protocyte_smoke::fixture::fixed_integer_array_values + - (sizeof(protocyte_smoke::fixture::fixed_integer_array_values) / - sizeof(protocyte_smoke::fixture::fixed_integer_array_values[0]))); - append_bytes(recursive->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_0)); - append_bytes(recursive->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_2)); - append_bytes(recursive->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_3)); - - populate_nested2(message->add_lots_of_nested(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::nested_description), 36.5f, 37.5f, - Message::NestedLevel1::NestedLevel2::A); - - message->add_colors(Message::RED); - message->add_colors(Message::BLUE); - message->set_opt_int32(38); - message->set_opt_string(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::optional_string))); - message->set_sha256(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::sha256_bytes))); - message->set_byte_array(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::byte_array))); - message->set_float_expr_array( - bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::float_expr_array))); - append_bytes(message->mutable_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_0)); - append_bytes(message->mutable_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_1)); - append_bytes(message->mutable_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_2)); - append_bytes(message->mutable_bounded_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_1)); - append_bytes(message->mutable_bounded_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_2)); - append_bytes(message->mutable_bounded_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_3)); - append_bytes(message->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_0)); - append_bytes(message->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_2)); - append_bytes(message->mutable_fixed_repeated_byte_array(), - protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::repeated_bytes_3)); - populate_fixed_repeated_bytes_holder(message->mutable_crazy_fixed_repeated_bytes()); - - message->mutable_integer_array()->Add(protocyte_smoke::fixture::integer_array_values, - protocyte_smoke::fixture::integer_array_values + - (sizeof(protocyte_smoke::fixture::integer_array_values) / - sizeof(protocyte_smoke::fixture::integer_array_values[0]))); - message->mutable_fixed_integer_array()->Add( - protocyte_smoke::fixture::fixed_integer_array_values, - protocyte_smoke::fixture::fixed_integer_array_values + - (sizeof(protocyte_smoke::fixture::fixed_integer_array_values) / - sizeof(protocyte_smoke::fixture::fixed_integer_array_values[0]))); - - auto *deep = message->mutable_extreme_nesting(); - deep->set_extreme(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::extreme_value))); - (*deep->mutable_weird_map())[7] = - bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::weird_value)); - deep->set_text(bytes_of(protocyte_smoke::fixture::view_of(protocyte_smoke::fixture::deep_text))); - } + using Message = protocyte_smoke::benchmark_fixture::ProtobufMessage; void BM_ProtobufBenchmarkMessage_ByteSizeLong(benchmark::State &state) { Message message; - populate_message(&message); + protocyte_smoke::benchmark_fixture::populate_protobuf_message(&message); for (auto _ : state) { auto size = message.ByteSizeLong(); @@ -163,7 +21,7 @@ namespace { void BM_ProtobufBenchmarkMessage_Serialize(benchmark::State &state) { Message message; - populate_message(&message); + protocyte_smoke::benchmark_fixture::populate_protobuf_message(&message); std::string encoded; encoded.resize(message.ByteSizeLong()); @@ -180,7 +38,7 @@ namespace { void BM_ProtobufBenchmarkMessage_ParseFromArray(benchmark::State &state) { Message message; - populate_message(&message); + protocyte_smoke::benchmark_fixture::populate_protobuf_message(&message); std::string encoded = message.SerializeAsString(); for (auto _ : state) { diff --git a/smoke/src/protobuf_benchmark_fixture.hpp b/smoke/src/protobuf_benchmark_fixture.hpp new file mode 100644 index 0000000..36767c0 --- /dev/null +++ b/smoke/src/protobuf_benchmark_fixture.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include + +#include "benchmark.pb.h" +#include "benchmark_fixture.hpp" + +namespace protocyte_smoke::benchmark_fixture { + + using ProtobufMessage = ::test::benchmark::BenchmarkMessage; + + inline std::string bytes_of(const protocyte::Span view) { + return std::string {reinterpret_cast(view.data()), view.size()}; + } + + inline void populate_nested2(ProtobufMessage::NestedLevel1::NestedLevel2 *value, + const protocyte::Span description, const float first, + const float second, + const ProtobufMessage::NestedLevel1::NestedLevel2::InnerEnum mode) { + value->set_description(bytes_of(description)); + value->add_values(first); + value->add_values(second); + value->set_mode(mode); + } + + inline void populate_nested1(ProtobufMessage::NestedLevel1 *value, const protocyte::Span name, + const int32_t id) { + value->set_name(bytes_of(name)); + value->set_id(id); + populate_nested2(value->mutable_inner(), view_of(nested_description), 1.5f, 2.5f, + ProtobufMessage::NestedLevel1::NestedLevel2::B); + } + + inline void append_bytes(google::protobuf::RepeatedPtrField *values, + const protocyte::Span view) { + values->Add(bytes_of(view)); + } + + inline void populate_fixed_repeated_bytes_holder(ProtobufMessage::FixedRepeatedBytesHolder *value) { + append_bytes(value->mutable_values(), view_of(repeated_bytes_0)); + append_bytes(value->mutable_values(), view_of(repeated_bytes_2)); + append_bytes(value->mutable_values(), view_of(repeated_bytes_3)); + } + + inline void populate_protobuf_message(ProtobufMessage *message) { + message->set_f_double(123.5); + message->set_f_float(12.25f); + message->set_f_int32(42); + message->set_f_int64(42000000000ll); + message->set_f_uint32(99u); + message->set_f_uint64(99000000000ull); + message->set_f_sint32(-17); + message->set_f_sint64(-17000000000ll); + message->set_f_fixed32(0x11223344u); + message->set_f_fixed64(0x1122334455667788ull); + message->set_f_sfixed32(-1234567); + message->set_f_sfixed64(-1234567890123ll); + message->set_f_bool(true); + message->set_f_string(bytes_of(view_of(string_bytes))); + message->set_f_bytes(bytes_of(view_of(bytes_data))); + message->add_r_int32_unpacked(21); + message->add_r_int32_unpacked(22); + message->add_r_int32_packed(23); + message->add_r_int32_packed(24); + message->add_r_double(23.5); + message->add_r_double(24.5); + message->set_color(ProtobufMessage::GREEN); + + populate_nested1(message->mutable_nested1(), view_of(nested_name), 25); + message->set_oneof_bytes(bytes_of(view_of(oneof_bytes))); + (*message->mutable_map_str_int32())[bytes_of(view_of(map_key))] = 301; + (*message->mutable_map_int32_str())[302] = bytes_of(view_of(map_value)); + (*message->mutable_map_bool_bytes())[true] = bytes_of(view_of(bool_bytes)); + populate_nested1(&(*message->mutable_map_uint64_msg())[3300u], view_of(nested_name), 330); + populate_nested2(&(*message->mutable_very_nested_map())[bytes_of(view_of(very_nested_key))], + view_of(nested_description), 3.5f, 4.5f, ProtobufMessage::NestedLevel1::NestedLevel2::C); + + auto *recursive = message->mutable_recursive_self(); + recursive->set_f_string(bytes_of(view_of(recursive_string))); + recursive->set_f_int32(350); + recursive->mutable_fixed_integer_array()->Add( + fixed_integer_array_values, + fixed_integer_array_values + (sizeof(fixed_integer_array_values) / sizeof(fixed_integer_array_values[0]))); + append_bytes(recursive->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_0)); + append_bytes(recursive->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_2)); + append_bytes(recursive->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_3)); + + populate_nested2(message->add_lots_of_nested(), view_of(nested_description), 36.5f, 37.5f, + ProtobufMessage::NestedLevel1::NestedLevel2::A); + message->add_colors(ProtobufMessage::RED); + message->add_colors(ProtobufMessage::BLUE); + message->set_opt_int32(38); + message->set_opt_string(bytes_of(view_of(optional_string))); + message->set_sha256(bytes_of(view_of(sha256_bytes))); + message->set_byte_array(bytes_of(view_of(byte_array))); + message->set_float_expr_array(bytes_of(view_of(float_expr_array))); + append_bytes(message->mutable_repeated_byte_array(), view_of(repeated_bytes_0)); + append_bytes(message->mutable_repeated_byte_array(), view_of(repeated_bytes_1)); + append_bytes(message->mutable_repeated_byte_array(), view_of(repeated_bytes_2)); + append_bytes(message->mutable_bounded_repeated_byte_array(), view_of(repeated_bytes_1)); + append_bytes(message->mutable_bounded_repeated_byte_array(), view_of(repeated_bytes_2)); + append_bytes(message->mutable_bounded_repeated_byte_array(), view_of(repeated_bytes_3)); + append_bytes(message->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_0)); + append_bytes(message->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_2)); + append_bytes(message->mutable_fixed_repeated_byte_array(), view_of(repeated_bytes_3)); + populate_fixed_repeated_bytes_holder(message->mutable_crazy_fixed_repeated_bytes()); + message->mutable_integer_array()->Add(integer_array_values, + integer_array_values + + (sizeof(integer_array_values) / sizeof(integer_array_values[0]))); + message->mutable_fixed_integer_array()->Add( + fixed_integer_array_values, + fixed_integer_array_values + (sizeof(fixed_integer_array_values) / sizeof(fixed_integer_array_values[0]))); + + auto *deep = message->mutable_extreme_nesting(); + deep->set_extreme(bytes_of(view_of(extreme_value))); + (*deep->mutable_weird_map())[7] = bytes_of(view_of(weird_value)); + deep->set_text(bytes_of(view_of(deep_text))); + } + +} // namespace protocyte_smoke::benchmark_fixture diff --git a/smoke/src/protocyte_benchmark_fixture.hpp b/smoke/src/protocyte_benchmark_fixture.hpp new file mode 100644 index 0000000..2939114 --- /dev/null +++ b/smoke/src/protocyte_benchmark_fixture.hpp @@ -0,0 +1,345 @@ +#pragma once + +#include "benchmark.protocyte.hpp" +#include "benchmark_fixture.hpp" + +namespace protocyte_smoke::benchmark_fixture { + + using ProtocyteMessage = ::protocyte_smoke::test::benchmark::BenchmarkMessage<>; + using ProtocyteNested1 = ::protocyte_smoke::test::benchmark::BenchmarkMessage_NestedLevel1<>; + using ProtocyteNested2 = ::protocyte_smoke::test::benchmark::BenchmarkMessage_NestedLevel1_NestedLevel2<>; + using ProtocyteFixedRepeatedBytesHolder = + ::protocyte_smoke::test::benchmark::BenchmarkMessage_FixedRepeatedBytesHolder<>; + using ProtocyteDeep = ::protocyte_smoke::test::benchmark::BenchmarkMessage_LevelA_LevelB_LevelC_LevelD_LevelE<>; + using ProtocyteColor = ::protocyte_smoke::test::benchmark::BenchmarkMessage_Color; + using ProtocyteInnerMode = ::protocyte_smoke::test::benchmark::BenchmarkMessage_NestedLevel1_NestedLevel2_InnerEnum; + + template protocyte::Status append_bytes(Container &out, protocyte::DefaultConfig::Context &ctx, + protocyte::Span view) noexcept { + protocyte::DefaultConfig::Bytes value(&ctx); + if (const auto st = value.assign(view); !st) { + return st; + } + return out.push_back(protocyte::move(value)); + } + + inline protocyte::Status populate_nested2(ProtocyteNested2 &value, protocyte::Span description, + const float first, const float second, + const ProtocyteInnerMode mode) noexcept { + if (const auto st = value.set_description(description); !st) { + return st; + } + if (const auto st = value.mutable_values().push_back(first); !st) { + return st; + } + if (const auto st = value.mutable_values().push_back(second); !st) { + return st; + } + return value.set_mode(mode); + } + + inline protocyte::Status populate_nested1(ProtocyteNested1 &value, protocyte::Span name, + const int32_t id) noexcept { + if (const auto st = value.set_name(name); !st) { + return st; + } + if (const auto st = value.set_id(id); !st) { + return st; + } + auto inner = value.ensure_inner(); + if (!inner) { + return protocyte::unexpected(inner.error()); + } + return populate_nested2(**inner, view_of(nested_description), 1.5f, 2.5f, ProtocyteInnerMode::B); + } + + inline protocyte::Status populate_fixed_repeated_bytes_holder(ProtocyteFixedRepeatedBytesHolder &value, + protocyte::DefaultConfig::Context &ctx) noexcept { + if (const auto st = append_bytes(value.mutable_values(), ctx, view_of(repeated_bytes_0)); !st) { + return st; + } + if (const auto st = append_bytes(value.mutable_values(), ctx, view_of(repeated_bytes_2)); !st) { + return st; + } + return append_bytes(value.mutable_values(), ctx, view_of(repeated_bytes_3)); + } + + inline protocyte::Status insert_map_str_int32(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + protocyte::DefaultConfig::String key(&ctx); + if (const auto st = key.assign(view_of(map_key)); !st) { + return st; + } + return message.mutable_map_str_int32().insert_or_assign(protocyte::move(key), 301); + } + + inline protocyte::Status insert_map_int32_str(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + protocyte::DefaultConfig::String value(&ctx); + if (const auto st = value.assign(view_of(map_value)); !st) { + return st; + } + return message.mutable_map_int32_str().insert_or_assign(302, protocyte::move(value)); + } + + inline protocyte::Status insert_map_bool_bytes(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + protocyte::DefaultConfig::Bytes value(&ctx); + if (const auto st = value.assign(view_of(bool_bytes)); !st) { + return st; + } + return message.mutable_map_bool_bytes().insert_or_assign(true, protocyte::move(value)); + } + + inline protocyte::Status insert_map_uint64_msg(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + ProtocyteNested1 value(ctx); + if (const auto st = populate_nested1(value, view_of(nested_name), 330); !st) { + return st; + } + return message.mutable_map_uint64_msg().insert_or_assign(3300u, protocyte::move(value)); + } + + inline protocyte::Status insert_very_nested_map(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + protocyte::DefaultConfig::String key(&ctx); + if (const auto st = key.assign(view_of(very_nested_key)); !st) { + return st; + } + ProtocyteNested2 value(ctx); + if (const auto st = populate_nested2(value, view_of(nested_description), 3.5f, 4.5f, ProtocyteInnerMode::C); + !st) { + return st; + } + return message.mutable_very_nested_map().insert_or_assign(protocyte::move(key), protocyte::move(value)); + } + + inline protocyte::Status populate_deep(ProtocyteDeep &value, protocyte::DefaultConfig::Context &ctx) noexcept { + if (const auto st = value.set_extreme(view_of(extreme_value)); !st) { + return st; + } + protocyte::DefaultConfig::String weird(&ctx); + if (const auto st = weird.assign(view_of(weird_value)); !st) { + return st; + } + if (const auto st = value.mutable_weird_map().insert_or_assign(7, protocyte::move(weird)); !st) { + return st; + } + return value.set_text(view_of(deep_text)); + } + + inline protocyte::Status populate_protocyte_message(ProtocyteMessage &message, + protocyte::DefaultConfig::Context &ctx) noexcept { + if (const auto st = message.set_f_double(123.5); !st) { + return st; + } + if (const auto st = message.set_f_float(12.25f); !st) { + return st; + } + if (const auto st = message.set_f_int32(42); !st) { + return st; + } + if (const auto st = message.set_f_int64(42000000000ll); !st) { + return st; + } + if (const auto st = message.set_f_uint32(99u); !st) { + return st; + } + if (const auto st = message.set_f_uint64(99000000000ull); !st) { + return st; + } + if (const auto st = message.set_f_sint32(-17); !st) { + return st; + } + if (const auto st = message.set_f_sint64(-17000000000ll); !st) { + return st; + } + if (const auto st = message.set_f_fixed32(0x11223344u); !st) { + return st; + } + if (const auto st = message.set_f_fixed64(0x1122334455667788ull); !st) { + return st; + } + if (const auto st = message.set_f_sfixed32(-1234567); !st) { + return st; + } + if (const auto st = message.set_f_sfixed64(-1234567890123ll); !st) { + return st; + } + if (const auto st = message.set_f_bool(true); !st) { + return st; + } + if (const auto st = message.set_f_string(view_of(string_bytes)); !st) { + return st; + } + if (const auto st = message.set_f_bytes(view_of(bytes_data)); !st) { + return st; + } + if (const auto st = message.mutable_r_int32_unpacked().push_back(21); !st) { + return st; + } + if (const auto st = message.mutable_r_int32_unpacked().push_back(22); !st) { + return st; + } + if (const auto st = message.mutable_r_int32_packed().push_back(23); !st) { + return st; + } + if (const auto st = message.mutable_r_int32_packed().push_back(24); !st) { + return st; + } + if (const auto st = message.mutable_r_double().push_back(23.5); !st) { + return st; + } + if (const auto st = message.mutable_r_double().push_back(24.5); !st) { + return st; + } + if (const auto st = message.set_color(ProtocyteColor::GREEN); !st) { + return st; + } + + auto nested = message.ensure_nested1(); + if (!nested) { + return protocyte::unexpected(nested.error()); + } + if (const auto st = populate_nested1(**nested, view_of(nested_name), 25); !st) { + return st; + } + if (const auto st = message.set_oneof_bytes(view_of(oneof_bytes)); !st) { + return st; + } + if (const auto st = insert_map_str_int32(message, ctx); !st) { + return st; + } + if (const auto st = insert_map_int32_str(message, ctx); !st) { + return st; + } + if (const auto st = insert_map_bool_bytes(message, ctx); !st) { + return st; + } + if (const auto st = insert_map_uint64_msg(message, ctx); !st) { + return st; + } + if (const auto st = insert_very_nested_map(message, ctx); !st) { + return st; + } + + auto recursive = message.ensure_recursive_self(); + if (!recursive) { + return protocyte::unexpected(recursive.error()); + } + if (const auto st = (*recursive)->set_f_string(view_of(recursive_string)); !st) { + return st; + } + if (const auto st = (*recursive)->set_f_int32(350); !st) { + return st; + } + for (const auto value : fixed_integer_array_values) { + if (const auto st = (*recursive)->mutable_fixed_integer_array().push_back(value); !st) { + return st; + } + } + if (const auto st = + append_bytes((*recursive)->mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_0)); + !st) { + return st; + } + if (const auto st = + append_bytes((*recursive)->mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_2)); + !st) { + return st; + } + if (const auto st = + append_bytes((*recursive)->mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_3)); + !st) { + return st; + } + + auto nested_item = message.mutable_lots_of_nested().emplace_back(ctx); + if (!nested_item) { + return protocyte::unexpected(nested_item.error()); + } + if (const auto st = + populate_nested2(**nested_item, view_of(nested_description), 36.5f, 37.5f, ProtocyteInnerMode::A); + !st) { + return st; + } + if (const auto st = message.mutable_colors().push_back(static_cast(ProtocyteColor::RED)); !st) { + return st; + } + if (const auto st = message.mutable_colors().push_back(static_cast(ProtocyteColor::BLUE)); !st) { + return st; + } + if (const auto st = message.set_opt_int32(38); !st) { + return st; + } + if (const auto st = message.set_opt_string(view_of(optional_string)); !st) { + return st; + } + if (const auto st = message.set_sha256(view_of(sha256_bytes)); !st) { + return st; + } + if (const auto st = message.set_byte_array(view_of(byte_array)); !st) { + return st; + } + if (const auto st = message.set_float_expr_array(view_of(float_expr_array)); !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_repeated_byte_array(), ctx, view_of(repeated_bytes_0)); !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_repeated_byte_array(), ctx, view_of(repeated_bytes_1)); !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_repeated_byte_array(), ctx, view_of(repeated_bytes_2)); !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_bounded_repeated_byte_array(), ctx, view_of(repeated_bytes_1)); + !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_bounded_repeated_byte_array(), ctx, view_of(repeated_bytes_2)); + !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_bounded_repeated_byte_array(), ctx, view_of(repeated_bytes_3)); + !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_0)); + !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_2)); + !st) { + return st; + } + if (const auto st = append_bytes(message.mutable_fixed_repeated_byte_array(), ctx, view_of(repeated_bytes_3)); + !st) { + return st; + } + auto crazy_fixed_repeated = message.ensure_crazy_fixed_repeated_bytes(); + if (!crazy_fixed_repeated) { + return protocyte::unexpected(crazy_fixed_repeated.error()); + } + if (const auto st = populate_fixed_repeated_bytes_holder(**crazy_fixed_repeated, ctx); !st) { + return st; + } + for (const auto value : integer_array_values) { + if (const auto st = message.mutable_integer_array().push_back(value); !st) { + return st; + } + } + for (const auto value : fixed_integer_array_values) { + if (const auto st = message.mutable_fixed_integer_array().push_back(value); !st) { + return st; + } + } + + auto deep = message.ensure_extreme_nesting(); + if (!deep) { + return protocyte::unexpected(deep.error()); + } + return populate_deep(**deep, ctx); + } + +} // namespace protocyte_smoke::benchmark_fixture diff --git a/src/protocyte/cpp.py b/src/protocyte/cpp.py index c5996e0..baee7cd 100644 --- a/src/protocyte/cpp.py +++ b/src/protocyte/cpp.py @@ -1438,7 +1438,7 @@ def _emit_write_field( def _emit_write_map(w: CppWriter, item: FieldModel, options: GeneratorOptions) -> None: assert item.map_key is not None and item.map_value is not None - w.line(f"for (const auto entry : {_member(item)}) {{") + w.line(f"for (const auto &entry : {_member(item)}) {{") with w.indent(), w.cpp_scope(): w.line("enum struct EntryFieldNumber : ::protocyte::u32 {") with w.indent(): @@ -1560,7 +1560,7 @@ def _emit_size_statement(w: CppWriter, item: FieldModel, options: GeneratorOptio def _emit_size_map(w: CppWriter, item: FieldModel, options: GeneratorOptions) -> None: assert item.map_key is not None and item.map_value is not None - w.line(f"for (const auto entry : {_member(item)}) {{") + w.line(f"for (const auto &entry : {_member(item)}) {{") with w.indent(), w.cpp_scope(): w.line("enum struct EntryFieldNumber : ::protocyte::u32 {") with w.indent(): diff --git a/src/protocyte/runtime/runtime.hpp b/src/protocyte/runtime/runtime.hpp index 3c538e5..0923ec6 100644 --- a/src/protocyte/runtime/runtime.hpp +++ b/src/protocyte/runtime/runtime.hpp @@ -2924,6 +2924,13 @@ namespace protocyte { return {}; } + Status validate() const noexcept { + if (!validate_utf8(byte_view())) { + return protocyte::unexpected(ErrorCode::invalid_utf8, {}); + } + return {}; + } + protected: Status check_size_limit(const usize size) const noexcept { if (const auto ctx = bytes_.context(); ctx != nullptr && size > ctx->limits.max_string_bytes) { @@ -4202,12 +4209,8 @@ namespace protocyte { return st; } auto buffer = temp.mutable_view(); - for (usize i {}; i < size; ++i) { - auto byte = reader.read_byte(); - if (!byte) { - return byte.status(); - } - buffer.data()[i] = *byte; + if (const auto st = reader.read(buffer.data(), buffer.size()); !st) { + return st; } out = protocyte::move(temp); return {}; @@ -4233,20 +4236,15 @@ namespace protocyte { if (size > ctx.limits.max_string_bytes) { return protocyte::unexpected(ErrorCode::size_limit, reader.position()); } - typename Config::Bytes buffer {&ctx}; - if (const auto st = buffer.resize_for_overwrite(size); !st) { + typename Config::String temp {&ctx}; + if (const auto st = temp.resize_for_overwrite(size); !st) { return st; } - auto bytes = buffer.mutable_view(); - for (usize i {}; i < size; ++i) { - auto byte = reader.read_byte(); - if (!byte) { - return byte.status(); - } - bytes.data()[i] = *byte; + auto bytes = temp.mutable_view_for_overwrite(); + if (const auto st = reader.read(bytes.data(), bytes.size()); !st) { + return st; } - typename Config::String temp {&ctx}; - if (const auto st = temp.assign_owned(protocyte::move(buffer)); !st) { + if (const auto st = temp.validate(); !st) { return st; } out = protocyte::move(temp); diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 503320f..3cc56c8 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -794,7 +794,7 @@ def test_checked_smoke_output_reflects_copy_propagation() -> None: " {" not in cross_header ) - weird_map_serialize = header.split("for (const auto entry : weird_map_) {", maxsplit=1)[1].split( + weird_map_serialize = header.split("for (const auto &entry : weird_map_) {", maxsplit=1)[1].split( "if (deep_oneof_case_", maxsplit=1 )[0] assert weird_map_serialize.count(" {\n const auto st_size =") == 2