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 2012/05/20 18:51:46 UTC

svn commit: r1340768 - in /avro/trunk: ./ lang/c++/ lang/c++/api/ lang/c++/impl/ lang/c++/jsonschemas/ lang/c++/test/

Author: thiru
Date: Sun May 20 16:51:44 2012
New Revision: 1340768

URL: http://svn.apache.org/viewvc?rev=1340768&view=rev
Log:
AVRO-1026. Add namespace support to C++

Added:
    avro/trunk/lang/c++/jsonschemas/tweet
Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/c++/CMakeLists.txt
    avro/trunk/lang/c++/api/Config.hh
    avro/trunk/lang/c++/api/Node.hh
    avro/trunk/lang/c++/api/NodeConcepts.hh
    avro/trunk/lang/c++/api/NodeImpl.hh
    avro/trunk/lang/c++/api/Schema.hh
    avro/trunk/lang/c++/impl/Compiler.cc
    avro/trunk/lang/c++/impl/Node.cc
    avro/trunk/lang/c++/impl/NodeImpl.cc
    avro/trunk/lang/c++/impl/Schema.cc
    avro/trunk/lang/c++/impl/ValidSchema.cc
    avro/trunk/lang/c++/impl/Validator.cc
    avro/trunk/lang/c++/impl/avrogencpp.cc
    avro/trunk/lang/c++/test/AvrogencppTests.cc
    avro/trunk/lang/c++/test/unittest.cc

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Sun May 20 16:51:44 2012
@@ -48,6 +48,7 @@ Avro 1.7.0 (unreleased)
 
     AVRO-1095. C++ compiler warns about control reaching end of doAdavance (in JsonIO.cc) which returns something other than void. (thiru)
 
+    AVRO-1026. Add namespace support to C++. (Keh-Li Sheng via thiru)
   BUG FIXES
 
     AVRO-1045. Java: Fix a bug in GenericData#deepCopy() of ByteBuffer values.

Modified: avro/trunk/lang/c++/CMakeLists.txt
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/CMakeLists.txt?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/CMakeLists.txt (original)
+++ avro/trunk/lang/c++/CMakeLists.txt Sun May 20 16:51:44 2012
@@ -124,6 +124,7 @@ endmacro (gen)
 
 gen (bigrecord testgen)
 gen (bigrecord2 testgen2)
+gen (tweet testgen3)
 gen (union_array_union uau)
 gen (union_map_union umu)
 gen (union_conflict uc)
@@ -158,7 +159,7 @@ if (CYGWIN OR NOT WIN32)
     add_dependencies (testgentest testgen testgen2)
 endif()
 
-add_dependencies (AvrogencppTests bigrecord_hh bigrecord2_hh
+add_dependencies (AvrogencppTests bigrecord_hh bigrecord2_hh tweet_hh
     union_array_union_hh union_map_union_hh union_conflict_hh
     recursive_hh reuse_hh circulardep_hh)
 

Modified: avro/trunk/lang/c++/api/Config.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/Config.hh?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/Config.hh (original)
+++ avro/trunk/lang/c++/api/Config.hh Sun May 20 16:51:44 2012
@@ -22,6 +22,8 @@
 // Windows DLL suport
 
 #ifdef _WIN32
+#pragma warning (disable: 4275 4251)
+
 #if defined(AVRO_DYN_LINK)
 #ifdef AVRO_SOURCE
 # define AVRO_DECL __declspec(dllexport)

Modified: avro/trunk/lang/c++/api/Node.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/Node.hh?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/Node.hh (original)
+++ avro/trunk/lang/c++/api/Node.hh Sun May 20 16:51:44 2012
@@ -19,11 +19,12 @@
 #ifndef avro_Node_hh__
 #define avro_Node_hh__
 
+#include "Config.hh"
+
 #include <cassert>
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include "Config.hh"
 #include "Exception.hh"
 #include "Types.hh"
 #include "SchemaResolution.hh"
@@ -34,6 +35,39 @@ class Node;
 
 typedef boost::shared_ptr<Node> NodePtr;
 
+class AVRO_DECL Name {
+    std::string ns_;
+    std::string simpleName_;
+public:
+    Name() { }
+    Name(const std::string& fullname);
+    Name(const std::string& simpleName, const std::string& ns) : ns_(ns), simpleName_(simpleName) { check(); }
+
+    const std::string fullname() const;
+    const std::string& ns() const { return ns_; }
+    const std::string& simpleName() const { return simpleName_; }
+
+    void ns(const std::string& n) { ns_ = n; }
+    void simpleName(const std::string& n) { simpleName_ = n; }
+    void fullname(const std::string& n);
+
+    bool operator < (const Name& n) const;
+    void check() const;
+    bool operator == (const Name& n) const;
+    bool operator != (const Name& n) const { return !((*this) == n); }
+    void clear() {
+        ns_.clear();
+        simpleName_.clear();
+    }
+    operator std::string() const {
+        return fullname();
+    }
+};
+
+inline
+std::ostream& operator << (std::ostream& os, const Name& n) {
+    return os << n.fullname();
+}
 
 /// Node is the building block for parse trees.  Each node represents an avro
 /// type.  Compound types have leaf nodes that represent the types they are
@@ -75,12 +109,12 @@ class AVRO_DECL Node : private boost::no
 
     virtual bool hasName() const = 0;
 
-    void setName(const std::string &name) {
+    void setName(const Name &name) {
         checkLock();
         checkName(name);
         doSetName(name);
     }
-    virtual const std::string &name() const = 0;
+    virtual const Name &name() const = 0;
 
     void addLeaf(const NodePtr &newLeaf) {
         checkLock();
@@ -122,9 +156,11 @@ class AVRO_DECL Node : private boost::no
         }
     }
 
-    void checkName(const std::string &name) const;
+    virtual void checkName(const Name &name) const {
+        name.check();
+    }
 
-    virtual void doSetName(const std::string &name) = 0;
+    virtual void doSetName(const Name &name) = 0;
     virtual void doAddLeaf(const NodePtr &newLeaf) = 0;
     virtual void doAddName(const std::string &name) = 0;
     virtual void doSetFixedSize(int size) = 0;

Modified: avro/trunk/lang/c++/api/NodeConcepts.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/NodeConcepts.hh?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/NodeConcepts.hh (original)
+++ avro/trunk/lang/c++/api/NodeConcepts.hh Sun May 20 16:51:44 2012
@@ -19,9 +19,10 @@
 #ifndef avro_NodeConcepts_hh__
 #define avro_NodeConcepts_hh__
 
+#include "Config.hh"
+
 #include <vector>
 #include <map>
-#include "Config.hh"
 #include "Exception.hh"
 
 namespace avro {
@@ -72,6 +73,13 @@ struct NoAttribute
         return empty;
     }
 
+    Attribute &get(size_t index = 0) {
+        // There must be an get function for the generic NodeImpl, but the
+        // Node APIs ensure that it is never called, the throw here is
+        // just in case
+        throw Exception("This type does not have attribute");
+    }
+
 };
 
 template<typename Attribute>
@@ -79,47 +87,45 @@ struct SingleAttribute
 {
     static const bool hasAttribute = true;
 
-    SingleAttribute() : attr_(), size_(0)
+    SingleAttribute() : attr_()
     { }
 
-    SingleAttribute(const Attribute& a) : attr_(a), size_(1) { }
+    SingleAttribute(const Attribute& a) : attr_(a) { }
     // copy constructing from another single attribute is allowed
     SingleAttribute(const SingleAttribute<Attribute> &rhs) : 
-        attr_(rhs.attr_), size_(rhs.size_)
+        attr_(rhs.attr_)
     { }
 
     // copy constructing from a no attribute is allowed
     SingleAttribute(const NoAttribute<Attribute> &rhs) : 
-        attr_(), size_(0)
+        attr_()
     { }
 
     size_t size() const {
-        return size_;
+        return 1;
     }
 
     void add(const Attribute &attr) {
-        if(size_ == 0) {
-            size_ = 1;
-        }
-        else {
-            throw Exception("SingleAttribute can only be set once");
-        }
         attr_ = attr;
     }
 
     const Attribute &get(size_t index = 0) const {
-        if(index != 0) {
+        if (index != 0) {
             throw Exception("SingleAttribute has only 1 value");
         }
         return attr_;
     }
 
-  private:
+    Attribute &get(size_t index = 0) {
+        if (index != 0) {
+            throw Exception("SingleAttribute has only 1 value");
+        }
+        return attr_;
+    }
 
+private:
     template<typename T> friend struct MultiAttribute;
-
     Attribute attr_;
-    int       size_;
 };
 
 template<typename Attribute>

Modified: avro/trunk/lang/c++/api/NodeImpl.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/NodeImpl.hh?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/NodeImpl.hh (original)
+++ avro/trunk/lang/c++/api/NodeImpl.hh Sun May 20 16:51:44 2012
@@ -19,11 +19,12 @@
 #ifndef avro_NodeImpl_hh__
 #define avro_NodeImpl_hh__
 
+#include "Config.hh"
+
 #include <limits>
 #include <set>
 #include <boost/weak_ptr.hpp>
 
-#include "Config.hh"
 #include "Node.hh"
 #include "NodeConcepts.hh"
 
@@ -71,15 +72,16 @@ class NodeImpl : public Node
         std::swap(sizeAttribute_, impl.sizeAttribute_);
         std::swap(nameIndex_, impl.nameIndex_);
     }
+
     bool hasName() const {
         return NameConcept::hasAttribute;
     }
 
-    void doSetName(const std::string &name) {
+    void doSetName(const Name &name) {
         nameAttribute_.add(name);
     }
     
-    const std::string &name() const {
+    const Name &name() const {
         return nameAttribute_.get();
     }
 
@@ -96,7 +98,7 @@ class NodeImpl : public Node
     }
 
     void doAddName(const std::string &name) { 
-        if(! nameIndex_.add(name, leafNameAttributes_.size())) {
+        if (! nameIndex_.add(name, leafNameAttributes_.size())) {
             throw Exception(boost::format("Cannot add duplicate name: %1%") % name);
         }
         leafNameAttributes_.add(name);
@@ -128,7 +130,42 @@ class NodeImpl : public Node
 
     void setLeafToSymbolic(int index, const NodePtr &node);
    
-    SchemaResolution furtherResolution(const Node &node) const;
+    SchemaResolution furtherResolution(const Node &reader) const {
+        SchemaResolution match = RESOLVE_NO_MATCH;
+
+        if (reader.type() == AVRO_SYMBOLIC) {
+    
+            // resolve the symbolic type, and check again
+            const NodePtr &node = reader.leafAt(0);
+            match = resolve(*node);
+        }
+        else if(reader.type() == AVRO_UNION) {
+
+            // in this case, need to see if there is an exact match for the
+            // writer's type, or if not, the first one that can be promoted to a
+            // match
+        
+            for(size_t i= 0; i < reader.leaves(); ++i)  {
+
+                const NodePtr &node = reader.leafAt(i);
+                SchemaResolution thisMatch = resolve(*node);
+
+                // if matched then the search is done
+                if(thisMatch == RESOLVE_MATCH) {
+                    match = thisMatch;
+                    break;
+                }
+
+                // thisMatch is either no match, or promotable, this will set match to 
+                // promotable if it hasn't been set already
+                if (match == RESOLVE_NO_MATCH) {
+                    match = thisMatch;
+                }
+            }
+        }
+
+        return match;
+    }
 
     NameConcept nameAttribute_;
     LeavesConcept leafAttributes_;
@@ -137,8 +174,8 @@ class NodeImpl : public Node
     concepts::NameIndexConcept<LeafNamesConcept> nameIndex_;
 };
 
-typedef concepts::NoAttribute<std::string>     NoName;
-typedef concepts::SingleAttribute<std::string> HasName;
+typedef concepts::NoAttribute<Name>     NoName;
+typedef concepts::SingleAttribute<Name> HasName;
 
 typedef concepts::NoAttribute<NodePtr>      NoLeaves;
 typedef concepts::SingleAttribute<NodePtr>  SingleLeaf;
@@ -398,7 +435,7 @@ class AVRO_DECL NodeUnion : public NodeI
                 case AVRO_UNION:
                 case AVRO_FIXED:
                 case AVRO_SYMBOLIC:
-                    name = n->name();
+                    name = n->name().fullname();
                     break;
                 default:
                     return false;
@@ -465,8 +502,9 @@ NodeImpl<A,B,C,D>::printBasicInfo(std::o
 {
     os << type();
     if(hasName()) {
-        os << " " << nameAttribute_.get();
+        os << ' ' << nameAttribute_.get();
     }
+
     if(D::hasAttribute) {
         os << " " << sizeAttribute_.get();
     }

Modified: avro/trunk/lang/c++/api/Schema.hh
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/api/Schema.hh?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/api/Schema.hh (original)
+++ avro/trunk/lang/c++/api/Schema.hh Sun May 20 16:51:44 2012
@@ -133,7 +133,7 @@ public:
 
 class AVRO_DECL SymbolicSchema : public Schema {
 public:
-    SymbolicSchema(const std::string& name, const NodePtr& link);
+    SymbolicSchema(const Name& name, const NodePtr& link);
 };
 } // namespace avro
 

Modified: avro/trunk/lang/c++/impl/Compiler.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/Compiler.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Compiler.cc (original)
+++ avro/trunk/lang/c++/impl/Compiler.cc Sun May 20 16:51:44 2012
@@ -15,6 +15,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <sstream>
 
 #include "Compiler.hh"
 #include "Types.hh"
@@ -32,7 +33,7 @@ using std::vector;
 
 namespace avro {
 
-typedef map<string, NodePtr> SymbolTable;
+typedef map<Name, NodePtr> SymbolTable;
 
 using json::Entity;
 
@@ -61,7 +62,7 @@ static NodePtr makePrimitive(const std::
     }
 }
 
-static NodePtr makeNode(const json::Entity& e, SymbolTable& st);
+static NodePtr makeNode(const json::Entity& e, SymbolTable& st, const string& ns);
 
 template <typename T>
 concepts::SingleAttribute<T> asSingleAttribute(const T& t)
@@ -71,17 +72,29 @@ concepts::SingleAttribute<T> asSingleAtt
     return n;
 }
 
-static NodePtr makeNode(const std::string& t, SymbolTable& st)
+static bool isFullName(const string& s)
+{
+    return s.find('.') != string::npos;
+}
+    
+static Name getName(const string& name, const string& ns)
+{
+    return (isFullName(name)) ? Name(name) : Name(name, ns);
+}
+
+static NodePtr makeNode(const std::string& t, SymbolTable& st, const string& ns)
 {
     NodePtr result = makePrimitive(t);
     if (result) {
         return result;
     }
-    map<string, NodePtr>::const_iterator it = st.find(t);
+    Name n = getName(t, ns);
+
+    map<Name, NodePtr>::const_iterator it = st.find(n);
     if (it != st.end()) {
-        return NodePtr(new NodeSymbolic(asSingleAttribute(t), it->second));
+        return NodePtr(new NodeSymbolic(asSingleAttribute(n), it->second));
     }
-    throw Exception(boost::format("Unknown type: %1%") % t);
+    throw Exception(boost::format("Unknown type: %1%") % n.fullname());
 }
 
 const map<string, Entity>::const_iterator findField(const Entity& e,
@@ -117,22 +130,23 @@ struct Field {
     Field(const string& n, const NodePtr& v) : name(n), value(v) { }
 };
 
-static Field makeField(const Entity& e, SymbolTable& st)
+static Field makeField(const Entity& e, SymbolTable& st, const string& ns)
 {
     const map<string, Entity>& m = e.value<map<string, Entity> >();
     const string& n = getField<string>(e, m, "name");
     map<string, Entity>::const_iterator it = findField(e, m, "type");
-    return Field(n, makeNode(it->second, st));
+    return Field(n, makeNode(it->second, st, ns));
 }
 
 static NodePtr makeRecordNode(const Entity& e,
-    const string& name, const map<string, Entity>& m, SymbolTable& st)
-{
+    const Name& name, const map<string, Entity>& m, SymbolTable& st, const string& ns)
+{        
     const vector<Entity>& v = getField<vector<Entity> >(e, m, "fields");
     concepts::MultiAttribute<string> fieldNames;
     concepts::MultiAttribute<NodePtr> fieldValues;
+    
     for (vector<Entity>::const_iterator it = v.begin(); it != v.end(); ++it) {
-        Field f = makeField(*it, st);
+        Field f = makeField(*it, st, ns);
         fieldNames.add(f.name);
         fieldValues.add(f.value);
     }
@@ -141,7 +155,7 @@ static NodePtr makeRecordNode(const Enti
 }
 
 static NodePtr makeEnumNode(const Entity& e,
-    const string& name, const map<string, Entity>& m)
+    const Name& name, const map<string, Entity>& m)
 {
     const vector<Entity>& v = getField<vector<Entity> >(e, m, "symbols");
     concepts::MultiAttribute<string> symbols;
@@ -156,37 +170,58 @@ static NodePtr makeEnumNode(const Entity
 }
 
 static NodePtr makeFixedNode(const Entity& e,
-    const string& name, const map<string, Entity>& m)
+    const Name& name, const map<string, Entity>& m)
 {
     int v = static_cast<int>(getField<int64_t>(e, m, "size"));
     if (v <= 0) {
         throw Exception(boost::format("Size for fixed is not positive: ") %
             e.toString());
     }
-    
     return NodePtr(new NodeFixed(asSingleAttribute(name),
         asSingleAttribute(v)));
 }
 
 static NodePtr makeArrayNode(const Entity& e, const map<string, Entity>& m,
-    SymbolTable& st)
+    SymbolTable& st, const string& ns)
 {
     map<string, Entity>::const_iterator it = findField(e, m, "items");
     return NodePtr(new NodeArray(asSingleAttribute(
-        makeNode(it->second, st))));
+        makeNode(it->second, st, ns))));
 }
 
 static NodePtr makeMapNode(const Entity& e, const map<string, Entity>& m,
-    SymbolTable& st)
+    SymbolTable& st, const string& ns)
 {
     map<string, Entity>::const_iterator it = findField(e, m, "values");
 
     return NodePtr(new NodeMap(asSingleAttribute(
-        makeNode(it->second, st))));
+        makeNode(it->second, st, ns))));
+}
+
+static Name getName(const Entity& e, const map<string, Entity>& m, const string& ns)
+{
+    const string& name = getField<string>(e, m, "name");
+
+    if (isFullName(name)) {
+        return Name(name);
+    } else {
+        map<string, Entity>::const_iterator it = m.find("namespace");
+        if (it != m.end()) {
+            if (it->second.type() != json::type_traits<string>::type()) {
+                throw Exception(boost::format(
+                    "Json field \"%1%\" is not a %2%: %3%") %
+                        "namespace" % json::type_traits<string>::name() %
+                        it->second.toString());
+            }
+            Name result = Name(name, it->second.value<string>());
+            return result;
+        }
+        return Name(name, ns);
+    }
 }
 
 static NodePtr makeNode(const Entity& e, const map<string, Entity>& m,
-    SymbolTable& st)
+    SymbolTable& st, const string& ns)
 {
     const string& type = getField<string>(e, m, "type");
     if (NodePtr result = makePrimitive(type)) {
@@ -199,48 +234,48 @@ static NodePtr makeNode(const Entity& e,
         }
     } else if (type == "record" || type == "error" ||
         type == "enum" || type == "fixed") {
-        const string& name = getField<string>(e, m, "name");
+        Name nm = getName(e, m, ns);
         NodePtr result;
         if (type == "record" || type == "error") {
             result = NodePtr(new NodeRecord());
-            st[name] = result;
-            NodePtr r = makeRecordNode(e, name, m, st);
+            st[nm] = result;
+            NodePtr r = makeRecordNode(e, nm, m, st, nm.ns());
             (boost::dynamic_pointer_cast<NodeRecord>(r))->swap(
                 *boost::dynamic_pointer_cast<NodeRecord>(result));
         } else {
-            result = (type == "enum") ? makeEnumNode(e, name, m) :
-                makeFixedNode(e, name, m);
-            st[name] = result;
+            result = (type == "enum") ? makeEnumNode(e, nm, m) :
+                makeFixedNode(e, nm, m);
+            st[nm] = result;
         }
         return result;
     } else if (type == "array") {
-        return makeArrayNode(e, m, st);
+        return makeArrayNode(e, m, st, ns);
     } else if (type == "map") {
-        return makeMapNode(e, m, st);
+        return makeMapNode(e, m, st, ns);
     }
     throw Exception(boost::format("Unknown type definition: %1%")
         % e.toString());
 }
 
 static NodePtr makeNode(const Entity& e, const vector<Entity>& m,
-    SymbolTable& st)
+    SymbolTable& st, const string& ns)
 {
     concepts::MultiAttribute<NodePtr> mm;
     for (vector<Entity>::const_iterator it = m.begin(); it != m.end(); ++it) {
-        mm.add(makeNode(*it, st));
+        mm.add(makeNode(*it, st, ns));
     }
     return NodePtr(new NodeUnion(mm));
 }
 
-static NodePtr makeNode(const json::Entity& e, SymbolTable& st)
+static NodePtr makeNode(const json::Entity& e, SymbolTable& st, const string& ns)
 {
     switch (e.type()) {
     case json::etString:
-        return makeNode(e.value<string>(), st);
+        return makeNode(e.value<string>(), st, ns);
     case json::etObject:
-        return makeNode(e, e.value<map<string, Entity> >(), st);
+        return makeNode(e, e.value<map<string, Entity> >(), st, ns);
     case json::etArray:
-        return makeNode(e, e.value<vector<Entity> >(), st);
+        return makeNode(e, e.value<vector<Entity> >(), st, ns);
     default:
         throw Exception(boost::format("Invalid Avro type: %1%") % e.toString());
     }
@@ -250,7 +285,7 @@ AVRO_DECL ValidSchema compileJsonSchemaF
 {
     json::Entity e = json::loadEntity(is);
     SymbolTable st;
-    NodePtr n = makeNode(e, st);
+    NodePtr n = makeNode(e, st, "");
     return ValidSchema(n);
 }
 

Modified: avro/trunk/lang/c++/impl/Node.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/Node.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Node.cc (original)
+++ avro/trunk/lang/c++/impl/Node.cc Sun May 20 16:51:44 2012
@@ -25,17 +25,59 @@ using std::string;
 Node::~Node()
 { }
 
-void 
-Node::checkName(const std::string &name) const
+Name::Name(const std::string& name)
 {
-    string::const_iterator it = name.begin();
-    if (it != name.end() && (isalpha(*it) || *it == '_')) {
-        while ((++it != name.end()) && (isalnum(*it) || *it == '_'));
-        if (it == name.end()) {
-            return;
-        }
+    fullname(name);
+}
+
+const string Name::fullname() const
+{
+    return (ns_.empty()) ? simpleName_ : ns_ + "." + simpleName_;
+}
+
+void Name::fullname(const string& name)
+{
+    string::size_type n = name.find_last_of('.');
+    if (n == string::npos) {
+        simpleName_ = name;
+        ns_.clear();
+    } else {
+        ns_ = name.substr(0, n);
+        simpleName_ = name.substr(n + 1);
     }
-    throw Exception("Names must match [A-Za-z_][A-Za-z0-9_]*");
+    check();
+}
+
+bool Name::operator < (const Name& n) const
+{
+    return (ns_ < n.ns_) ? true :
+        (n.ns_ < ns_) ? false :
+        (simpleName_ < n.simpleName_);
+}
+
+static bool invalidChar1(char c)
+{
+    return !isalnum(c) && c != '_' && c != '.';
+}
+
+static bool invalidChar2(char c)
+{
+    return !isalnum(c) && c != '_';
+}
+
+void Name::check() const
+{
+    if (! ns_.empty() && (ns_[0] == '.' || ns_[ns_.size() - 1] == '.' || std::find_if(ns_.begin(), ns_.end(), invalidChar1) != ns_.end())) {
+        throw Exception("Invalid namespace: " + ns_);
+    }
+    if (simpleName_.empty() || std::find_if(simpleName_.begin(), simpleName_.end(), invalidChar2) != simpleName_.end()) {
+        throw Exception("Invalid name: " + simpleName_);
+    }
+}
+
+bool Name::operator == (const Name& n) const
+{
+    return ns_ == n.ns_ && simpleName_ == n.simpleName_;
 }
 
 } // namespace avro

Modified: avro/trunk/lang/c++/impl/NodeImpl.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/NodeImpl.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/NodeImpl.cc (original)
+++ avro/trunk/lang/c++/impl/NodeImpl.cc Sun May 20 16:51:44 2012
@@ -21,47 +21,6 @@
 
 namespace avro {
 
-
-template < class A, class B, class C, class D >
-SchemaResolution 
-NodeImpl<A,B,C,D>::furtherResolution(const Node &reader) const
-{
-    SchemaResolution match = RESOLVE_NO_MATCH;
-
-    if(reader.type() == AVRO_SYMBOLIC) {
-    
-        // resolve the symbolic type, and check again
-        const NodePtr &node = reader.leafAt(0);
-        match = resolve(*node);
-    }
-    else if(reader.type() == AVRO_UNION) {
-
-        // in this case, need to see if there is an exact match for the
-        // writer's type, or if not, the first one that can be promoted to a
-        // match
-        
-        for(size_t i= 0; i < reader.leaves(); ++i)  {
-
-            const NodePtr &node = reader.leafAt(i);
-            SchemaResolution thisMatch = resolve(*node);
-
-            // if matched then the search is done
-            if(thisMatch == RESOLVE_MATCH) {
-                match = thisMatch;
-                break;
-            }
-
-            // thisMatch is either no match, or promotable, this will set match to 
-            // promotable if it hasn't been set already
-            if (match == RESOLVE_NO_MATCH) {
-                match = thisMatch;
-            }
-        }
-    }
-
-    return match;
-}
-
 SchemaResolution 
 NodePrimitive::resolve(const Node &reader) const
 {
@@ -216,14 +175,20 @@ NodeSymbolic::printJson(std::ostream &os
     os << '\"' << nameAttribute_.get() << '\"';
 }
 
+static void printName(std::ostream& os, const Name& n, int depth)
+{
+    if (!n.ns().empty()) {
+        os << indent(depth) << "\"namespace\": \"" << n.ns() << "\",\n";
+    }
+    os << indent(depth) << "\"name\": \"" << n.simpleName() << "\",\n";
+}
+
 void 
 NodeRecord::printJson(std::ostream &os, int depth) const
 {
     os << "{\n";
     os << indent(++depth) << "\"type\": \"record\",\n";
-    if(!nameAttribute_.get().empty()) {
-        os << indent(depth) << "\"name\": \"" << nameAttribute_.get() << "\",\n";
-    }
+    printName(os, nameAttribute_.get(), depth);
     os << indent(depth) << "\"fields\": [\n";
 
     int fields = leafAttributes_.size();
@@ -249,9 +214,7 @@ NodeEnum::printJson(std::ostream &os, in
 {
     os << "{\n";
     os << indent(++depth) << "\"type\": \"enum\",\n";
-    if(!nameAttribute_.get().empty()) {
-        os << indent(depth) << "\"name\": \"" << nameAttribute_.get() << "\",\n";
-    }
+    printName(os, nameAttribute_.get(), depth);
     os << indent(depth) << "\"symbols\": [\n";
 
     int names = leafNameAttributes_.size();
@@ -312,7 +275,7 @@ NodeFixed::printJson(std::ostream &os, i
     os << "{\n";
     os << indent(++depth) << "\"type\": \"fixed\",\n";
     os << indent(depth) << "\"size\": " << sizeAttribute_.get() << ",\n";
-    os << indent(depth) << "\"name\": \"" << nameAttribute_.get() << "\"\n";
+    printName(os, nameAttribute_.get(), depth);
     os << indent(--depth) << '}';
 }
 

Modified: avro/trunk/lang/c++/impl/Schema.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/Schema.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Schema.cc (original)
+++ avro/trunk/lang/c++/impl/Schema.cc Sun May 20 16:51:44 2012
@@ -108,7 +108,7 @@ FixedSchema::FixedSchema(int size, const
     node_->setName(name);
 }
 
-SymbolicSchema::SymbolicSchema(const std::string &name, const NodePtr& link) :
+SymbolicSchema::SymbolicSchema(const Name &name, const NodePtr& link) :
     Schema(new NodeSymbolic(HasName(name), link))
 {
 }

Modified: avro/trunk/lang/c++/impl/ValidSchema.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/ValidSchema.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/ValidSchema.cc (original)
+++ avro/trunk/lang/c++/impl/ValidSchema.cc Sun May 20 16:51:44 2012
@@ -17,6 +17,7 @@
  */
 
 #include <boost/format.hpp>
+#include <sstream>
 
 #include "ValidSchema.hh"
 #include "Schema.hh"
@@ -30,7 +31,7 @@ using boost::static_pointer_cast;
 
 namespace avro {
 
-typedef std::map<std::string, NodePtr> SymbolMap;
+typedef std::map<Name, NodePtr> SymbolMap;
 
 static bool validate(const NodePtr &node, SymbolMap &symbolMap) 
 {
@@ -40,7 +41,7 @@ static bool validate(const NodePtr &node
     }
 
     if (node->hasName()) {
-        const string& nm = node->name();
+        const Name& nm = node->name();
         SymbolMap::iterator it = symbolMap.find(nm);
         bool found = it != symbolMap.end() && nm == it->first;
 

Modified: avro/trunk/lang/c++/impl/Validator.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/Validator.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/Validator.cc (original)
+++ avro/trunk/lang/c++/impl/Validator.cc Sun May 20 16:51:44 2012
@@ -275,7 +275,7 @@ Validator::getCurrentRecordName(std::str
     }
     
     if(idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
-        name = compoundStack_[idx].node->name();
+        name = compoundStack_[idx].node->name().simpleName();
         found = true;
     }
     return found;

Modified: avro/trunk/lang/c++/impl/avrogencpp.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/impl/avrogencpp.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/impl/avrogencpp.cc (original)
+++ avro/trunk/lang/c++/impl/avrogencpp.cc Sun May 20 16:51:44 2012
@@ -117,6 +117,11 @@ public:
     void generate(const ValidSchema& schema);
 };
 
+static string decorate(const avro::Name& name)
+{
+    return name.simpleName();
+}
+
 string CodeGen::fullname(const string& name) const
 {
     return ns_.empty() ? name : (ns_ + "::" + name);
@@ -124,13 +129,14 @@ string CodeGen::fullname(const string& n
 
 string CodeGen::generateEnumType(const NodePtr& n)
 {
-    os_ << "enum " << n->name() << " {\n";
+    string s = decorate(n->name());
+    os_ << "enum " << s << " {\n";
     size_t c = n->names();
     for (size_t i = 0; i < c; ++i) {
         os_ << "    " << n->nameAt(i) << ",\n";
     }
     os_ << "};\n\n";
-    return n->name();
+    return s;
 }
 
 string CodeGen::cppTypeOf(const NodePtr& n)
@@ -152,7 +158,10 @@ string CodeGen::cppTypeOf(const NodePtr&
         return "bool";
     case avro::AVRO_RECORD:
     case avro::AVRO_ENUM:
-        return inNamespace_ ? n->name() : fullname(n->name());
+        {
+            string nm = decorate(n->name());
+            return inNamespace_ ? nm : fullname(nm);
+        }
     case avro::AVRO_ARRAY:
         return "std::vector<" + cppTypeOf(n->leafAt(0)) + " >";
     case avro::AVRO_MAP:
@@ -189,7 +198,7 @@ static string cppNameOf(const NodePtr& n
     case avro::AVRO_RECORD:
     case avro::AVRO_ENUM:
     case avro::AVRO_FIXED:
-        return n->name();
+        return decorate(n->name());
     case avro::AVRO_ARRAY:
         return "array";
     case avro::AVRO_MAP:
@@ -214,7 +223,7 @@ string CodeGen::generateRecordType(const
         return it->second;
     }
 
-    os_ << "struct " << n->name() << " {\n";
+    os_ << "struct " << decorate(n->name()) << " {\n";
     if (! noUnion_) {
         for (size_t i = 0; i < c; ++i) {
             if (n->leafAt(i)->type() == avro::AVRO_UNION) {
@@ -232,7 +241,7 @@ string CodeGen::generateRecordType(const
         os_ << ' ' << n->nameAt(i) << ";\n";
     }
     os_ << "};\n\n";
-    return n->name();
+    return decorate(n->name());
 }
 
 void makeCanonical(string& s, bool foldCase)
@@ -443,7 +452,7 @@ string CodeGen::generateDeclaration(cons
 
 void CodeGen::generateEnumTraits(const NodePtr& n)
 {
-    string fn = fullname(n->name());
+    string fn = fullname(decorate(n->name()));
     os_ << "template<> struct codec_traits<" << fn << "> {\n"
         << "    static void encode(Encoder& e, " << fn << " v) {\n"
         << "        e.encodeEnum(v);\n"
@@ -461,7 +470,7 @@ void CodeGen::generateRecordTraits(const
         generateTraits(n->leafAt(i));
     }
 
-    string fn = fullname(n->name());
+    string fn = fullname(decorate(n->name()));
     os_ << "template<> struct codec_traits<" << fn << "> {\n"
         << "    static void encode(Encoder& e, const " << fn << "& v) {\n";
 

Added: avro/trunk/lang/c++/jsonschemas/tweet
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/jsonschemas/tweet?rev=1340768&view=auto
==============================================================================
--- avro/trunk/lang/c++/jsonschemas/tweet (added)
+++ avro/trunk/lang/c++/jsonschemas/tweet Sun May 20 16:51:44 2012
@@ -0,0 +1,152 @@
+{
+    "type": "record",
+    "name": "AvroTweet",
+    "namespace": "com.bifflabs.grok.model.twitter.avro",
+    "fields": [{
+        "name": "ID",
+        "type": "long"
+    },
+    {
+        "name": "text",
+        "type": "string"
+    },
+    {
+        "name": "authorScreenName",
+        "type": "string"
+    },
+    {
+        "name": "authorProfileImageURL",
+        "type": "string"
+    },
+    {
+        "name": "authorUserID",
+        "type": ["null", "long"]
+    },
+    {
+        "name": "location",
+        "type": ["null", {
+            "type": "record",
+            "name": "AvroPoint",
+            "namespace": "com.bifflabs.grok.model.common.avro",
+            "fields": [{
+                "name": "latitude",
+                "type": "double"
+            },
+            {
+                "name": "longitude",
+                "type": "double"
+            }]
+        }]
+    },
+    {
+        "name": "placeID",
+        "type": ["null", "string"]
+    },
+    {
+        "name": "createdAt",
+        "type": {
+            "type": "record",
+            "name": "AvroDateTime",
+            "namespace": "com.bifflabs.grok.model.common.avro",
+            "fields": [{
+                "name": "dateTimeString",
+                "type": "string"
+            }]
+        }
+    },
+    {
+        "name": "metadata",
+        "type": {
+            "type": "record",
+            "name": "AvroTweetMetadata",
+            "fields": [{
+                "name": "inReplyToScreenName",
+                "type": {
+                    "type": "record",
+                    "name": "AvroKnowableOptionString",
+                    "namespace": "com.bifflabs.grok.model.common.avro",
+                    "fields": [{
+                        "name": "known",
+                        "type": "boolean"
+                    },
+                    {
+                        "name": "data",
+                        "type": ["null", "string"]
+                    }]
+                }
+            },
+            {
+                "name": "mentionedScreenNames",
+                "type": {
+                    "type": "record",
+                    "name": "AvroKnowableListString",
+                    "namespace": "com.bifflabs.grok.model.common.avro",
+                    "fields": [{
+                        "name": "known",
+                        "type": "boolean"
+                    },
+                    {
+                        "name": "data",
+                        "type": {
+                            "type": "array",
+                            "items": "string"
+                        }
+                    }]
+                }
+            },
+            {
+                "name": "links",
+                "type": "com.bifflabs.grok.model.common.avro.AvroKnowableListString"
+            },            
+            {
+                "name": "hashtags",
+                "type": "com.bifflabs.grok.model.common.avro.AvroKnowableListString"
+            },
+            {
+                "name": "isBareCheckin",
+                "type": {
+                    "type": "record",
+                    "name": "AvroKnowableBoolean",
+                    "namespace": "com.bifflabs.grok.model.common.avro",
+                    "fields": [{
+                        "name": "known",
+                        "type": "boolean"
+                    },
+                    {
+                        "name": "data",
+                        "type": "boolean"
+                    }]
+                }
+            },
+            {
+                "name": "isBareRetweet",
+                "type": "com.bifflabs.grok.model.common.avro.AvroKnowableBoolean"
+            },
+            {
+                "name": "isRetweet",
+                "type": "com.bifflabs.grok.model.common.avro.AvroKnowableBoolean"
+            },
+            {
+                "name": "venueID",
+                "type": "com.bifflabs.grok.model.common.avro.AvroKnowableOptionString"
+            },
+            {
+                "name": "venuePoint",
+                "type": {
+                    "type": "record",
+                    "name": "AvroKnowableOptionPoint",
+                    "namespace": "com.bifflabs.grok.model.common.avro",
+                    "fields": [{
+                        "name": "known",
+                        "type": "boolean"
+                    },
+                    {
+                        "name": "data",
+                        "type": ["null", "AvroPoint"]
+                    }]
+                }
+            }
+            ]
+        }
+    }]
+}
\ No newline at end of file

Modified: avro/trunk/lang/c++/test/AvrogencppTests.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/test/AvrogencppTests.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/test/AvrogencppTests.cc (original)
+++ avro/trunk/lang/c++/test/AvrogencppTests.cc Sun May 20 16:51:44 2012
@@ -18,6 +18,7 @@
 
 #include "bigrecord.hh"
 #include "bigrecord2.hh"
+#include "tweet.hh"
 #include "union_array_union.hh"
 #include "union_map_union.hh"
 #include "union_conflict.hh"
@@ -140,6 +141,21 @@ void testEncoding()
     check(t2, t1);
 }
 
+void testNamespace()
+{
+    ValidSchema s;
+    ifstream ifs("jsonschemas/tweet");
+    // basic compilation should work
+    compileJsonSchema(ifs, s);
+    // an AvroPoint was defined and then referred to from within a namespace
+    testgen3::AvroPoint point;
+    point.latitude = 42.3570;
+    point.longitude = -71.1109;
+    // set it in something that referred to it in the schema
+    testgen3::_tweet_Union__1__ twPoint;
+    twPoint.set_AvroPoint(point);
+}
+
 void setRecord(uau::r1& r)
 {
 }
@@ -199,6 +215,7 @@ init_unit_test_suite(int argc, char* arg
     ts->add(BOOST_TEST_CASE(testEncoding));
     ts->add(BOOST_TEST_CASE(testEncoding2<uau::r1>));
     ts->add(BOOST_TEST_CASE(testEncoding2<umu::r1>));
+    ts->add(BOOST_TEST_CASE(testNamespace));
     return ts;
 }
 

Modified: avro/trunk/lang/c++/test/unittest.cc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/c%2B%2B/test/unittest.cc?rev=1340768&r1=1340767&r2=1340768&view=diff
==============================================================================
--- avro/trunk/lang/c++/test/unittest.cc (original)
+++ avro/trunk/lang/c++/test/unittest.cc Sun May 20 16:51:44 2012
@@ -481,7 +481,7 @@ struct TestNested
         rec.addField("value", LongSchema());
         UnionSchema next;
         next.addType(NullSchema());
-        next.addType(SymbolicSchema("LongList", rec.root()));
+        next.addType(SymbolicSchema(Name("LongList"), rec.root()));
         rec.addField("next", next);
         rec.addField("end", BoolSchema());