You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by th...@apache.org on 2011/10/21 17:00:26 UTC

svn commit: r1187383 - in /avro/trunk: CHANGES.txt lang/c++/api/Generic.hh lang/c++/examples/generic.cc lang/c++/impl/Generic.cc lang/c++/test/CodecTests.cc

Author: thiru
Date: Fri Oct 21 15:00:25 2011
New Revision: 1187383

URL: http://svn.apache.org/viewvc?rev=1187383&view=rev
Log:
AVRO-940. C++ design for generic datum could be better

Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/c++/api/Generic.hh
    avro/trunk/lang/c++/examples/generic.cc
    avro/trunk/lang/c++/impl/Generic.cc
    avro/trunk/lang/c++/test/CodecTests.cc

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1187383&r1=1187382&r2=1187383&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Fri Oct 21 15:00:25 2011
@@ -151,6 +151,9 @@ Avro 1.6.0 (unreleased)
     AVRO-938. Some more warning when built on RHEL. (thiru)
 
     AVRO-937. C++ CMake keeps generating code even when there is no change. (thiru)
+
+    AVRO-940. C++ design for generic datum could be better. (thiru)
+
   BUG FIXES
 
     AVRO-824. Java: Fix usage message of BinaryFragmentToJsonTool.

Modified: avro/trunk/lang/c++/api/Generic.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/Generic.hh?rev=1187383&r1=1187382&r2=1187383&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/Generic.hh (original)
+++ avro/trunk/lang/c++/api/Generic.hh Fri Oct 21 15:00:25 2011
@@ -33,7 +33,6 @@
 #include "ValidSchema.hh"
 
 namespace avro {
-
 /**
  * Generic datum which can hold any Avro type. The datum has a type
  * and a value. The type is one of the Avro data types. The C++ type for
@@ -65,23 +64,19 @@ class GenericDatum {
     template <typename T>
     GenericDatum(Type t, const T& v) : type_(t), value_(v) { }
 
+    void init(const NodePtr& schema);
 public:
     /**
      * The avro data type this datum holds.
      */
-    Type type() const {
-        return type_;
-    }
+    Type type() const;
 
     /**
      * Returns the value held by this datum.
      * T The type for the value. This must correspond to the
      * avro type returned by type().
      */
-    template<typename T>
-    const T& value() const {
-        return *boost::any_cast<T>(&value_);
-    }
+    template<typename T> const T& value() const;
 
     /**
      * Returns the reference to the value held by this datum, which
@@ -92,10 +87,24 @@ public:
      * T The type for the value. This must correspond to the
      * avro type returned by type().
      */
-    template<typename T>
-    T& value() {
-        return *boost::any_cast<T>(&value_);
-    }
+    template<typename T> T& value();
+
+    /**
+     * Returns true if and only if this datum is a union.
+     */
+    bool isUnion() const { return type_ == AVRO_UNION; }
+
+    /**
+     * Returns the index of the current branch, if this is a union.
+     * \sa isUnion().
+     */
+    size_t unionBranch() const;
+
+    /**
+     * Selects a new branch in the union if this is a union.
+     * \sa isUnion().
+     */
+    void selectBranch(size_t branch);
 
     /// Makes a new AVRO_NULL datum.
     GenericDatum() : type_(AVRO_NULL) { }
@@ -130,30 +139,35 @@ public:
      * \param schema The schema that defines the avro type.
      */
     GenericDatum(const NodePtr& schema);
+
+    /**
+     * Constructs a datum corresponding to the given avro type.
+     * The value will the appropraite default corresponding to the
+     * data type.
+     * \param schema The schema that defines the avro type.
+     */
+    GenericDatum(const ValidSchema& schema);
 };
 
 /**
  * The base class for all generic type for containers.
  */
 class GenericContainer {
-    const NodePtr schema_;
+    NodePtr schema_;
+    static void assertType(const NodePtr& schema, Type type);
 protected:
     /**
      * Constructs a container corresponding to the given schema.
      */
-    GenericContainer(const NodePtr& s) : schema_(s) { }
+    GenericContainer(Type type, const NodePtr& s) : schema_(s) {
+        assertType(s, type);
+    }
 
     /**
      * Asserts if the given generic datum \p v has a type that matches \p n.
      */
     static void assertSameType(const GenericDatum& v, const NodePtr& n);
 
-    /**
-     * Asserts that the given schema \p schema has the given type \c type.
-     * If not, it throws an exception with the given message \c message.
-     */
-    static void assertType(const NodePtr& schema, Type type,
-        const char* message);
 public:
     /// Returns the schema for this object
     const NodePtr& schema() const {
@@ -162,6 +176,64 @@ public:
 };
 
 /**
+ * Generic container for unions.
+ */
+class GenericUnion : public GenericContainer {
+    size_t curBranch_;
+    GenericDatum datum_;
+
+public:
+    /**
+     * Constructs a generic union corresponding to the given schema \p schema,
+     * and the given value. The schema should be of Avro type union
+     * and the value should correspond to one of the branches of the union.
+     */
+    GenericUnion(const NodePtr& schema) :
+        GenericContainer(AVRO_UNION, schema), curBranch_(schema->leaves()) {
+    }
+
+    /**
+     * Returns the index of the current branch.
+     */
+    size_t currentBranch() const { return curBranch_; }
+
+    /**
+     * Selects a new branch. The type for the value is changed accordingly.
+     * \param branch The index for the selected branch.
+     */
+    void selectBranch(size_t branch) {
+        if (curBranch_ != branch) {
+            datum_ = GenericDatum(schema()->leafAt(branch));
+            curBranch_ = branch;
+        }
+    }
+
+    /**
+     * Returns the type for currently selected branch in this union.
+     */
+    Type type() const {
+        return datum_.type();
+    }
+
+    /**
+     * Returns the value in this union.
+     */
+    template<typename T>
+    const T& value() const {
+        return datum_.value<T>();
+    }
+
+    /**
+     * Returns the reference to the value in this union.
+     */
+    template<typename T>
+    T& value() {
+        return datum_.value<T>();
+    }
+
+};
+
+/**
  * The generic container for Avro records.
  */
 class GenericRecord : public GenericContainer {
@@ -218,10 +290,7 @@ public:
      * Constructs a generic array corresponding to the given schema \p schema,
      * which should be of Avro type array.
      */
-    GenericArray(const NodePtr& schema) : GenericContainer(schema) {
-        if (schema->type() != AVRO_ARRAY) {
-            throw Exception("Schema is not an array");
-        }
+    GenericArray(const NodePtr& schema) : GenericContainer(AVRO_ARRAY, schema) {
     }
 
     /**
@@ -255,8 +324,7 @@ public:
      * Constructs a generic map corresponding to the given schema \p schema,
      * which should be of Avro type map.
      */
-    GenericMap(const NodePtr& schema) : GenericContainer(schema) {
-        assertType(schema, AVRO_MAP, "Schema is not a map");
+    GenericMap(const NodePtr& schema) : GenericContainer(AVRO_MAP, schema) {
     }
 
     /**
@@ -286,7 +354,8 @@ public:
      * Constructs a generic enum corresponding to the given schema \p schema,
      * which should be of Avro type enum.
      */
-    GenericEnum(const NodePtr& schema) : GenericContainer(schema), value_(0) {
+    GenericEnum(const NodePtr& schema) :
+        GenericContainer(AVRO_ENUM, schema), value_(0) {
     }
 
     /**
@@ -355,7 +424,7 @@ public:
      * Constructs a generic enum corresponding to the given schema \p schema,
      * which should be of Avro type fixed.
      */
-    GenericFixed(const NodePtr& schema) : GenericContainer(schema) {
+    GenericFixed(const NodePtr& schema) : GenericContainer(AVRO_FIXED, schema) {
         value_.resize(schema->fixedSize());
     }
 
@@ -383,8 +452,7 @@ class GenericReader : boost::noncopyable
     const bool isResolving_;
     const DecoderPtr decoder_;
 
-    static void read(GenericDatum& datum, const NodePtr& n, Decoder& d,
-        bool isResolving);
+    static void read(GenericDatum& datum, Decoder& d, bool isResolving);
 public:
     /**
      * Constructs a reader for the given schema using the given decoder.
@@ -407,6 +475,11 @@ public:
     /**
      * Reads a generic datum from the stream, using the given schema.
      */
+    static void read(Decoder& d, GenericDatum& g);
+
+    /**
+     * Reads a generic datum from the stream, using the given schema.
+     */
     static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
 };
 
@@ -418,7 +491,7 @@ class GenericWriter : boost::noncopyable
     const ValidSchema schema_;
     const EncoderPtr encoder_;
 
-    static void write(const GenericDatum& datum, const NodePtr& n, Encoder& e);
+    static void write(const GenericDatum& datum, Encoder& e);
 public:
     /**
      * Constructs a writer for the given schema using the given encoder.
@@ -431,15 +504,52 @@ public:
     void write(const GenericDatum& datum) const;
 
     /**
+     * Writes a generic datum on to the stream.
+     */
+    static void write(Encoder& e, const GenericDatum& g);
+
+    /**
      * Writes a generic datum on to the stream, using the given schema.
+     * Retained for backward compatibility.
      */
-    static void write(Encoder& e, const GenericDatum& g, const ValidSchema& s);
+    static void write(Encoder& e, const GenericDatum& g, const ValidSchema&) {
+        write(e, g);
+    }
 };
 
+inline Type GenericDatum::type() const {
+    return (type_ == AVRO_UNION) ?
+        boost::any_cast<GenericUnion>(&value_)->type() : type_;
+}
+
+template<typename T>
+const T& GenericDatum::value() const {
+    return (type_ == AVRO_UNION) ?
+        boost::any_cast<GenericUnion>(&value_)->value<T>() :
+        *boost::any_cast<T>(&value_);
+}
+
+template<typename T>
+T& GenericDatum::value() {
+    return (type_ == AVRO_UNION) ?
+        boost::any_cast<GenericUnion>(&value_)->value<T>() :
+        *boost::any_cast<T>(&value_);
+}
+
+inline size_t GenericDatum::unionBranch() const {
+    return boost::any_cast<GenericUnion>(&value_)->currentBranch();
+}
+
+inline void GenericDatum::selectBranch(size_t branch) {
+    boost::any_cast<GenericUnion>(&value_)->selectBranch(branch);
+}
+
 template <typename T> struct codec_traits;
 
 /**
- * Specialization for codec_traits for Generic datum.
+ * Specialization of codec_traits for Generic datum along with its schema.
+ * This is maintained for compatibility with old code. Please use the
+ * cleaner codec_traits<GenericDatum> instead.
  */
 template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
     /** Encodes */
@@ -453,6 +563,22 @@ template <> struct codec_traits<std::pai
         GenericReader::read(d, p.second, p.first);
     }
 };
+
+/**
+ * Specialization of codec_traits for GenericDatum.
+ */
+template <> struct codec_traits<GenericDatum> {
+    /** Encodes */
+    static void encode(Encoder& e, const GenericDatum& g) {
+        GenericWriter::write(e, g);
+    }
+
+    /** Decodes */
+    static void decode(Decoder& d, GenericDatum& g) {
+        GenericReader::read(d, g);
+    }
+};
+    
 }   // namespace avro
 #endif
 

Modified: avro/trunk/lang/c++/examples/generic.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/examples/generic.cc?rev=1187383&r1=1187382&r2=1187383&view=diff
==============================================================================
--- avro/trunk/lang/c++/examples/generic.cc (original)
+++ avro/trunk/lang/c++/examples/generic.cc Fri Oct 21 15:00:25 2011
@@ -29,10 +29,8 @@ main()
     avro::DecoderPtr d = avro::binaryDecoder();
     d->init(*in);
 
-    std::pair<avro::ValidSchema, avro::GenericDatum> p(cpxSchema,
-        avro::GenericDatum(cpxSchema.root()));
-    avro::decode(*d, p);
-    const avro::GenericDatum& datum = p.second;
+    avro::GenericDatum datum(cpxSchema);
+    avro::decode(*d, datum);
     std::cout << "Type: " << datum.type() << std::endl;
     if (datum.type() == avro::AVRO_RECORD) {
         const avro::GenericRecord& r = datum.value<avro::GenericRecord>();

Modified: avro/trunk/lang/c++/impl/Generic.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/Generic.cc?rev=1187383&r1=1187382&r2=1187383&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Generic.cc (original)
+++ avro/trunk/lang/c++/impl/Generic.cc Fri Oct 21 15:00:25 2011
@@ -28,68 +28,85 @@ using std::ostringstream;
 
 typedef vector<uint8_t> bytes;
 
-void GenericContainer::assertType(const NodePtr& schema, Type type,
-    const char* message)
-{
+void GenericContainer::assertType(const NodePtr& schema, Type type) {
     if (schema->type() != type) {
-        throw Exception(message);
+        throw Exception(boost::format("Schema type %1 expected %2") %
+            toString(schema->type()) % toString(type));
     }
 }
 
+GenericDatum::GenericDatum(const ValidSchema& schema) :
+    type_(schema.root()->type())
+{
+    init(schema.root());
+}
+
 GenericDatum::GenericDatum(const NodePtr& schema) : type_(schema->type())
 {
+    init(schema);
+}
+
+void GenericDatum::init(const NodePtr& schema)
+{
+    NodePtr sc = schema;
     if (type_ == AVRO_SYMBOLIC) {
-        type_ = static_cast<NodeSymbolic&>(*schema).type();
+        sc = resolveSymbol(schema);
+        type_ = sc->type();
     }
     switch (type_) {
-        case AVRO_NULL:
-            break;
-        case AVRO_BOOL:
-            value_ = bool();
-            break;
-        case AVRO_INT:
-            value_ = int32_t();
-            break;
-        case AVRO_LONG:
-            value_ = int64_t();
-            break;
-        case AVRO_FLOAT:
-            value_ = float();
-            break;
-        case AVRO_DOUBLE:
-            value_ = double();
-            break;
-        case AVRO_STRING:
-            value_ = string();
-            break;
-        case AVRO_BYTES:
-            value_ = vector<uint8_t>();
-            break;
-        case AVRO_FIXED:
-            value_ = GenericFixed(schema);
-            break;
-        case AVRO_RECORD:
-            value_ = GenericRecord(schema);
-            break;
-        case AVRO_ENUM:
-            value_ = GenericEnum(schema);
-            break;
-        case AVRO_ARRAY:
-            value_ = GenericArray(schema);
-            break;
-        case AVRO_MAP:
-            value_ = GenericMap(schema);
-            break;
-        case AVRO_UNION:
-            throw Exception("Generic datum cannot be a union");
-        default:
-            throw Exception(boost::format("Unknown schema type %1%") %
-                toString(type_));
+    case AVRO_NULL:
+        break;
+    case AVRO_BOOL:
+        value_ = bool();
+        break;
+    case AVRO_INT:
+        value_ = int32_t();
+        break;
+    case AVRO_LONG:
+        value_ = int64_t();
+        break;
+    case AVRO_FLOAT:
+        value_ = float();
+        break;
+    case AVRO_DOUBLE:
+        value_ = double();
+        break;
+    case AVRO_STRING:
+        value_ = string();
+        break;
+    case AVRO_BYTES:
+        value_ = vector<uint8_t>();
+        break;
+    case AVRO_FIXED:
+        value_ = GenericFixed(sc);
+        break;
+    case AVRO_RECORD:
+        value_ = GenericRecord(sc);
+        break;
+    case AVRO_ENUM:
+        value_ = GenericEnum(sc);
+        break;
+    case AVRO_ARRAY:
+        value_ = GenericArray(sc);
+        break;
+    case AVRO_MAP:
+        value_ = GenericMap(sc);
+        break;
+    case AVRO_UNION:
+        value_ = GenericUnion(sc);
+        break;
+    default:
+        throw Exception(boost::format("Unknown schema type %1%") %
+            toString(type_));
     }
 }
 
-GenericRecord::GenericRecord(const NodePtr& schema) : GenericContainer(schema) {
+GenericRecord::GenericRecord(const NodePtr& schema) :
+    GenericContainer(AVRO_RECORD, schema) {
     fields_.resize(schema->leaves());
+    for (size_t i = 0; i < schema->leaves(); ++i) {
+        fields_[i] = GenericDatum(schema->leafAt(i));
+    }
 }
 
 GenericReader::GenericReader(const ValidSchema& s, const DecoderPtr& decoder) :
@@ -108,65 +125,16 @@ GenericReader::GenericReader(const Valid
 
 void GenericReader::read(GenericDatum& datum) const
 {
-    read(datum, schema_.root(), *decoder_, isResolving_);
-}
-
-static void ensureType(GenericDatum& datum, const NodePtr& n)
-{
-    if (datum.type() != n->type()) {
-        switch (n->type()) {
-        case AVRO_NULL:
-            datum = GenericDatum();
-            break;
-        case AVRO_BOOL:
-            datum = bool();
-            break;
-        case AVRO_INT:
-            datum = int32_t();
-            break;
-        case AVRO_LONG:
-            datum = int64_t();
-            break;
-        case AVRO_FLOAT:
-            datum = float();
-            break;
-        case AVRO_DOUBLE:
-            datum = double();
-            break;
-        case AVRO_STRING:
-            datum = string();
-            break;
-        case AVRO_BYTES:
-            datum = bytes();
-            break;
-        case AVRO_FIXED:
-        case AVRO_RECORD:
-        case AVRO_ENUM:
-        case AVRO_ARRAY:
-        case AVRO_MAP:
-            datum = n;
-            break;
-        case AVRO_UNION:
-            break;
-        default:
-            throw Exception("Unknown schema type");
-        }
-    }
+    datum = GenericDatum(schema_.root());
+    read(datum, *decoder_, isResolving_);
 }
 
-void GenericReader::read(GenericDatum& datum, const NodePtr& n, Decoder& d,
-    bool isResolving)
+void GenericReader::read(GenericDatum& datum, Decoder& d, bool isResolving)
 {
-    NodePtr nn = n;
-    if (nn->type() == AVRO_UNION) {
-        size_t r = d.decodeUnionIndex();
-        nn = nn->leafAt(r);
+    if (datum.isUnion()) {
+        datum.selectBranch(d.decodeUnionIndex());
     }
-    if (nn->type() == AVRO_SYMBOLIC) {
-        nn = static_cast<NodeSymbolic&>(*nn).getNode();
-    }
-    ensureType(datum, nn);
-    switch (nn->type()) {
+    switch (datum.type()) {
     case AVRO_NULL:
         d.decodeNull();
         break;
@@ -192,21 +160,24 @@ void GenericReader::read(GenericDatum& d
         d.decodeBytes(datum.value<bytes>());
         break;
     case AVRO_FIXED:
-        d.decodeFixed(nn->fixedSize(), datum.value<GenericFixed>().value());
+        {
+            GenericFixed& f = datum.value<GenericFixed>();
+            d.decodeFixed(f.schema()->fixedSize(), f.value());
+        }
         break;
     case AVRO_RECORD:
         {
             GenericRecord& r = datum.value<GenericRecord>();
-            size_t c = nn->leaves();
+            size_t c = r.schema()->leaves();
             if (isResolving) {
                 std::vector<size_t> fo =
                     static_cast<ResolvingDecoder&>(d).fieldOrder();
                 for (size_t i = 0; i < c; ++i) {
-                    read(r.fieldAt(fo[i]), nn->leafAt(fo[i]), d, isResolving);
+                    read(r.fieldAt(fo[i]), d, isResolving);
                 }
             } else {
                 for (size_t i = 0; i < c; ++i) {
-                    read(r.fieldAt(i), nn->leafAt(i), d, isResolving);
+                    read(r.fieldAt(i), d, isResolving);
                 }
             }
         }
@@ -216,82 +187,52 @@ void GenericReader::read(GenericDatum& d
         break;
     case AVRO_ARRAY:
         {
-            vector<GenericDatum>& r = datum.value<GenericArray>().value();
+            GenericArray& v = datum.value<GenericArray>();
+            vector<GenericDatum>& r = v.value();
+            const NodePtr& nn = v.schema()->leafAt(0);
             r.resize(0);
             size_t start = 0;
             for (size_t m = d.arrayStart(); m != 0; m = d.arrayNext()) {
                 r.resize(r.size() + m);
                 for (; start < r.size(); ++start) {
-                    read(r[start], nn->leafAt(0), d, isResolving);
+                    r[start] = GenericDatum(nn);
+                    read(r[start], d, isResolving);
                 }
             }
         }
         break;
     case AVRO_MAP:
         {
-            GenericMap::Value& r = datum.value<GenericMap>().value();
+            GenericMap& v = datum.value<GenericMap>();
+            GenericMap::Value& r = v.value();
+            const NodePtr& nn = v.schema()->leafAt(1);
             r.resize(0);
             size_t start = 0;
             for (size_t m = d.mapStart(); m != 0; m = d.mapNext()) {
                 r.resize(r.size() + m);
                 for (; start < r.size(); ++start) {
                     d.decodeString(r[start].first);
-                    read(r[start].second, nn->leafAt(1), d, isResolving);
+                    r[start].second = GenericDatum(nn);
+                    read(r[start].second, d, isResolving);
                 }
             }
         }
         break;
     default:
-        throw Exception("Unknown schema type");
+        throw Exception(boost::format("Unknown schema type %1%") %
+            toString(datum.type()));
     }
 }
 
 void GenericReader::read(Decoder& d, GenericDatum& g, const ValidSchema& s)
 {
-    read(g, s.root(), d, dynamic_cast<ResolvingDecoder*>(&d) != 0);
-}
-
-static void typeMismatch(Type t, Type u)
-{
-    throw Exception(boost::format("Type mismatch %1% v %2%") %
-        toString(t) % toString(u));
+    g = GenericDatum(s);
+    read(d, g);
 }
 
-template <typename T>
-bool hasSameName(const GenericDatum& datum, const NodePtr& n)
+void GenericReader::read(Decoder& d, GenericDatum& g)
 {
-    const T& c = datum.value<T>();
-    return c.schema()->name() == n->name();
-}
-
-template <typename T>
-void assertSameType(const GenericDatum& datum, const NodePtr& n)
-{
-    const T& c = datum.value<T>();
-    if (c.schema() != n) {
-        typeMismatch(c.schema()->type(), n->type());
-    }
-}
-
-static void assertType(const GenericDatum& datum, const NodePtr& n)
-{
-    if (datum.type() == n->type()) {
-        switch (n->type()) {
-        case AVRO_FIXED:
-            assertSameType<GenericFixed>(datum, n);
-            return;
-        case AVRO_RECORD:
-            assertSameType<GenericRecord>(datum, n);
-            return;
-        case AVRO_ENUM:
-            assertSameType<GenericEnum>(datum, n);
-            return;
-        default:
-            return;
-        }
-    } else {
-        typeMismatch(datum.type(), n->type());
-    }
+    read(g, d, dynamic_cast<ResolvingDecoder*>(&d) != 0);
 }
 
 GenericWriter::GenericWriter(const ValidSchema& s, const EncoderPtr& encoder) :
@@ -301,50 +242,15 @@ GenericWriter::GenericWriter(const Valid
 
 void GenericWriter::write(const GenericDatum& datum) const
 {
-    write(datum, schema_.root(), *encoder_);
+    write(datum, *encoder_);
 }
 
-static size_t selectBranch(const GenericDatum& datum, const NodePtr& n)
+void GenericWriter::write(const GenericDatum& datum, Encoder& e)
 {
-    size_t c = n->leaves();
-    for (size_t i = 0; i < c; ++i) {
-        const NodePtr& nn = n->leafAt(i);
-        if (datum.type() == nn->type()) {
-            switch (datum.type()) {
-            case AVRO_FIXED:
-                if (hasSameName<GenericFixed>(datum, nn)) return i;
-                break;
-            case AVRO_RECORD:
-                if (hasSameName<GenericRecord>(datum, nn)) return i;
-                break;
-            case AVRO_ENUM:
-                if (hasSameName<GenericEnum>(datum, nn)) return i;
-                break;
-            default:
-                return i;
-            }
-        }
-    }
-    ostringstream oss;
-    n->printJson(oss, 0);
-    throw Exception(boost::format("No match for %1% in %2%") %
-        toString(datum.type()) % oss.str());
-}
-
-void GenericWriter::write(const GenericDatum& datum,
-    const NodePtr& n, Encoder& e)
-{
-    NodePtr nn = n;
-    if (nn->type() == AVRO_UNION) {
-        size_t br = selectBranch(datum, nn);
-        e.encodeUnionIndex(br);
-        nn = nn->leafAt(br);
-    }
-    if (nn->type() == AVRO_SYMBOLIC) {
-        nn = static_cast<NodeSymbolic&>(*nn).getNode();
+    if (datum.isUnion()) {
+        e.encodeUnionIndex(datum.unionBranch());
     }
-    assertType(datum, nn);
-    switch (nn->type()) {
+    switch (datum.type()) {
     case AVRO_NULL:
         e.encodeNull();
         break;
@@ -375,9 +281,9 @@ void GenericWriter::write(const GenericD
     case AVRO_RECORD:
         {
             const GenericRecord& r = datum.value<GenericRecord>();
-            size_t c = nn->leaves();
+            size_t c = r.schema()->leaves();
             for (size_t i = 0; i < c; ++i) {
-                write(r.fieldAt(i), nn->leafAt(i), e);
+                write(r.fieldAt(i), e);
             }
         }
         break;
@@ -393,7 +299,7 @@ void GenericWriter::write(const GenericD
                 for (GenericArray::Value::const_iterator it = r.begin();
                     it != r.end(); ++it) {
                     e.startItem();
-                    write(*it, nn->leafAt(0), e);
+                    write(*it, e);
                 }
             }
             e.arrayEnd();
@@ -409,21 +315,21 @@ void GenericWriter::write(const GenericD
                     it != r.end(); ++it) {
                     e.startItem();
                     e.encodeString(it->first);
-                    write(it->second, nn->leafAt(1), e);
+                    write(it->second, e);
                 }
             }
             e.mapEnd();
         }
         break;
     default:
-        throw Exception("Unknown schema type");
+        throw Exception(boost::format("Unknown schema type %1%") %
+            toString(datum.type()));
     }
 }
 
-void GenericWriter::write(Encoder& e, const GenericDatum& g,
-    const ValidSchema& s)
+void GenericWriter::write(Encoder& e, const GenericDatum& g)
 {
-    write(g, s.root(), e);
+    write(g, e);
 }
 
 }   // namespace avro

Modified: avro/trunk/lang/c++/test/CodecTests.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/test/CodecTests.cc?rev=1187383&r1=1187382&r2=1187383&view=diff
==============================================================================
--- avro/trunk/lang/c++/test/CodecTests.cc (original)
+++ avro/trunk/lang/c++/test/CodecTests.cc Fri Oct 21 15:00:25 2011
@@ -23,6 +23,7 @@
 #include "Compiler.hh"
 #include "ValidSchema.hh"
 #include "Generic.hh"
+#include "Specific.hh"
 
 #include <stdint.h>
 #include <vector>
@@ -762,16 +763,14 @@ void testGeneric(const TestData& td) {
         DecoderPtr d1 = CodecFactory::newDecoder(vs);
         auto_ptr<InputStream> in1 = memoryInputStream(*p);
         d1->init(*in1);
-        GenericReader gr(vs, d1);
-        GenericDatum datum;
-        gr.read(datum);
+        GenericDatum datum(vs);
+        avro::decode(*d1, datum);
 
         EncoderPtr e2 = CodecFactory::newEncoder(vs);
         auto_ptr<OutputStream> ob = memoryOutputStream();
         e2->init(*ob);
 
-        GenericWriter gw(vs, e2);
-        gw.write(datum);
+        avro::encode(*e2, datum);
         e2->flush();
 
         BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
@@ -813,9 +812,7 @@ void testGenericResolving(const TestData
         EncoderPtr e2 = CodecFactory::newEncoder(rvs);
         auto_ptr<OutputStream> ob = memoryOutputStream();
         e2->init(*ob);
-
-        GenericWriter gw(rvs, e2);
-        gw.write(datum);
+        avro::encode(*e2, datum);
         e2->flush();
 
         BOOST_TEST_CHECKPOINT("Test: " << testNo << ' '
@@ -859,9 +856,7 @@ void testGenericResolving2(const TestDat
     EncoderPtr e2 = CodecFactory::newEncoder(rvs);
     auto_ptr<OutputStream> ob = memoryOutputStream();
     e2->init(*ob);
-
-    GenericWriter gw(rvs, e2);
-    gw.write(datum);
+    avro::encode(*e2, datum);
     e2->flush();
     // We cannot verify with the reader calls because they are for
     // the resolving decoder and hence could be in a different order than