[ 
https://issues.apache.org/jira/browse/AVRO-1635?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16635887#comment-16635887
 ] 

ASF GitHub Bot commented on AVRO-1635:
--------------------------------------

thiru-apache closed pull request #301: AVRO-1635 C++ schema aware encoders 
throw tr1::bad_weak_ptr exception for recursive schema
URL: https://github.com/apache/avro/pull/301
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/lang/c++/impl/parsing/JsonCodec.cc 
b/lang/c++/impl/parsing/JsonCodec.cc
index ead44cab5..a7663a9e0 100644
--- a/lang/c++/impl/parsing/JsonCodec.cc
+++ b/lang/c++/impl/parsing/JsonCodec.cc
@@ -106,7 +106,7 @@ ProductionPtr JsonGrammarGenerator::doGenerate(const 
NodePtr& n,
             reverse(result->begin(), result->end());
 
             m[n] = result;
-            return result;
+            return make_shared<Production>(1, Symbol::indirect(result));
         }
     case AVRO_ENUM:
         {
@@ -363,6 +363,7 @@ template <typename P>
 size_t JsonDecoder<P>::arrayStart()
 {
     parser_.advance(Symbol::sArrayStart);
+    parser_.pushRepeatCount(0);
     expect(JsonParser::tkArrayStart);
     return arrayNext();
 }
@@ -377,7 +378,7 @@ size_t JsonDecoder<P>::arrayNext()
         parser_.advance(Symbol::sArrayEnd);
         return 0;
     }
-    parser_.setRepeatCount(1);
+    parser_.nextRepeatCount(1);
     return 1;
 }
 
@@ -419,6 +420,7 @@ template <typename P>
 size_t JsonDecoder<P>::mapStart()
 {
     parser_.advance(Symbol::sMapStart);
+    parser_.pushRepeatCount(0);
     expect(JsonParser::tkObjectStart);
     return mapNext();
 }
@@ -433,7 +435,7 @@ size_t JsonDecoder<P>::mapNext()
         parser_.advance(Symbol::sMapEnd);
         return 0;
     }
-    parser_.setRepeatCount(1);
+    parser_.nextRepeatCount(1);
     return 1;
 }
 
@@ -624,6 +626,7 @@ template<typename P, typename F>
 void JsonEncoder<P, F>::arrayStart()
 {
     parser_.advance(Symbol::sArrayStart);
+    parser_.pushRepeatCount(0);
     out_.arrayStart();
 }
 
@@ -639,6 +642,7 @@ template<typename P, typename F>
 void JsonEncoder<P, F>::mapStart()
 {
     parser_.advance(Symbol::sMapStart);
+    parser_.pushRepeatCount(0);
     out_.objectStart();
 }
 
@@ -653,7 +657,7 @@ void JsonEncoder<P, F>::mapEnd()
 template<typename P, typename F>
 void JsonEncoder<P, F>::setItemCount(size_t count)
 {
-    parser_.setRepeatCount(count);
+    parser_.nextRepeatCount(count);
 }
 
 template<typename P, typename F>
diff --git a/lang/c++/impl/parsing/ResolvingDecoder.cc 
b/lang/c++/impl/parsing/ResolvingDecoder.cc
index e0d25edfd..08518d93e 100644
--- a/lang/c++/impl/parsing/ResolvingDecoder.cc
+++ b/lang/c++/impl/parsing/ResolvingDecoder.cc
@@ -327,7 +327,7 @@ ProductionPtr ResolvingGrammarGenerator::doGenerate2(
                 m[key] = ProductionPtr();
                 ProductionPtr result = resolveRecords(writer, reader, m, m2);
                 m[key] = result;
-                return result;
+               return make_shared<Production>(1, Symbol::indirect(result));
             }
             break;
 
@@ -636,11 +636,10 @@ size_t ResolvingDecoderImpl<P>::arrayStart()
 {
     parser_.advance(Symbol::sArrayStart);
     size_t result = base_->arrayStart();
+    parser_.pushRepeatCount(result);
     if (result == 0) {
         parser_.popRepeater();
         parser_.advance(Symbol::sArrayEnd);
-    } else {
-        parser_.setRepeatCount(result);
     }
     return result;
 }
@@ -650,11 +649,10 @@ size_t ResolvingDecoderImpl<P>::arrayNext()
 {
     parser_.processImplicitActions();
     size_t result = base_->arrayNext();
+    parser_.nextRepeatCount(result);
     if (result == 0) {
         parser_.popRepeater();
         parser_.advance(Symbol::sArrayEnd);
-    } else {
-        parser_.setRepeatCount(result);
     }
     return result;
 }
@@ -667,7 +665,7 @@ size_t ResolvingDecoderImpl<P>::skipArray()
     if (n == 0) {
         parser_.pop();
     } else {
-        parser_.setRepeatCount(n);
+        parser_.pushRepeatCount(n);
         parser_.skip(*base_);
     }
     parser_.advance(Symbol::sArrayEnd);
@@ -679,11 +677,10 @@ size_t ResolvingDecoderImpl<P>::mapStart()
 {
     parser_.advance(Symbol::sMapStart);
     size_t result = base_->mapStart();
+    parser_.pushRepeatCount(result);
     if (result == 0) {
         parser_.popRepeater();
         parser_.advance(Symbol::sMapEnd);
-    } else {
-        parser_.setRepeatCount(result);
     }
     return result;
 }
@@ -693,11 +690,10 @@ size_t ResolvingDecoderImpl<P>::mapNext()
 {
     parser_.processImplicitActions();
     size_t result = base_->mapNext();
+    parser_.nextRepeatCount(result);
     if (result == 0) {
         parser_.popRepeater();
         parser_.advance(Symbol::sMapEnd);
-    } else {
-        parser_.setRepeatCount(result);
     }
     return result;
 }
@@ -710,7 +706,7 @@ size_t ResolvingDecoderImpl<P>::skipMap()
     if (n == 0) {
         parser_.pop();
     } else {
-        parser_.setRepeatCount(n);
+        parser_.pushRepeatCount(n);
         parser_.skip(*base_);
     }
     parser_.advance(Symbol::sMapEnd);
diff --git a/lang/c++/impl/parsing/Symbol.hh b/lang/c++/impl/parsing/Symbol.hh
index 291175291..33c71f639 100644
--- a/lang/c++/impl/parsing/Symbol.hh
+++ b/lang/c++/impl/parsing/Symbol.hh
@@ -42,7 +42,7 @@ class Symbol;
 
 typedef std::vector<Symbol> Production;
 typedef boost::shared_ptr<Production> ProductionPtr;
-typedef boost::tuple<size_t, bool, ProductionPtr, ProductionPtr> RepeaterInfo;
+typedef boost::tuple<std::stack<ssize_t>, bool, ProductionPtr, ProductionPtr> 
RepeaterInfo;
 typedef boost::tuple<ProductionPtr, ProductionPtr> RootInfo;
 
 class Symbol {
@@ -206,15 +206,14 @@ public:
 
     static Symbol repeater(const ProductionPtr& p,
                            bool isArray) {
-        size_t s = 0;
-        return Symbol(sRepeater, boost::make_tuple(s, isArray, p, p));
+        return repeater(p, p, isArray);
     }
 
     static Symbol repeater(const ProductionPtr& read,
                            const ProductionPtr& skip,
                            bool isArray) {
-        size_t s = 0;
-        return Symbol(sRepeater, boost::make_tuple(s, isArray, read, skip));
+        std::stack<ssize_t> s;
+        return Symbol(sRepeater, RepeaterInfo(s, isArray, read, skip));
     }
 
     static Symbol defaultStartAction(boost::shared_ptr<std::vector<uint8_t> > 
bb)
@@ -425,6 +424,8 @@ public:
     Symbol::Kind advance(Symbol::Kind k) {
         for (; ;) {
             Symbol& s = parsingStack.top();
+//            std::cout << "advance: " << Symbol::toString(s.kind())
+//                      << " looking for " << Symbol::toString(k) << '\n';
             if (s.kind() == k) {
                 parsingStack.pop();
                 return k;
@@ -454,7 +455,16 @@ public:
                 case Symbol::sRepeater:
                     {
                         RepeaterInfo *p = s.extrap<RepeaterInfo>();
-                        --boost::tuples::get<0>(*p);
+                        std::stack<ssize_t>& ns = boost::tuples::get<0>(*p);
+                        if (ns.empty()) {
+                            throw Exception(
+                                "Empty item count stack in repeater advance");
+                        }
+                       if (ns.top() == 0) {
+                            throw Exception(
+                                "Zero item count in repeater advance");
+                        }
+                        --ns.top();
                         append(boost::tuples::get<2>(*p));
                     }
                     continue;
@@ -500,6 +510,7 @@ public:
         }
         while (parsingStack.size() >= sz) {
             Symbol& t = parsingStack.top();
+           // std::cout << "skip: " << Symbol::toString(t.kind()) << '\n';
             switch (t.kind()) {
             case Symbol::sNull:
                 d.decodeNull();
@@ -529,13 +540,14 @@ public:
                 {
                     parsingStack.pop();
                     size_t n = d.skipArray();
+                   processImplicitActions();
                     assertMatch(Symbol::sRepeater, parsingStack.top().kind());
                     if (n == 0) {
                         break;
                     }
                     Symbol& t = parsingStack.top();
                     RepeaterInfo *p = t.extrap<RepeaterInfo>();
-                    boost::tuples::get<0>(*p) = n;
+                    boost::tuples::get<0>(*p).push(n);
                     continue;
                 }
             case Symbol::sArrayEnd:
@@ -544,13 +556,14 @@ public:
                 {
                     parsingStack.pop();
                     size_t n = d.skipMap();
+                   processImplicitActions();
+                    assertMatch(Symbol::sRepeater, parsingStack.top().kind());
                     if (n == 0) {
                         break;
                     }
-                    assertMatch(Symbol::sRepeater, parsingStack.top().kind());
                     Symbol& t = parsingStack.top();
                     RepeaterInfo *p = t.extrap<RepeaterInfo>();
-                    boost::tuples::get<0>(*p) = n;
+                    boost::tuples::get<0>(*p).push(n);
                     continue;
                 }
             case Symbol::sMapEnd:
@@ -576,15 +589,22 @@ public:
             case Symbol::sRepeater:
                 {
                     RepeaterInfo *p = t.extrap<RepeaterInfo>();
-                    if (boost::tuples::get<0>(*p) == 0) {
-                        boost::tuples::get<0>(*p) =
-                            boost::tuples::get<1>(*p) ? d.arrayNext() :
-                                d.mapNext();
+                    std::stack<ssize_t>& ns = boost::tuples::get<0>(*p);
+                    if (ns.empty()) {
+                        throw Exception(
+                            "Empty item count stack in repeater skip");
+                    }
+                    ssize_t& n = ns.top();
+                    if (n == 0) {
+                        n = boost::tuples::get<1>(*p) ? d.arrayNext()
+                                                      : d.mapNext();
                     }
-                    if (boost::tuples::get<0>(*p) != 0) {
-                        --boost::tuples::get<0>(*p);
+                    if (n != 0) {
+                        --n;
                         append(boost::tuples::get<3>(*p));
                         continue;
+                    } else {
+                        ns.pop();
                     }
                 }
                 break;
@@ -685,23 +705,40 @@ public:
         return result;
     }
 
-    void setRepeatCount(size_t n) {
+    void pushRepeatCount(size_t n) {
+       processImplicitActions();
         Symbol& s = parsingStack.top();
         assertMatch(Symbol::sRepeater, s.kind());
-        size_t& nn = boost::tuples::get<0>(*s.extrap<RepeaterInfo>());
-        if (nn != 0) {
-            throw Exception("Wrong number of items");
-        }
-        nn = n;
+       RepeaterInfo *p = s.extrap<RepeaterInfo>();
+        std::stack<ssize_t> &nn = boost::tuples::get<0>(*p);
+        nn.push(n);
+    }
+
+    void nextRepeatCount(size_t n) {
+       processImplicitActions();
+        Symbol& s = parsingStack.top();
+        assertMatch(Symbol::sRepeater, s.kind());
+       RepeaterInfo *p = s.extrap<RepeaterInfo>();
+        std::stack<ssize_t> &nn = boost::tuples::get<0>(*p);
+        if (nn.empty() || nn.top() != 0) {
+         throw Exception("Wrong number of items");
+       }
+        nn.top() = n;
     }
 
     void popRepeater() {
         processImplicitActions();
-        const Symbol& s = parsingStack.top();
+        Symbol& s = parsingStack.top();
         assertMatch(Symbol::sRepeater, s.kind());
-        if (boost::tuples::get<0>(*s.extrap<RepeaterInfo>()) != 0) {
-            throw Exception("Incorrect number of items");
+       RepeaterInfo *p = s.extrap<RepeaterInfo>();
+        std::stack<ssize_t> &ns = boost::tuples::get<0>(*p);
+        if (ns.empty()) {
+            throw Exception("Incorrect number of items (empty)");
+        }
+        if (ns.top() > 0) {
+            throw Exception("Incorrect number of items (non-zero)");
         }
+        ns.pop();
         parsingStack.pop();
     }
 
@@ -778,9 +815,9 @@ inline std::ostream& operator<<(std::ostream& os, const 
Symbol s)
             {
                 const RepeaterInfo& ri = *s.extrap<RepeaterInfo>();
                 os << '(' << Symbol::toString(s.kind())
-                    << boost::tuples::get<2>(ri)
-                    << boost::tuples::get<3>(ri)
-                    << ')';
+                   << ' ' << *boost::tuples::get<2>(ri)
+                   << ' ' << *boost::tuples::get<3>(ri)
+                   << ')';
             }
             break;
         case Symbol::sIndirect:
@@ -789,6 +826,25 @@ inline std::ostream& operator<<(std::ostream& os, const 
Symbol s)
                 << *s.extra<boost::shared_ptr<Production> >() << ')';
             }
             break;
+        case Symbol::sAlternative:
+            {
+                os << '(' << Symbol::toString(s.kind());
+                for (std::vector<ProductionPtr>::const_iterator it =
+                         s.extrap<std::vector<ProductionPtr> >()->begin();
+                     it != s.extrap<std::vector<ProductionPtr> >()->end();
+                     ++it) {
+                    os << ' ' << **it;
+                }
+                os << ')';
+            }
+            break;
+        case Symbol::sSymbolic:
+            {
+              os << '(' << Symbol::toString(s.kind())
+                 << ' ' << s.extra<boost::weak_ptr<Production> >().lock()
+                 << ')';
+          }
+          break;
         default:
             os << Symbol::toString(s.kind());
             break;
diff --git a/lang/c++/impl/parsing/ValidatingCodec.cc 
b/lang/c++/impl/parsing/ValidatingCodec.cc
index a401afc6f..eecc393e2 100644
--- a/lang/c++/impl/parsing/ValidatingCodec.cc
+++ b/lang/c++/impl/parsing/ValidatingCodec.cc
@@ -103,7 +103,7 @@ ProductionPtr ValidatingGrammarGenerator::doGenerate(const 
NodePtr& n,
             reverse(result->begin(), result->end());
 
             m[n] = result;
-            return result;
+            return make_shared<Production>(1, Symbol::indirect(result));
         }
     case AVRO_ENUM:
         {
@@ -311,11 +311,10 @@ size_t ValidatingDecoder<P>::arrayStart()
 {
     parser.advance(Symbol::sArrayStart);
     size_t result = base->arrayStart();
+    parser.pushRepeatCount(result);
     if (result == 0) {
         parser.popRepeater();
         parser.advance(Symbol::sArrayEnd);
-    } else {
-        parser.setRepeatCount(result);
     }
     return result;
 }
@@ -324,11 +323,10 @@ template <typename P>
 size_t ValidatingDecoder<P>::arrayNext()
 {
     size_t result = base->arrayNext();
+    parser.nextRepeatCount(result);
     if (result == 0) {
         parser.popRepeater();
         parser.advance(Symbol::sArrayEnd);
-    } else {
-        parser.setRepeatCount(result);
     }
     return result;
 }
@@ -341,7 +339,7 @@ size_t ValidatingDecoder<P>::skipArray()
     if (n == 0) {
         parser.pop();
     } else {
-        parser.setRepeatCount(n);
+        parser.pushRepeatCount(n);
         parser.skip(*base);
     }
     parser.advance(Symbol::sArrayEnd);
@@ -353,11 +351,10 @@ size_t ValidatingDecoder<P>::mapStart()
 {
     parser.advance(Symbol::sMapStart);
     size_t result = base->mapStart();
+    parser.pushRepeatCount(result);
     if (result == 0) {
         parser.popRepeater();
         parser.advance(Symbol::sMapEnd);
-    } else {
-        parser.setRepeatCount(result);
     }
     return result;
 }
@@ -366,11 +363,10 @@ template <typename P>
 size_t ValidatingDecoder<P>::mapNext()
 {
     size_t result = base->mapNext();
+    parser.nextRepeatCount(result);
     if (result == 0) {
         parser.popRepeater();
         parser.advance(Symbol::sMapEnd);
-    } else {
-        parser.setRepeatCount(result);
     }
     return result;
 }
@@ -383,7 +379,7 @@ size_t ValidatingDecoder<P>::skipMap()
     if (n == 0) {
         parser.pop();
     } else {
-        parser.setRepeatCount(n);
+        parser.pushRepeatCount(n);
         parser.skip(*base);
     }
     parser.advance(Symbol::sMapEnd);
@@ -518,6 +514,7 @@ template<typename P>
 void ValidatingEncoder<P>::arrayStart()
 {
     parser_.advance(Symbol::sArrayStart);
+    parser_.pushRepeatCount(0);
     base_->arrayStart();
 }
 
@@ -533,6 +530,7 @@ template<typename P>
 void ValidatingEncoder<P>::mapStart()
 {
     parser_.advance(Symbol::sMapStart);
+    parser_.pushRepeatCount(0);
     base_->mapStart();
 }
 
@@ -547,7 +545,7 @@ void ValidatingEncoder<P>::mapEnd()
 template<typename P>
 void ValidatingEncoder<P>::setItemCount(size_t count)
 {
-    parser_.setRepeatCount(count);
+    parser_.nextRepeatCount(count);
     base_->setItemCount(count);
 }
 
diff --git a/lang/c++/test/CodecTests.cc b/lang/c++/test/CodecTests.cc
index f8bbe84d0..e49881e5f 100644
--- a/lang/c++/test/CodecTests.cc
+++ b/lang/c++/test/CodecTests.cc
@@ -1070,6 +1070,64 @@ static const TestData data[] = {
       "{\"name\":\"car\", \"type\":\"Lisp\"},"
       "{\"name\":\"cdr\", \"type\":\"Lisp\"}]}]}]}",
       "U2U1S10U0N", 1},
+    { "{"  // https://issues.apache.org/jira/browse/AVRO-1635
+      "  \"name\": \"Container\","
+      "  \"type\": \"record\","
+      "  \"fields\": [{"
+      "    \"name\": \"field\","
+      "    \"type\": {"
+      "      \"name\": \"Object\","
+      "      \"type\": \"record\","
+      "      \"fields\": [{"
+      "        \"name\": \"value\","
+      "        \"type\": ["
+      "          \"string\","
+      "          {\"type\": \"map\", \"values\": \"Object\"}"
+      "        ]"
+      "      }]"
+      "    }"
+      "  }]"
+      "}",
+      "U1{c1sK1U0S1c2sK2U1{c2sK4U1{c1sK6U1{}}sK5U1{}}sK3U0S3}", 5},
+    { "{"
+      "  \"name\": \"Container\","
+      "  \"type\": \"record\","
+      "  \"fields\": [{"
+      "    \"name\": \"tree_A\","
+      "    \"type\": {"
+      "      \"name\": \"ArrayTree\","
+      "      \"type\": \"record\","
+      "      \"fields\": [{"
+      "        \"name\": \"label\","
+      "        \"type\": \"long\""
+      "      }, {"
+      "        \"name\": \"children\","
+      "        \"type\": {"
+      "          \"type\": \"array\","
+      "          \"items\": {"
+      "            \"name\": \"MapTree\","
+      "            \"type\": \"record\","
+      "            \"fields\": [{"
+      "              \"name\": \"label\","
+      "              \"type\": \"int\""
+      "            }, {"
+      "              \"name\": \"children\","
+      "              \"type\": {"
+      "                \"type\": \"map\","
+      "                \"values\": \"ArrayTree\""
+      "              }"
+      "            }]"
+      "          }"
+      "        }"
+      "      }]"
+      "    }"
+      "  }, {"
+      "    \"name\": \"tree_B\","
+      "    \"type\": \"MapTree\""
+      "  }]"
+      "}",
+      
"L[c1sI{c1sK3L[]c2sK4L[c1sI{c1sK6L[c2sI{}sI{}]}]sK5L[]}]I{c2sK1L[]sK2L[]}",
+      7},
 };
 
 static const TestData2 data2[] = {
diff --git a/lang/c++/test/unittest.cc b/lang/c++/test/unittest.cc
index 5aef9b75a..44d347930 100644
--- a/lang/c++/test/unittest.cc
+++ b/lang/c++/test/unittest.cc
@@ -29,6 +29,9 @@
 #include "Parser.hh"
 #include "Compiler.hh"
 #include "SchemaResolution.hh"
+#include "Stream.hh"
+#include "Encoder.hh"
+#include "Decoder.hh"
 #include "buffer/BufferStream.hh"
 #include "buffer/BufferPrint.hh"
 
@@ -477,72 +480,179 @@ struct TestNested
     void createSchema() 
     {
         std::cout << "TestNested\n";
-        RecordSchema rec("LongList");
-        rec.addField("value", LongSchema());
+        RecordSchema rec("LongListContainer");
+
+        RecordSchema list("LongList");
+        list.addField("value", LongSchema());
         UnionSchema next;
         next.addType(NullSchema());
-        next.addType(SymbolicSchema(Name("LongList"), rec.root()));
-        rec.addField("next", next);
-        rec.addField("end", BoolSchema());
-
+        next.addType(SymbolicSchema(Name("LongList"), list.root()));
+        list.addField("next", next);
+        list.addField("end", BoolSchema());
+        rec.addField("list", list);
+
+        RecordSchema arrayTree("ArrayTree");
+        arrayTree.addField("label", StringSchema());
+        arrayTree.addField("children", ArraySchema(
+            SymbolicSchema(Name("ArrayTree"), arrayTree.root())));
+        rec.addField("array_tree", arrayTree);
+        
         schema_.setSchema(rec);
         schema_.toJson(std::cout);
         schema_.toFlatList(std::cout);
     }
 
-    InputBuffer serializeNoRecurse()
-    {
+    InputBuffer serializeNoRecurse() {
         std::cout << "No recurse\n";
         Serializer<ValidatingWriter> s(schema_);
         s.writeRecord();
-        s.writeLong(1);
-        s.writeUnion(0);
-        s.writeNull();
-        s.writeBool(true);
+        {
+            s.writeRecord();
+            s.writeLong(1);
+            s.writeUnion(0);
+            s.writeNull();
+            s.writeBool(true);
+            s.writeRecordEnd();
+        }
+        {
+            s.writeRecord();
+            s.writeString("hello world");
+            s.writeArrayEnd();
+            s.writeRecordEnd();
+        }
         s.writeRecordEnd();
 
         return s.buffer();
     }
 
+    static void encodeNoRecurse(Encoder &e)
+    {
+        std::cout << "Encode no recurse\n";
+        e.encodeLong(1);
+        e.encodeUnionIndex(0);
+        e.encodeNull();
+        e.encodeBool(true);
+
+        e.encodeString("hello world");
+        e.arrayStart();
+        e.arrayEnd();
+    }
+
     InputBuffer serializeRecurse()
     {
         std::cout << "Recurse\n";
         Serializer<ValidatingWriter> s(schema_);
         s.writeRecord();
-        s.writeLong(1);
-        s.writeUnion(1);
         {
             s.writeRecord();
-            s.writeLong(2);
+            s.writeLong(1);
             s.writeUnion(1);
             {
                 s.writeRecord();
-                s.writeLong(3);
-                s.writeUnion(0);
-                { 
-                    s.writeNull();
+                s.writeLong(2);
+                s.writeUnion(1);
+                {
+                    s.writeRecord();
+                    s.writeLong(3);
+                    s.writeUnion(0);
+                    { s.writeNull(); }
+                    s.writeBool(false);
+                    s.writeRecordEnd();
                 }
                 s.writeBool(false);
                 s.writeRecordEnd();
             }
-            s.writeBool(false);
+            s.writeBool(true);
+            s.writeRecordEnd();
+        }
+        {
+            s.writeRecord();
+            s.writeString("a");
+            s.writeArrayBlock(2);
+            {
+                s.writeRecord();
+                s.writeString("aa");
+                s.writeArrayBlock(1);
+                {
+                    s.writeRecord();
+                    s.writeString("aaa");
+                    s.writeArrayEnd();
+                    s.writeRecordEnd();
+                }
+                s.writeArrayEnd();
+                s.writeRecordEnd();
+            }
+            {
+                s.writeRecord();
+                s.writeString("ab");
+                s.writeArrayEnd();
+                s.writeRecordEnd();
+            }
+            s.writeArrayEnd();
             s.writeRecordEnd();
-
         }
-        s.writeBool(true);
         s.writeRecordEnd();
 
         return s.buffer();
     }
 
-    void readRecord(Parser<ValidatingReader> &p) 
+    static void encodeRecurse(Encoder &e)
+    {
+        std::cout << "Encode recurse\n";
+        e.encodeLong(1);
+        e.encodeUnionIndex(1);
+        {
+            e.encodeLong(2);
+            e.encodeUnionIndex(1);
+            {
+                e.encodeLong(3);
+                e.encodeUnionIndex(0);
+                {
+                    e.encodeNull();
+                }
+                e.encodeBool(false);
+            }
+            e.encodeBool(false);
+        }
+        e.encodeBool(true);
+
+        e.encodeString("a");
+        e.arrayStart();
+       e.setItemCount(2);
+        {
+            e.encodeString("aa");
+            e.arrayStart();
+           e.setItemCount(1);
+            {
+                e.encodeString("aaa");
+                e.arrayStart();
+                e.arrayEnd();
+            }
+            e.arrayEnd();
+        }
+        {
+            e.encodeString("ab");
+            e.arrayStart();
+            e.arrayEnd();
+        }
+        e.arrayEnd();
+    }
+
+    void readRecord(Parser<ValidatingReader> &p) {
+        p.readRecord();
+        readListRecord(p);
+        readArrayRecord(p);
+        p.readRecordEnd();
+    }
+  
+    void readListRecord(Parser<ValidatingReader> &p) 
     {
         p.readRecord();
         int64_t val = p.readLong();
         std::cout << "longval = " << val << '\n';
         int64_t path = p.readUnion();
         if (path == 1) {
-            readRecord(p);
+            readListRecord(p);
         }
         else {
             p.readNull();
@@ -552,12 +662,60 @@ struct TestNested
         p.readRecordEnd();
     }
 
+    void readArrayRecord(Parser<ValidatingReader> &p)
+    {
+        p.readRecord();
+        std::string label;
+        p.readString(label);
+        std::cout << "label = " << label << '\n';
+        for (int64_t bs = p.readArrayBlockSize(); bs > 0;
+             bs = p.readArrayBlockSize()) {
+            for (int64_t i = 0; i < bs; ++i) {
+                readArrayRecord(p);
+            }
+        }
+        p.readRecordEnd();
+    }
+
     void validatingParser(InputBuffer &buf) 
     {
         Parser<ValidatingReader> p(schema_, buf);
         readRecord(p);
     }
 
+    void decodeListRecord(Decoder& d)
+    {
+        int64_t val = d.decodeLong();
+        std::cout << "longval = " << val << '\n';
+        int64_t path = d.decodeUnionIndex();
+        if (path == 1) {
+            decodeListRecord(d);
+        }
+        else {
+          d.decodeNull();
+        }
+        bool b = d.decodeBool();
+        std::cout << "bval = " << b << '\n';      
+    }
+
+    void decodeArrayRecord(Decoder& d)
+    {
+      std::string label = d.decodeString();
+      std::cout << "label = " << label << '\n';
+      for (int64_t bs = d.arrayStart(); bs > 0; bs = d.arrayNext()) {
+       std::cout << "array block size = " << bs << '\n';
+        for (int64_t i = 0; i < bs; ++i) {
+          decodeArrayRecord(d);
+        }
+      }
+    }
+
+    void runDecoder(Decoder& d)
+    {
+      decodeListRecord(d);
+      decodeArrayRecord(d);
+    }
+  
     void testToScreen() {
         InputBuffer buf1 = serializeNoRecurse();
         InputBuffer buf2 = serializeRecurse();
@@ -565,6 +723,7 @@ struct TestNested
         std::cout << buf2;
     }
 
+    // Tests for Serializer + Parser
     void testParseNoRecurse() {
         std::cout << "ParseNoRecurse\n";
         InputBuffer buf = serializeNoRecurse();
@@ -579,6 +738,50 @@ struct TestNested
         validatingParser(buf);
     }
 
+    // Tests for encode + decode
+    void runEncodeDecode(Encoder &e, Decoder &d, void (*encode_fn)(Encoder &))
+    {
+       std::auto_ptr<OutputStream> out = memoryOutputStream();
+       e.init(*out);
+       encode_fn(e);
+       std::auto_ptr<InputStream> in = memoryInputStream(*out);
+       d.init(*in);
+        runDecoder(d);
+    }
+
+    void testDecodeNoRecurse()
+    {
+        std::cout << "DecodeNoRecurse\n";
+       runEncodeDecode(*validatingEncoder(schema_, binaryEncoder()),
+                       *validatingDecoder(schema_, binaryDecoder()),
+                       encodeNoRecurse);
+       
+    }
+
+    void testDecodeRecurse()
+    {
+        std::cout << "DecodeRecurse\n";
+       runEncodeDecode(*validatingEncoder(schema_, binaryEncoder()),
+                       *validatingDecoder(schema_, binaryDecoder()),
+                       encodeRecurse);
+    }
+
+  void testDecodeNoRecurseJson()
+    {
+        std::cout << "DecodeNoRecurseJson\n";
+       runEncodeDecode(*jsonEncoder(schema_),
+                       *jsonDecoder(schema_),
+                       encodeNoRecurse);
+       
+    }
+
+    void testDecodeRecurseJson()
+    {
+        std::cout << "DecodeRecurseJson\n";
+       runEncodeDecode(*jsonEncoder(schema_),
+                       *jsonDecoder(schema_),
+                       encodeRecurse);
+    }
 
     void test() {
         createSchema();
@@ -587,6 +790,10 @@ struct TestNested
         testParseNoRecurse();
         testParseRecurse();
 
+        testDecodeNoRecurse();
+        testDecodeRecurse();
+        testDecodeNoRecurseJson();
+        testDecodeRecurseJson();
     }
 
     ValidSchema schema_;


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


> C++ schema aware encoders throw tr1::bad_weak_ptr exception for recursive 
> schema
> --------------------------------------------------------------------------------
>
>                 Key: AVRO-1635
>                 URL: https://issues.apache.org/jira/browse/AVRO-1635
>             Project: Avro
>          Issue Type: Bug
>          Components: c++
>    Affects Versions: 1.7.7
>         Environment: Ubuntu 12.04, gcc 4.6.4
>            Reporter: Heye Vöcking
>            Assignee: William Matthews
>            Priority: Major
>              Labels: avro, c++, encode, recursive, schema
>
> Encoding an object with a recursive schema fails when using a jsonEncoder or 
> a validatingEncoder. Here is an example:
> Output:
> {noformat}
> terminate called after throwing an instance of 
> 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr>
>  >'
>   what():  tr1::bad_weak_ptr
> {noformat}
> {code:title=container.json|borderStyle=solid}
> {
>   "name": "Container",
>   "doc": "Container to demonstrate the weak_ptr exception.",
>   "type": "record",
>   "fields": [{
>     "name": "field",
>     "type": {
>       "name": "Object",
>       "type": "record",
>       "fields": [{
>         "name": "value",
>         "type": [
>           "string",
>           {"type": "map", "values": "Object"}
>         ]
>       }]
>     }
>   }]
> }
> {code}
> {code:title=example.cc|borderStyle=solid}
> #include <fstream>
> #include <avro/Compiler.hh>
> #include <avro/Encoder.hh>
> #include <avro/Stream.hh>
> #include <avro/ValidSchema.hh>
> #include "container.hh"
> int
> main()
> {
>     std::ifstream ifs("container.json");
>     avro::ValidSchema schema;
>     avro::compileJsonSchema(ifs, schema);
>     std::auto_ptr<avro::OutputStream> out = avro::memoryOutputStream();
>     // Either one fails, here we use the jsonEncoder
>     // avro::EncoderPtr encoder = avro::jsonEncoder(schema);
>     avro::EncoderPtr encoder = avro::validatingEncoder(schema, 
> avro::binaryEncoder());
>     
>     // An encoder that doesn't know the schema works fine
>     // avro::EncoderPtr encoder = avro::binaryEncoder();
>     encoder->init(*out);
>     Container container;
>     std::map<std::string, Object > object;
>     // Note that it doesn't fail if we don't insert a value into the map
>     object["a"].value.set_string("x");
>     container.field.value.set_map(object);
>     avro::encode(*encoder, container);
>     return 0;
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to