NodeConcepts.hh 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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. * https://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. #ifndef avro_NodeConcepts_hh__
  19. #define avro_NodeConcepts_hh__
  20. #include "Config.hh"
  21. #include "Exception.hh"
  22. #include <map>
  23. #include <vector>
  24. namespace avro {
  25. ///
  26. /// The concept classes are used to simplify NodeImpl. Since different types
  27. /// of avro types carry different attributes, such as names, or field names for
  28. /// record members. Using the concept class of NoAttribute vs Attribute, the
  29. /// NodeImpl object can enable/disable the attribute, but the code is the same
  30. /// in either case.
  31. ///
  32. /// Furthermore, attributes may have different types, for example, most
  33. /// attributes are strings, but fixed types have a size attribute, which is
  34. /// integer.
  35. ///
  36. /// Since compound types are composed of other types, the leaf attribute
  37. /// concepts extend a NodeImpl to include leaf nodes, and attributes for leaf
  38. /// nodes, which are used to build parse trees.
  39. ///
  40. ///
  41. namespace concepts {
  42. template<typename Attribute>
  43. struct NoAttribute {
  44. static const bool hasAttribute = false;
  45. size_t size() const {
  46. return 0;
  47. }
  48. void add(const Attribute & /* attr */) {
  49. // There must be an add function for the generic NodeImpl, but the
  50. // Node APIs ensure that it is never called, the throw here is
  51. // just in case
  52. throw Exception("This type does not have attribute");
  53. }
  54. const Attribute &get(size_t /* index */ = 0) const {
  55. // There must be an get function for the generic NodeImpl, but the
  56. // Node APIs ensure that it is never called, the throw here is
  57. // just in case
  58. throw Exception("This type does not have attribute");
  59. }
  60. Attribute &get(size_t /* index */ = 0) {
  61. // There must be an get function for the generic NodeImpl, but the
  62. // Node APIs ensure that it is never called, the throw here is
  63. // just in case
  64. throw Exception("This type does not have attribute");
  65. }
  66. };
  67. template<typename Attribute>
  68. struct SingleAttribute {
  69. static const bool hasAttribute = true;
  70. SingleAttribute() : attr_() {}
  71. explicit SingleAttribute(const Attribute &a) : attr_(a) {}
  72. // copy constructing from another single attribute is allowed
  73. SingleAttribute(const SingleAttribute<Attribute> &rhs) : attr_(rhs.attr_) {}
  74. // copy constructing from a no attribute is allowed
  75. explicit SingleAttribute(const NoAttribute<Attribute> &rhs) : attr_() {}
  76. size_t size() const {
  77. return 1;
  78. }
  79. void add(const Attribute &attr) {
  80. attr_ = attr;
  81. }
  82. const Attribute &get(size_t index = 0) const {
  83. if (index != 0) {
  84. throw Exception("SingleAttribute has only 1 value");
  85. }
  86. return attr_;
  87. }
  88. Attribute &get(size_t index = 0) {
  89. if (index != 0) {
  90. throw Exception("SingleAttribute has only 1 value");
  91. }
  92. return attr_;
  93. }
  94. private:
  95. template<typename T>
  96. friend struct MultiAttribute;
  97. Attribute attr_;
  98. };
  99. template<typename Attribute>
  100. struct MultiAttribute {
  101. static const bool hasAttribute = true;
  102. MultiAttribute() = default;
  103. // copy constructing from another single attribute is allowed, it
  104. // pushes the attribute
  105. explicit MultiAttribute(const SingleAttribute<Attribute> &rhs) {
  106. // since map is the only type that does this we know it's
  107. // final size will be two, so reserve
  108. attrs_.reserve(2);
  109. attrs_.push_back(rhs.attr_);
  110. }
  111. MultiAttribute(const MultiAttribute<Attribute> &rhs) : attrs_(rhs.attrs_) {}
  112. explicit MultiAttribute(const NoAttribute<Attribute> &rhs) {}
  113. size_t size() const {
  114. return attrs_.size();
  115. }
  116. void add(const Attribute &attr) {
  117. attrs_.push_back(attr);
  118. }
  119. const Attribute &get(size_t index = 0) const {
  120. return attrs_.at(index);
  121. }
  122. Attribute &get(size_t index) {
  123. return attrs_.at(index);
  124. }
  125. private:
  126. std::vector<Attribute> attrs_;
  127. };
  128. template<typename T>
  129. struct NameIndexConcept {
  130. bool lookup(const std::string &name, size_t &index) const {
  131. throw Exception("Name index does not exist");
  132. }
  133. bool add(const ::std::string &name, size_t) {
  134. throw Exception("Name index does not exist");
  135. }
  136. };
  137. template<>
  138. struct NameIndexConcept<MultiAttribute<std::string>> {
  139. using IndexMap = std::map<std::string, size_t>;
  140. bool lookup(const std::string &name, size_t &index) const {
  141. auto iter = map_.find(name);
  142. if (iter == map_.end()) {
  143. return false;
  144. }
  145. index = iter->second;
  146. return true;
  147. }
  148. bool add(const ::std::string &name, size_t index) {
  149. bool added = false;
  150. auto lb = map_.lower_bound(name);
  151. if (lb == map_.end() || map_.key_comp()(name, lb->first)) {
  152. map_.insert(lb, IndexMap::value_type(name, index));
  153. added = true;
  154. }
  155. return added;
  156. }
  157. private:
  158. IndexMap map_;
  159. };
  160. } // namespace concepts
  161. } // namespace avro
  162. #endif