00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef avro_NodeImpl_hh__
00020 #define avro_NodeImpl_hh__
00021
00022 #include <limits>
00023 #include <set>
00024 #include <boost/weak_ptr.hpp>
00025
00026 #include "Config.hh"
00027 #include "Node.hh"
00028 #include "NodeConcepts.hh"
00029
00030 namespace avro {
00031
00034
00035 template
00036 <
00037 class NameConcept,
00038 class LeavesConcept,
00039 class LeafNamesConcept,
00040 class SizeConcept
00041 >
00042 class NodeImpl : public Node
00043 {
00044
00045 protected:
00046
00047 NodeImpl(Type type) :
00048 Node(type),
00049 nameAttribute_(),
00050 leafAttributes_(),
00051 leafNameAttributes_(),
00052 sizeAttribute_()
00053 { }
00054
00055 NodeImpl(Type type,
00056 const NameConcept &name,
00057 const LeavesConcept &leaves,
00058 const LeafNamesConcept &leafNames,
00059 const SizeConcept &size) :
00060 Node(type),
00061 nameAttribute_(name),
00062 leafAttributes_(leaves),
00063 leafNameAttributes_(leafNames),
00064 sizeAttribute_(size)
00065 { }
00066
00067 void swap(NodeImpl& impl) {
00068 std::swap(nameAttribute_, impl.nameAttribute_);
00069 std::swap(leafAttributes_, impl.leafAttributes_);
00070 std::swap(leafNameAttributes_, impl.leafNameAttributes_);
00071 std::swap(sizeAttribute_, impl.sizeAttribute_);
00072 std::swap(nameIndex_, impl.nameIndex_);
00073 }
00074 bool hasName() const {
00075 return NameConcept::hasAttribute;
00076 }
00077
00078 void doSetName(const std::string &name) {
00079 nameAttribute_.add(name);
00080 }
00081
00082 const std::string &name() const {
00083 return nameAttribute_.get();
00084 }
00085
00086 void doAddLeaf(const NodePtr &newLeaf) {
00087 leafAttributes_.add(newLeaf);
00088 }
00089
00090 size_t leaves() const {
00091 return leafAttributes_.size();
00092 }
00093
00094 const NodePtr &leafAt(int index) const {
00095 return leafAttributes_.get(index);
00096 }
00097
00098 void doAddName(const std::string &name) {
00099 if(! nameIndex_.add(name, leafNameAttributes_.size())) {
00100 throw Exception(boost::format("Cannot add duplicate name: %1%") % name);
00101 }
00102 leafNameAttributes_.add(name);
00103 }
00104
00105 size_t names() const {
00106 return leafNameAttributes_.size();
00107 }
00108
00109 const std::string &nameAt(int index) const {
00110 return leafNameAttributes_.get(index);
00111 }
00112
00113 bool nameIndex(const std::string &name, size_t &index) const {
00114 return nameIndex_.lookup(name, index);
00115 }
00116
00117 void doSetFixedSize(int size) {
00118 sizeAttribute_.add(size);
00119 }
00120
00121 int fixedSize() const {
00122 return sizeAttribute_.get();
00123 }
00124
00125 virtual bool isValid() const = 0;
00126
00127 void printBasicInfo(std::ostream &os) const;
00128
00129 void setLeafToSymbolic(int index, const NodePtr &node);
00130
00131 SchemaResolution furtherResolution(const Node &node) const;
00132
00133 NameConcept nameAttribute_;
00134 LeavesConcept leafAttributes_;
00135 LeafNamesConcept leafNameAttributes_;
00136 SizeConcept sizeAttribute_;
00137 concepts::NameIndexConcept<LeafNamesConcept> nameIndex_;
00138 };
00139
00140 typedef concepts::NoAttribute<std::string> NoName;
00141 typedef concepts::SingleAttribute<std::string> HasName;
00142
00143 typedef concepts::NoAttribute<NodePtr> NoLeaves;
00144 typedef concepts::SingleAttribute<NodePtr> SingleLeaf;
00145 typedef concepts::MultiAttribute<NodePtr> MultiLeaves;
00146
00147 typedef concepts::NoAttribute<std::string> NoLeafNames;
00148 typedef concepts::MultiAttribute<std::string> LeafNames;
00149
00150 typedef concepts::NoAttribute<int> NoSize;
00151 typedef concepts::SingleAttribute<int> HasSize;
00152
00153 typedef NodeImpl< NoName, NoLeaves, NoLeafNames, NoSize > NodeImplPrimitive;
00154 typedef NodeImpl< HasName, NoLeaves, NoLeafNames, NoSize > NodeImplSymbolic;
00155
00156 typedef NodeImpl< HasName, MultiLeaves, LeafNames, NoSize > NodeImplRecord;
00157 typedef NodeImpl< HasName, NoLeaves, LeafNames, NoSize > NodeImplEnum;
00158 typedef NodeImpl< NoName, SingleLeaf, NoLeafNames, NoSize > NodeImplArray;
00159 typedef NodeImpl< NoName, MultiLeaves, NoLeafNames, NoSize > NodeImplMap;
00160 typedef NodeImpl< NoName, MultiLeaves, NoLeafNames, NoSize > NodeImplUnion;
00161 typedef NodeImpl< HasName, NoLeaves, NoLeafNames, HasSize > NodeImplFixed;
00162
00163 class AVRO_DECL NodePrimitive : public NodeImplPrimitive
00164 {
00165 public:
00166
00167 explicit NodePrimitive(Type type) :
00168 NodeImplPrimitive(type)
00169 { }
00170
00171 SchemaResolution resolve(const Node &reader) const;
00172
00173 void printJson(std::ostream &os, int depth) const;
00174
00175 bool isValid() const {
00176 return true;
00177 }
00178 };
00179
00180 class AVRO_DECL NodeSymbolic : public NodeImplSymbolic
00181 {
00182 typedef boost::weak_ptr<Node> NodeWeakPtr;
00183
00184 public:
00185
00186 NodeSymbolic() :
00187 NodeImplSymbolic(AVRO_SYMBOLIC)
00188 { }
00189
00190 explicit NodeSymbolic(const HasName &name) :
00191 NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize())
00192 { }
00193
00194 NodeSymbolic(const HasName &name, const NodePtr n) :
00195 NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize()), actualNode_(n)
00196 { }
00197 SchemaResolution resolve(const Node &reader) const;
00198
00199 void printJson(std::ostream &os, int depth) const;
00200
00201 bool isValid() const {
00202 return (nameAttribute_.size() == 1);
00203 }
00204
00205 bool isSet() const {
00206 return (actualNode_.lock() != 0);
00207 }
00208
00209 NodePtr getNode() const {
00210 NodePtr node = actualNode_.lock();
00211 if(!node) {
00212 throw Exception(boost::format("Could not follow symbol %1%") % name());
00213 }
00214 return node;
00215 }
00216
00217 void setNode(const NodePtr &node) {
00218 actualNode_ = node;
00219 }
00220
00221 protected:
00222
00223 NodeWeakPtr actualNode_;
00224
00225 };
00226
00227 class AVRO_DECL NodeRecord : public NodeImplRecord
00228 {
00229 public:
00230
00231 NodeRecord() :
00232 NodeImplRecord(AVRO_RECORD)
00233 { }
00234
00235 NodeRecord(const HasName &name, const MultiLeaves &fields, const LeafNames &fieldsNames) :
00236 NodeImplRecord(AVRO_RECORD, name, fields, fieldsNames, NoSize())
00237 {
00238 for(size_t i=0; i < leafNameAttributes_.size(); ++i) {
00239 if(!nameIndex_.add(leafNameAttributes_.get(i), i)) {
00240 throw Exception(boost::format("Cannot add duplicate name: %1%") % leafNameAttributes_.get(i));
00241 }
00242 }
00243 }
00244
00245 void swap(NodeRecord& r) {
00246 NodeImplRecord::swap(r);
00247 }
00248
00249 SchemaResolution resolve(const Node &reader) const;
00250
00251 void printJson(std::ostream &os, int depth) const;
00252
00253 bool isValid() const {
00254 return (
00255 (nameAttribute_.size() == 1) &&
00256 (leafAttributes_.size() > 0) &&
00257 (leafAttributes_.size() == leafNameAttributes_.size())
00258 );
00259 }
00260 };
00261
00262 class AVRO_DECL NodeEnum : public NodeImplEnum
00263 {
00264 public:
00265
00266 NodeEnum() :
00267 NodeImplEnum(AVRO_ENUM)
00268 { }
00269
00270 NodeEnum(const HasName &name, const LeafNames &symbols) :
00271 NodeImplEnum(AVRO_ENUM, name, NoLeaves(), symbols, NoSize())
00272 {
00273 for(size_t i=0; i < leafNameAttributes_.size(); ++i) {
00274 if(!nameIndex_.add(leafNameAttributes_.get(i), i)) {
00275 throw Exception(boost::format("Cannot add duplicate name: %1%") % leafNameAttributes_.get(i));
00276 }
00277 }
00278 }
00279
00280 SchemaResolution resolve(const Node &reader) const;
00281
00282 void printJson(std::ostream &os, int depth) const;
00283
00284 bool isValid() const {
00285 return (
00286 (nameAttribute_.size() == 1) &&
00287 (leafNameAttributes_.size() > 0)
00288 );
00289 }
00290 };
00291
00292 class AVRO_DECL NodeArray : public NodeImplArray
00293 {
00294 public:
00295
00296 NodeArray() :
00297 NodeImplArray(AVRO_ARRAY)
00298 { }
00299
00300 explicit NodeArray(const SingleLeaf &items) :
00301 NodeImplArray(AVRO_ARRAY, NoName(), items, NoLeafNames(), NoSize())
00302 { }
00303
00304 SchemaResolution resolve(const Node &reader) const;
00305
00306 void printJson(std::ostream &os, int depth) const;
00307
00308 bool isValid() const {
00309 return (leafAttributes_.size() == 1);
00310 }
00311 };
00312
00313 class AVRO_DECL NodeMap : public NodeImplMap
00314 {
00315 public:
00316
00317 NodeMap() :
00318 NodeImplMap(AVRO_MAP)
00319 {
00320 NodePtr key(new NodePrimitive(AVRO_STRING));
00321 doAddLeaf(key);
00322 }
00323
00324 explicit NodeMap(const SingleLeaf &values) :
00325 NodeImplMap(AVRO_MAP, NoName(), values, NoLeafNames(), NoSize())
00326 {
00327
00328 NodePtr key(new NodePrimitive(AVRO_STRING));
00329 doAddLeaf(key);
00330
00331
00332 std::swap(leafAttributes_.get(0), leafAttributes_.get(1));
00333 }
00334
00335 SchemaResolution resolve(const Node &reader) const;
00336
00337 void printJson(std::ostream &os, int depth) const;
00338
00339 bool isValid() const {
00340 return (leafAttributes_.size() == 2);
00341 }
00342 };
00343
00344 class AVRO_DECL NodeUnion : public NodeImplUnion
00345 {
00346 public:
00347
00348 NodeUnion() :
00349 NodeImplUnion(AVRO_UNION)
00350 { }
00351
00352 explicit NodeUnion(const MultiLeaves &types) :
00353 NodeImplUnion(AVRO_UNION, NoName(), types, NoLeafNames(), NoSize())
00354 { }
00355
00356 SchemaResolution resolve(const Node &reader) const;
00357
00358 void printJson(std::ostream &os, int depth) const;
00359
00360 bool isValid() const {
00361 std::set<std::string> seen;
00362 if (leafAttributes_.size() >= 1) {
00363 for (size_t i = 0; i < leafAttributes_.size(); ++i) {
00364 std::string name;
00365 const NodePtr& n = leafAttributes_.get(i);
00366 switch (n->type()) {
00367 case AVRO_STRING:
00368 name = "string";
00369 break;
00370 case AVRO_BYTES:
00371 name = "bytes";
00372 break;
00373 case AVRO_INT:
00374 name = "int";
00375 break;
00376 case AVRO_LONG:
00377 name = "long";
00378 break;
00379 case AVRO_FLOAT:
00380 name = "float";
00381 break;
00382 case AVRO_DOUBLE:
00383 name = "double";
00384 break;
00385 case AVRO_BOOL:
00386 name = "bool";
00387 break;
00388 case AVRO_NULL:
00389 name = "null";
00390 break;
00391 case AVRO_ARRAY:
00392 name = "array";
00393 break;
00394 case AVRO_MAP:
00395 name = "map";
00396 break;
00397 case AVRO_RECORD:
00398 case AVRO_ENUM:
00399 case AVRO_UNION:
00400 case AVRO_FIXED:
00401 case AVRO_SYMBOLIC:
00402 name = n->name();
00403 break;
00404 default:
00405 return false;
00406 }
00407 if (seen.find(name) != seen.end()) {
00408 return false;
00409 }
00410 seen.insert(name);
00411 }
00412 return true;
00413 }
00414 return false;
00415 }
00416 };
00417
00418 class AVRO_DECL NodeFixed : public NodeImplFixed
00419 {
00420 public:
00421
00422 NodeFixed() :
00423 NodeImplFixed(AVRO_FIXED)
00424 { }
00425
00426 NodeFixed(const HasName &name, const HasSize &size) :
00427 NodeImplFixed(AVRO_FIXED, name, NoLeaves(), NoLeafNames(), size)
00428 { }
00429
00430 SchemaResolution resolve(const Node &reader) const;
00431
00432 void printJson(std::ostream &os, int depth) const;
00433
00434 bool isValid() const {
00435 return (
00436 (nameAttribute_.size() == 1) &&
00437 (sizeAttribute_.size() == 1)
00438 );
00439 }
00440 };
00441
00442 template < class A, class B, class C, class D >
00443 inline void
00444 NodeImpl<A,B,C,D>::setLeafToSymbolic(int index, const NodePtr &node)
00445 {
00446 if(!B::hasAttribute) {
00447 throw Exception("Cannot change leaf node for nonexistent leaf");
00448 }
00449
00450 NodePtr &replaceNode = const_cast<NodePtr &>(leafAttributes_.get(index));
00451 if(replaceNode->name() != node->name()) {
00452 throw Exception("Symbolic name does not match the name of the schema it references");
00453 }
00454
00455 NodePtr symbol(new NodeSymbolic);
00456 NodeSymbolic *ptr = static_cast<NodeSymbolic *> (symbol.get());
00457
00458 ptr->setName(node->name());
00459 ptr->setNode(node);
00460 replaceNode.swap(symbol);
00461 }
00462
00463 template < class A, class B, class C, class D >
00464 inline void
00465 NodeImpl<A,B,C,D>::printBasicInfo(std::ostream &os) const
00466 {
00467 os << type();
00468 if(hasName()) {
00469 os << " " << nameAttribute_.get();
00470 }
00471 if(D::hasAttribute) {
00472 os << " " << sizeAttribute_.get();
00473 }
00474 os << '\n';
00475 int count = leaves();
00476 count = count ? count : names();
00477 for(int i= 0; i < count; ++i) {
00478 if( C::hasAttribute ) {
00479 os << "name " << nameAt(i) << '\n';
00480 }
00481 if( type() != AVRO_SYMBOLIC && leafAttributes_.hasAttribute) {
00482 leafAt(i)->printBasicInfo(os);
00483 }
00484 }
00485 if(isCompound(type())) {
00486 os << "end " << type() << '\n';
00487 }
00488 }
00489
00490
00491 inline NodePtr resolveSymbol(const NodePtr &node)
00492 {
00493 if(node->type() != AVRO_SYMBOLIC) {
00494 throw Exception("Only symbolic nodes may be resolved");
00495 }
00496 boost::shared_ptr<NodeSymbolic> symNode = boost::static_pointer_cast<NodeSymbolic>(node);
00497 return symNode->getNode();
00498 }
00499
00500 }
00501
00502 #endif