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