Avro C++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
NodeImpl.hh
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #ifndef avro_NodeImpl_hh__
20 #define avro_NodeImpl_hh__
21 
22 #include "Config.hh"
23 #include "GenericDatum.hh"
24 
25 #include <limits>
26 #include <set>
27 #include <boost/weak_ptr.hpp>
28 
29 #include "Node.hh"
30 #include "NodeConcepts.hh"
31 
32 namespace avro {
33 
36 
37 template
38 <
39  class NameConcept,
40  class LeavesConcept,
41  class LeafNamesConcept,
42  class SizeConcept
43 >
44 class NodeImpl : public Node
45 {
46 
47  protected:
48 
49  NodeImpl(Type type) :
50  Node(type),
51  nameAttribute_(),
52  leafAttributes_(),
53  leafNameAttributes_(),
54  sizeAttribute_()
55  { }
56 
57  NodeImpl(Type type,
58  const NameConcept &name,
59  const LeavesConcept &leaves,
60  const LeafNamesConcept &leafNames,
61  const SizeConcept &size) :
62  Node(type),
63  nameAttribute_(name),
64  leafAttributes_(leaves),
65  leafNameAttributes_(leafNames),
66  sizeAttribute_(size)
67  { }
68 
69  void swap(NodeImpl& impl) {
70  std::swap(nameAttribute_, impl.nameAttribute_);
71  std::swap(leafAttributes_, impl.leafAttributes_);
72  std::swap(leafNameAttributes_, impl.leafNameAttributes_);
73  std::swap(sizeAttribute_, impl.sizeAttribute_);
74  std::swap(nameIndex_, impl.nameIndex_);
75  }
76 
77  bool hasName() const {
78  return NameConcept::hasAttribute;
79  }
80 
81  void doSetName(const Name &name) {
82  nameAttribute_.add(name);
83  }
84 
85  const Name &name() const {
86  return nameAttribute_.get();
87  }
88 
89  void doAddLeaf(const NodePtr &newLeaf) {
90  leafAttributes_.add(newLeaf);
91  }
92 
93  size_t leaves() const {
94  return leafAttributes_.size();
95  }
96 
97  const NodePtr &leafAt(int index) const {
98  return leafAttributes_.get(index);
99  }
100 
101  void doAddName(const std::string &name) {
102  if (! nameIndex_.add(name, leafNameAttributes_.size())) {
103  throw Exception(boost::format("Cannot add duplicate name: %1%") % name);
104  }
105  leafNameAttributes_.add(name);
106  }
107 
108  size_t names() const {
109  return leafNameAttributes_.size();
110  }
111 
112  const std::string &nameAt(int index) const {
113  return leafNameAttributes_.get(index);
114  }
115 
116  bool nameIndex(const std::string &name, size_t &index) const {
117  return nameIndex_.lookup(name, index);
118  }
119 
120  void doSetFixedSize(int size) {
121  sizeAttribute_.add(size);
122  }
123 
124  int fixedSize() const {
125  return sizeAttribute_.get();
126  }
127 
128  virtual bool isValid() const = 0;
129 
130  void printBasicInfo(std::ostream &os) const;
131 
132  void setLeafToSymbolic(int index, const NodePtr &node);
133 
134  SchemaResolution furtherResolution(const Node &reader) const {
136 
137  if (reader.type() == AVRO_SYMBOLIC) {
138 
139  // resolve the symbolic type, and check again
140  const NodePtr &node = reader.leafAt(0);
141  match = resolve(*node);
142  }
143  else if(reader.type() == AVRO_UNION) {
144 
145  // in this case, need to see if there is an exact match for the
146  // writer's type, or if not, the first one that can be promoted to a
147  // match
148 
149  for(size_t i= 0; i < reader.leaves(); ++i) {
150 
151  const NodePtr &node = reader.leafAt(i);
152  SchemaResolution thisMatch = resolve(*node);
153 
154  // if matched then the search is done
155  if(thisMatch == RESOLVE_MATCH) {
156  match = thisMatch;
157  break;
158  }
159 
160  // thisMatch is either no match, or promotable, this will set match to
161  // promotable if it hasn't been set already
162  if (match == RESOLVE_NO_MATCH) {
163  match = thisMatch;
164  }
165  }
166  }
167 
168  return match;
169  }
170 
171  NameConcept nameAttribute_;
172  LeavesConcept leafAttributes_;
173  LeafNamesConcept leafNameAttributes_;
174  SizeConcept sizeAttribute_;
176 };
177 
180 
184 
187 
190 
193 
200 
201 class AVRO_DECL NodePrimitive : public NodeImplPrimitive
202 {
203  public:
204 
205  explicit NodePrimitive(Type type) :
206  NodeImplPrimitive(type)
207  { }
208 
209  SchemaResolution resolve(const Node &reader) const;
210 
211  void printJson(std::ostream &os, int depth) const;
212 
213  bool isValid() const {
214  return true;
215  }
216 };
217 
218 class AVRO_DECL NodeSymbolic : public NodeImplSymbolic
219 {
220  typedef boost::weak_ptr<Node> NodeWeakPtr;
221 
222  public:
223 
224  NodeSymbolic() :
225  NodeImplSymbolic(AVRO_SYMBOLIC)
226  { }
227 
228  explicit NodeSymbolic(const HasName &name) :
229  NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize())
230  { }
231 
232  NodeSymbolic(const HasName &name, const NodePtr n) :
233  NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize()), actualNode_(n)
234  { }
235  SchemaResolution resolve(const Node &reader) const;
236 
237  void printJson(std::ostream &os, int depth) const;
238 
239  bool isValid() const {
240  return (nameAttribute_.size() == 1);
241  }
242 
243  bool isSet() const {
244  return (actualNode_.lock() != 0);
245  }
246 
247  NodePtr getNode() const {
248  NodePtr node = actualNode_.lock();
249  if(!node) {
250  throw Exception(boost::format("Could not follow symbol %1%") % name());
251  }
252  return node;
253  }
254 
255  void setNode(const NodePtr &node) {
256  actualNode_ = node;
257  }
258 
259  protected:
260 
261  NodeWeakPtr actualNode_;
262 
263 };
264 
265 class AVRO_DECL NodeRecord : public NodeImplRecord {
266  std::vector<GenericDatum> defaultValues;
267 public:
268  NodeRecord() : NodeImplRecord(AVRO_RECORD) { }
269  NodeRecord(const HasName &name, const MultiLeaves &fields,
270  const LeafNames &fieldsNames,
271  const std::vector<GenericDatum>& dv) :
272  NodeImplRecord(AVRO_RECORD, name, fields, fieldsNames, NoSize()),
273  defaultValues(dv) {
274  for (size_t i = 0; i < leafNameAttributes_.size(); ++i) {
275  if (!nameIndex_.add(leafNameAttributes_.get(i), i)) {
276  throw Exception(boost::format(
277  "Cannot add duplicate name: %1%") %
278  leafNameAttributes_.get(i));
279  }
280  }
281  }
282 
283  void swap(NodeRecord& r) {
284  NodeImplRecord::swap(r);
285  defaultValues.swap(r.defaultValues);
286  }
287 
288  SchemaResolution resolve(const Node &reader) const;
289 
290  void printJson(std::ostream &os, int depth) const;
291 
292  bool isValid() const {
293  return ((nameAttribute_.size() == 1) &&
294  (leafAttributes_.size() == leafNameAttributes_.size()));
295  }
296 
297  const GenericDatum& defaultValueAt(int index) {
298  return defaultValues[index];
299  }
300 };
301 
302 class AVRO_DECL NodeEnum : public NodeImplEnum
303 {
304  public:
305 
306  NodeEnum() :
307  NodeImplEnum(AVRO_ENUM)
308  { }
309 
310  NodeEnum(const HasName &name, const LeafNames &symbols) :
311  NodeImplEnum(AVRO_ENUM, name, NoLeaves(), symbols, NoSize())
312  {
313  for(size_t i=0; i < leafNameAttributes_.size(); ++i) {
314  if(!nameIndex_.add(leafNameAttributes_.get(i), i)) {
315  throw Exception(boost::format("Cannot add duplicate name: %1%") % leafNameAttributes_.get(i));
316  }
317  }
318  }
319 
320  SchemaResolution resolve(const Node &reader) const;
321 
322  void printJson(std::ostream &os, int depth) const;
323 
324  bool isValid() const {
325  return (
326  (nameAttribute_.size() == 1) &&
327  (leafNameAttributes_.size() > 0)
328  );
329  }
330 };
331 
332 class AVRO_DECL NodeArray : public NodeImplArray
333 {
334  public:
335 
336  NodeArray() :
337  NodeImplArray(AVRO_ARRAY)
338  { }
339 
340  explicit NodeArray(const SingleLeaf &items) :
341  NodeImplArray(AVRO_ARRAY, NoName(), items, NoLeafNames(), NoSize())
342  { }
343 
344  SchemaResolution resolve(const Node &reader) const;
345 
346  void printJson(std::ostream &os, int depth) const;
347 
348  bool isValid() const {
349  return (leafAttributes_.size() == 1);
350  }
351 };
352 
353 class AVRO_DECL NodeMap : public NodeImplMap
354 {
355  public:
356 
357  NodeMap() :
358  NodeImplMap(AVRO_MAP)
359  {
360  NodePtr key(new NodePrimitive(AVRO_STRING));
361  doAddLeaf(key);
362  }
363 
364  explicit NodeMap(const SingleLeaf &values) :
365  NodeImplMap(AVRO_MAP, NoName(), values, NoLeafNames(), NoSize())
366  {
367  // need to add the key for the map too
368  NodePtr key(new NodePrimitive(AVRO_STRING));
369  doAddLeaf(key);
370 
371  // key goes before value
372  std::swap(leafAttributes_.get(0), leafAttributes_.get(1));
373  }
374 
375  SchemaResolution resolve(const Node &reader) const;
376 
377  void printJson(std::ostream &os, int depth) const;
378 
379  bool isValid() const {
380  return (leafAttributes_.size() == 2);
381  }
382 };
383 
384 class AVRO_DECL NodeUnion : public NodeImplUnion
385 {
386  public:
387 
388  NodeUnion() :
389  NodeImplUnion(AVRO_UNION)
390  { }
391 
392  explicit NodeUnion(const MultiLeaves &types) :
393  NodeImplUnion(AVRO_UNION, NoName(), types, NoLeafNames(), NoSize())
394  { }
395 
396  SchemaResolution resolve(const Node &reader) const;
397 
398  void printJson(std::ostream &os, int depth) const;
399 
400  bool isValid() const {
401  std::set<std::string> seen;
402  if (leafAttributes_.size() >= 1) {
403  for (size_t i = 0; i < leafAttributes_.size(); ++i) {
404  std::string name;
405  const NodePtr& n = leafAttributes_.get(i);
406  switch (n->type()) {
407  case AVRO_STRING:
408  name = "string";
409  break;
410  case AVRO_BYTES:
411  name = "bytes";
412  break;
413  case AVRO_INT:
414  name = "int";
415  break;
416  case AVRO_LONG:
417  name = "long";
418  break;
419  case AVRO_FLOAT:
420  name = "float";
421  break;
422  case AVRO_DOUBLE:
423  name = "double";
424  break;
425  case AVRO_BOOL:
426  name = "bool";
427  break;
428  case AVRO_NULL:
429  name = "null";
430  break;
431  case AVRO_ARRAY:
432  name = "array";
433  break;
434  case AVRO_MAP:
435  name = "map";
436  break;
437  case AVRO_RECORD:
438  case AVRO_ENUM:
439  case AVRO_UNION:
440  case AVRO_FIXED:
441  case AVRO_SYMBOLIC:
442  name = n->name().fullname();
443  break;
444  default:
445  return false;
446  }
447  if (seen.find(name) != seen.end()) {
448  return false;
449  }
450  seen.insert(name);
451  }
452  return true;
453  }
454  return false;
455  }
456 };
457 
458 class AVRO_DECL NodeFixed : public NodeImplFixed
459 {
460  public:
461 
462  NodeFixed() :
463  NodeImplFixed(AVRO_FIXED)
464  { }
465 
466  NodeFixed(const HasName &name, const HasSize &size) :
467  NodeImplFixed(AVRO_FIXED, name, NoLeaves(), NoLeafNames(), size)
468  { }
469 
470  SchemaResolution resolve(const Node &reader) const;
471 
472  void printJson(std::ostream &os, int depth) const;
473 
474  bool isValid() const {
475  return (
476  (nameAttribute_.size() == 1) &&
477  (sizeAttribute_.size() == 1)
478  );
479  }
480 };
481 
482 template < class A, class B, class C, class D >
483 inline void
484 NodeImpl<A,B,C,D>::setLeafToSymbolic(int index, const NodePtr &node)
485 {
486  if(!B::hasAttribute) {
487  throw Exception("Cannot change leaf node for nonexistent leaf");
488  }
489 
490  NodePtr &replaceNode = const_cast<NodePtr &>(leafAttributes_.get(index));
491  if(replaceNode->name() != node->name()) {
492  throw Exception("Symbolic name does not match the name of the schema it references");
493  }
494 
495  NodePtr symbol(new NodeSymbolic);
496  NodeSymbolic *ptr = static_cast<NodeSymbolic *> (symbol.get());
497 
498  ptr->setName(node->name());
499  ptr->setNode(node);
500  replaceNode.swap(symbol);
501 }
502 
503 template < class A, class B, class C, class D >
504 inline void
505 NodeImpl<A,B,C,D>::printBasicInfo(std::ostream &os) const
506 {
507  os << type();
508  if(hasName()) {
509  os << ' ' << nameAttribute_.get();
510  }
511 
512  if(D::hasAttribute) {
513  os << " " << sizeAttribute_.get();
514  }
515  os << '\n';
516  int count = leaves();
517  count = count ? count : names();
518  for(int i= 0; i < count; ++i) {
519  if( C::hasAttribute ) {
520  os << "name " << nameAt(i) << '\n';
521  }
522  if( type() != AVRO_SYMBOLIC && leafAttributes_.hasAttribute) {
523  leafAt(i)->printBasicInfo(os);
524  }
525  }
526  if(isCompound(type())) {
527  os << "end " << type() << '\n';
528  }
529 }
530 
531 
532 inline NodePtr resolveSymbol(const NodePtr &node)
533 {
534  if(node->type() != AVRO_SYMBOLIC) {
535  throw Exception("Only symbolic nodes may be resolved");
536  }
537  boost::shared_ptr<NodeSymbolic> symNode = boost::static_pointer_cast<NodeSymbolic>(node);
538  return symNode->getNode();
539 }
540 
541 } // namespace avro
542 
543 #endif
Node is the building block for parse trees.
Definition: Node.hh:88
Definition: NodeImpl.hh:302
Definition: Types.hh:37
Definition: Types.hh:45
The schemas match at a cursory level.
Definition: SchemaResolution.hh:38
Definition: Node.hh:39
Definition: Types.hh:40
Type
The "type" for the schema.
Definition: Types.hh:31
A bunch of templates and specializations for encoding and decoding specific types.
Definition: AvroParse.hh:31
Definition: NodeImpl.hh:218
Definition: Types.hh:43
Definition: NodeImpl.hh:332
Definition: Types.hh:39
SchemaResolution
Definition: SchemaResolution.hh:27
Definition: Types.hh:33
Definition: NodeImpl.hh:201
Definition: NodeImpl.hh:353
Definition: NodeConcepts.hh:132
Definition: Types.hh:44
Definition: NodeConcepts.hh:86
Definition: Types.hh:35
Definition: Types.hh:47
Definition: Types.hh:34
The schemas definitely do not match.
Definition: SchemaResolution.hh:31
Definition: Types.hh:38
Wrapper for std::runtime_error that provides convenience constructor for boost::format objects...
Definition: Exception.hh:31
Definition: NodeConcepts.hh:51
Definition: NodeImpl.hh:265
Implementation details for Node.
Definition: NodeImpl.hh:44
Definition: Types.hh:42
Definition: Types.hh:46
Definition: NodeImpl.hh:384
bool isCompound(Type t)
Returns true if and only if the given type is a non primitive valid type.
Definition: Types.hh:72
Definition: Types.hh:36
Definition: Types.hh:53
Generic datum which can hold any Avro type.
Definition: GenericDatum.hh:55
Definition: NodeImpl.hh:458