This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/main by this push:
new 49587555f AVRO-3992 [C++] Fix compiler warnings in code generated by
schema with empty record (#2927)
49587555f is described below
commit 49587555fa79214bdee8929ee9cdf1c4d3e183f6
Author: Gerrit Birkeland <[email protected]>
AuthorDate: Tue Jun 25 03:57:38 2024 -0600
AVRO-3992 [C++] Fix compiler warnings in code generated by schema with
empty record (#2927)
* [C++] Fix compiler warnings in code generated by schema with empty record
* [C++] Generate union names for record array-unions
Added to make writing a test for empty unions easier.
* [C++] Fix validatingEncoder for records
---
lang/c++/CMakeLists.txt | 4 +++-
lang/c++/impl/avrogencpp.cc | 22 +++++++++++++++++--
lang/c++/impl/parsing/ValidatingCodec.cc | 1 +
lang/c++/jsonschemas/union_empty_record | 25 +++++++++++++++++++++
lang/c++/test/AvrogencppTests.cc | 37 ++++++++++++++++++++++++++++++--
5 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/lang/c++/CMakeLists.txt b/lang/c++/CMakeLists.txt
index fb7f951e2..62c04ff2f 100644
--- a/lang/c++/CMakeLists.txt
+++ b/lang/c++/CMakeLists.txt
@@ -171,6 +171,7 @@ gen (tweet testgen3)
gen (union_array_union uau)
gen (union_map_union umu)
gen (union_conflict uc)
+gen (union_empty_record uer)
gen (recursive rec)
gen (reuse ru)
gen (circulardep cd)
@@ -213,7 +214,8 @@ add_dependencies (AvrogencppTests bigrecord_hh
bigrecord_r_hh bigrecord2_hh
tweet_hh
union_array_union_hh union_map_union_hh union_conflict_hh
recursive_hh reuse_hh circulardep_hh tree1_hh tree2_hh crossref_hh
- primitivetypes_hh empty_record_hh cpp_reserved_words_union_typedef_hh)
+ primitivetypes_hh empty_record_hh cpp_reserved_words_union_typedef_hh
+ union_empty_record_hh)
include (InstallRequiredSystemLibraries)
diff --git a/lang/c++/impl/avrogencpp.cc b/lang/c++/impl/avrogencpp.cc
index 88912fe42..39da7af35 100644
--- a/lang/c++/impl/avrogencpp.cc
+++ b/lang/c++/impl/avrogencpp.cc
@@ -247,6 +247,10 @@ string CodeGen::generateRecordType(const NodePtr &n) {
<< ' ' << n->nameAt(i) << "_t;\n";
types[i] = n->nameAt(i) + "_t";
}
+ if (n->leafAt(i)->type() == avro::AVRO_ARRAY &&
n->leafAt(i)->leafAt(0)->type() == avro::AVRO_UNION) {
+ os_ << " typedef " << types[i] << "::value_type"
+ << ' ' << n->nameAt(i) << "_item_t;\n";
+ }
}
}
for (size_t i = 0; i < c; ++i) {
@@ -537,8 +541,22 @@ void CodeGen::generateRecordTraits(const NodePtr &n) {
}
string fn = fullname(decorate(n->name()));
- os_ << "template<> struct codec_traits<" << fn << "> {\n"
- << " static void encode(Encoder& e, const " << fn << "& v) {\n";
+ os_ << "template<> struct codec_traits<" << fn << "> {\n";
+
+ if (c == 0) {
+ os_ << " static void encode(Encoder&, const " << fn << "&) {}\n";
+ // ResolvingDecoder::fieldOrder mutates the state of the decoder, so
if that decoder is
+ // passed in, we need to call the method even though it will return an
empty vector.
+ os_ << " static void decode(Decoder& d, " << fn << "&) {\n";
+ os_ << " if (avro::ResolvingDecoder *rd =
dynamic_cast<avro::ResolvingDecoder *>(&d)) {\n";
+ os_ << " rd->fieldOrder();\n";
+ os_ << " }\n";
+ os_ << " }\n";
+ os_ << "};\n";
+ return;
+ }
+
+ os_ << " static void encode(Encoder& e, const " << fn << "& v) {\n";
for (size_t i = 0; i < c; ++i) {
// the nameAt(i) does not take c++ reserved words into account
diff --git a/lang/c++/impl/parsing/ValidatingCodec.cc
b/lang/c++/impl/parsing/ValidatingCodec.cc
index 228c1a509..7a1f8d91b 100644
--- a/lang/c++/impl/parsing/ValidatingCodec.cc
+++ b/lang/c++/impl/parsing/ValidatingCodec.cc
@@ -502,6 +502,7 @@ void ValidatingEncoder<P>::setItemCount(size_t count) {
template<typename P>
void ValidatingEncoder<P>::startItem() {
+ parser_.processImplicitActions();
if (parser_.top() != Symbol::Kind::Repeater) {
throw Exception("startItem at not an item boundary");
}
diff --git a/lang/c++/jsonschemas/union_empty_record
b/lang/c++/jsonschemas/union_empty_record
new file mode 100644
index 000000000..5d2523165
--- /dev/null
+++ b/lang/c++/jsonschemas/union_empty_record
@@ -0,0 +1,25 @@
+{
+ "type": "record",
+ "name": "StackCalculator",
+ "fields": [
+ {
+ "name": "stack",
+ "type": {
+ "type": "array",
+ "items": [
+ "int",
+ {
+ "type": "record",
+ "name": "Dup",
+ "fields": []
+ },
+ {
+ "type": "record",
+ "name": "Add",
+ "fields": []
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/lang/c++/test/AvrogencppTests.cc b/lang/c++/test/AvrogencppTests.cc
index 793fa050b..d393e373d 100644
--- a/lang/c++/test/AvrogencppTests.cc
+++ b/lang/c++/test/AvrogencppTests.cc
@@ -21,6 +21,7 @@
#include "bigrecord_r.hh"
#include "tweet.hh"
#include "union_array_union.hh"
+#include "union_empty_record.hh"
#include "union_map_union.hh"
#include <boost/test/included/unit_test.hpp>
@@ -267,13 +268,45 @@ void testEncoding2() {
check(t2, t1);
}
-boost::unit_test::test_suite *
-init_unit_test_suite(int /*argc*/, char * /*argv*/[]) {
+void testEmptyRecord() {
+ uer::StackCalculator calc;
+ uer::StackCalculator::stack_item_t item;
+ item.set_int(3);
+ calc.stack.push_back(item);
+ item.set_Dup(uer::Dup());
+ calc.stack.push_back(item);
+ item.set_Add(uer::Add());
+ calc.stack.push_back(item);
+
+ ValidSchema s;
+ ifstream ifs("jsonschemas/union_empty_record");
+ compileJsonSchema(ifs, s);
+
+ unique_ptr<OutputStream> os = memoryOutputStream();
+ EncoderPtr e = validatingEncoder(s, binaryEncoder());
+ e->init(*os);
+ avro::encode(*e, calc);
+ e->flush();
+
+ DecoderPtr d = validatingDecoder(s, binaryDecoder());
+ unique_ptr<InputStream> is = memoryInputStream(*os);
+ d->init(*is);
+ uer::StackCalculator calc2;
+ avro::decode(*d, calc2);
+
+ BOOST_CHECK_EQUAL(calc.stack.size(), calc2.stack.size());
+ BOOST_CHECK_EQUAL(calc2.stack[0].idx(), 0);
+ BOOST_CHECK_EQUAL(calc2.stack[1].idx(), 1);
+ BOOST_CHECK_EQUAL(calc2.stack[2].idx(), 2);
+}
+
+boost::unit_test::test_suite *init_unit_test_suite(int /*argc*/, char *
/*argv*/[]) {
auto *ts = BOOST_TEST_SUITE("Code generator tests");
ts->add(BOOST_TEST_CASE(testEncoding));
ts->add(BOOST_TEST_CASE(testResolution));
ts->add(BOOST_TEST_CASE(testEncoding2<uau::r1>));
ts->add(BOOST_TEST_CASE(testEncoding2<umu::r1>));
ts->add(BOOST_TEST_CASE(testNamespace));
+ ts->add(BOOST_TEST_CASE(testEmptyRecord));
return ts;
}