From cf259284b9cebda9ce8475b0090e46b0f8d3fa9c Mon Sep 17 00:00:00 2001 From: Philippe Verney Date: Wed, 12 Nov 2025 16:14:12 +0100 Subject: [PATCH 1/2] C++ std::optional Specific Encoder and Decoder --- lang/c++/include/avro/Specific.hh | 39 +++++++++++++++++++++++++++++++ lang/c++/test/SpecificTests.cc | 15 ++++++++++++ 2 files changed, 54 insertions(+) diff --git a/lang/c++/include/avro/Specific.hh b/lang/c++/include/avro/Specific.hh index fc28b3f5e4b..cfbc07c9a23 100644 --- a/lang/c++/include/avro/Specific.hh +++ b/lang/c++/include/avro/Specific.hh @@ -22,6 +22,7 @@ #include "array" #include #include +#include #include #include @@ -165,6 +166,44 @@ struct codec_traits { } }; +/** +* codec_traits for Avro optional. +*/ +template +struct codec_traits> { + /** + * Encodes a given value. + */ + static void encode(Encoder &e, const std::optional &b) { + if (b) { + e.encodeUnionIndex(1); + avro::encode(e, b.value()); + } else { + e.encodeUnionIndex(0); + e.encodeNull(); + } + } + + /** + * Decodes into a given value. + */ + static void decode(Decoder &d, std::optional &s) { + size_t n = d.decodeUnionIndex(); + if (n >= 2) { throw avro::Exception("Union index too big"); } + switch (n) { + case 0: { + d.decodeNull(); + s = std::nullopt; + } break; + case 1: { + T t; + avro::decode(d, t); + s.emplace(t); + } break; + } + } +}; + /** * codec_traits for Avro string. */ diff --git a/lang/c++/test/SpecificTests.cc b/lang/c++/test/SpecificTests.cc index 72f2897e45b..91c5ce6d551 100644 --- a/lang/c++/test/SpecificTests.cc +++ b/lang/c++/test/SpecificTests.cc @@ -24,6 +24,7 @@ using std::array; using std::map; +using std::optional; using std::string; using std::unique_ptr; using std::vector; @@ -127,6 +128,18 @@ void testDouble() { BOOST_CHECK_CLOSE(b, n, 0.00000001); } +void testNonEmptyOptional() { + optional n = -109; + optional b = encodeAndDecode(n); + BOOST_CHECK_EQUAL(b.value(), n.value()); +} + +void testEmptyOptional() { + optional n; + optional b = encodeAndDecode(n); + BOOST_CHECK(!b.has_value()); +} + void testString() { string n = "abc"; string b = encodeAndDecode(n); @@ -191,6 +204,8 @@ init_unit_test_suite(int /*argc*/, char * /*argv*/[]) { ts->add(BOOST_TEST_CASE(avro::specific::testLong)); ts->add(BOOST_TEST_CASE(avro::specific::testFloat)); ts->add(BOOST_TEST_CASE(avro::specific::testDouble)); + ts->add(BOOST_TEST_CASE(avro::specific::testNonEmptyOptional)); + ts->add(BOOST_TEST_CASE(avro::specific::testEmptyOptional)); ts->add(BOOST_TEST_CASE(avro::specific::testString)); ts->add(BOOST_TEST_CASE(avro::specific::testBytes)); ts->add(BOOST_TEST_CASE(avro::specific::testFixed)); From e7022101d22c8d32abfaea5d4f3e59478d5fb476 Mon Sep 17 00:00:00 2001 From: Philippe Verney Date: Thu, 13 Nov 2025 10:19:37 +0100 Subject: [PATCH 2/2] In place construction for optional Add missing header. Improve error message. Document expected corresponding schema. Prefere optional.reset() over optional = std::nullopt --- lang/c++/include/avro/Specific.hh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lang/c++/include/avro/Specific.hh b/lang/c++/include/avro/Specific.hh index cfbc07c9a23..edd2c92d867 100644 --- a/lang/c++/include/avro/Specific.hh +++ b/lang/c++/include/avro/Specific.hh @@ -30,6 +30,7 @@ #include "Config.hh" #include "Decoder.hh" #include "Encoder.hh" +#include "Exception.hh" /** * A bunch of templates and specializations for encoding and decoding @@ -167,7 +168,7 @@ struct codec_traits { }; /** -* codec_traits for Avro optional. +* codec_traits for Avro optional assumming that the schema is ["null", T]. */ template struct codec_traits> { @@ -189,16 +190,15 @@ struct codec_traits> { */ static void decode(Decoder &d, std::optional &s) { size_t n = d.decodeUnionIndex(); - if (n >= 2) { throw avro::Exception("Union index too big"); } + if (n >= 2) { throw avro::Exception("Union index too big for optional (expected 0 or 1, got " + std::to_string(n) + ")"); } switch (n) { case 0: { d.decodeNull(); - s = std::nullopt; + s.reset(); } break; case 1: { - T t; - avro::decode(d, t); - s.emplace(t); + s.emplace(); + avro::decode(d, *s); } break; } }