From 8466975290773f5e0d19a16d2c36c05d64ea5134 Mon Sep 17 00:00:00 2001 From: Purushotham Nayak Date: Mon, 25 Sep 2017 16:53:31 -0400 Subject: [PATCH] Fix compilation error caused due to vector specialization. The codec_traits<> specialization of vector assumes that there is a codec_traits specialization of type T. It dereferences a const_iterator pointing to an element in vector to get a const_reference and then encodes/decodes that element using the codec_traits specialization. This works readily with g++ (gcc) where vector::const_reference is same as bool and we have a codec_traits specialization. However, in the case of c++ (clang) this vector::const_reference != bool. So there will be missing specialization for codec_traits::const_reference>. Adding the above specialization will fix the clang but will create a second definition in case of g++ and violate ODR and hence compilation failure. This change provides a specialization of codec_traits::const_reference> if it doesn't already exist. This should make it work for both c++ and g++. I've also added a test case to cover this, so we can catch it if future changes in implementation breaks it or for testing with other implementations. Fixes AVRO-2081 --- lang/c++/api/AvroTraits.hh | 54 ++++++++++++++++++++++++++++++---- lang/c++/api/Specific.hh | 17 +++++++++-- lang/c++/test/SpecificTests.cc | 10 +++++++ 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/lang/c++/api/AvroTraits.hh b/lang/c++/api/AvroTraits.hh index 41db8371cf4..acf6ff7480f 100644 --- a/lang/c++/api/AvroTraits.hh +++ b/lang/c++/api/AvroTraits.hh @@ -23,13 +23,16 @@ #include "Boost.hh" #include "Types.hh" -/// \file -/// -/// Define an is_serializable trait for types we can serialize natively. -/// New types will need to define the trait as well. - +/** @file + * + * This header contains type traits and similar utilities used by the library. + */ namespace avro { +/** + * Define an is_serializable trait for types we can serialize natively. + * New types will need to define the trait as well. + */ template struct is_serializable : public boost::false_type{}; @@ -41,6 +44,47 @@ struct type_to_avro { static const Type type = AVRO_NUM_TYPES; }; +/** + * Check if a \p T is a complete type i.e. it is defined as opposed to just + * declared. + * + * is_defined::value will be true or false depending on whether T is a + * complete type or not respectively. + */ +template +struct is_defined { + + typedef char yes[1]; + + typedef char no[2]; + + template static yes& test(char(*)[sizeof(U)]) { }; + + template static no& test(...) { }; + + static const bool value = sizeof(test(0)) == sizeof(yes); +}; + +/** + * Similar to is_defined, but used to check if T is not defined. + * + * is_not_defined::value will be true or false depending on whether T is an + * incomplete type or not respectively. + */ +template +struct is_not_defined { + + typedef char yes[1]; + + typedef char no[2]; + + template static yes& test(char(*)[sizeof(U)]) { }; + + template static no& test(...) { }; + + static const bool value = sizeof(test(0)) == sizeof(no); +}; + #define DEFINE_PRIMITIVE(CTYPE, AVROTYPE) \ template <> \ struct is_serializable : public boost::true_type{}; \ diff --git a/lang/c++/api/Specific.hh b/lang/c++/api/Specific.hh index 0a00fb3ccdf..4aaf34802fb 100644 --- a/lang/c++/api/Specific.hh +++ b/lang/c++/api/Specific.hh @@ -27,6 +27,7 @@ #include "boost/array.hpp" #include "boost/blank.hpp" +#include "AvroTraits.hh" #include "Config.hh" #include "Encoder.hh" #include "Decoder.hh" @@ -61,8 +62,7 @@ template void decode(Decoder& d, T& t); * The default is empty. */ template -struct codec_traits { -}; +struct codec_traits; /** * codec_traits for Avro boolean. @@ -253,6 +253,18 @@ template struct codec_traits > { } }; +typedef codec_traits::const_reference> bool_codec_traits; + +template <> struct codec_traits::value, + std::vector::const_reference, void>::type> { + /** + * Encodes a given value. + */ + static void encode(Encoder& e, std::vector::const_reference b) { + e.encodeBool(b); + } +}; + /** * codec_traits for Avro maps. */ @@ -330,6 +342,7 @@ void decode(Decoder& d, T& t) { } } // namespace avro + #endif // avro_Codec_hh__ diff --git a/lang/c++/test/SpecificTests.cc b/lang/c++/test/SpecificTests.cc index aec338ca04a..a9453dccb0a 100644 --- a/lang/c++/test/SpecificTests.cc +++ b/lang/c++/test/SpecificTests.cc @@ -158,6 +158,15 @@ void testArray() BOOST_CHECK_EQUAL_COLLECTIONS(b.begin(), b.end(), n.begin(), n.end()); } +void testBoolArray() +{ + bool values[] = { true, false, true, false }; + vector n(values, values + 4); + vector b = encodeAndDecode(n); + + BOOST_CHECK_EQUAL_COLLECTIONS(b.begin(), b.end(), n.begin(), n.end()); +} + void testMap() { map n; @@ -194,6 +203,7 @@ init_unit_test_suite( int argc, char* argv[] ) ts->add(BOOST_TEST_CASE(avro::specific::testBytes)); ts->add(BOOST_TEST_CASE(avro::specific::testFixed)); ts->add(BOOST_TEST_CASE(avro::specific::testArray)); + ts->add(BOOST_TEST_CASE(avro::specific::testBoolArray)); ts->add(BOOST_TEST_CASE(avro::specific::testMap)); ts->add(BOOST_TEST_CASE(avro::specific::testCustom)); return ts;