Validator.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. #include <utility>
  19. #include "NodeImpl.hh"
  20. #include "ValidSchema.hh"
  21. #include "Validator.hh"
  22. namespace avro {
  23. Validator::Validator(ValidSchema schema) : schema_(std::move(schema)),
  24. nextType_(AVRO_NULL),
  25. expectedTypesFlag_(0),
  26. compoundStarted_(false),
  27. waitingForCount_(false),
  28. count_(0) {
  29. setupOperation(schema_.root());
  30. }
  31. void Validator::setWaitingForCount() {
  32. waitingForCount_ = true;
  33. count_ = 0;
  34. expectedTypesFlag_ = typeToFlag(AVRO_INT) | typeToFlag(AVRO_LONG);
  35. nextType_ = AVRO_LONG;
  36. }
  37. void Validator::enumAdvance() {
  38. if (compoundStarted_) {
  39. setWaitingForCount();
  40. compoundStarted_ = false;
  41. } else {
  42. waitingForCount_ = false;
  43. compoundStack_.pop_back();
  44. }
  45. }
  46. bool Validator::countingSetup() {
  47. auto proceed = true;
  48. if (compoundStarted_) {
  49. setWaitingForCount();
  50. compoundStarted_ = false;
  51. proceed = false;
  52. } else if (waitingForCount_) {
  53. waitingForCount_ = false;
  54. if (count_ == 0) {
  55. compoundStack_.pop_back();
  56. proceed = false;
  57. } else {
  58. counters_.push_back(static_cast<size_t>(count_));
  59. }
  60. }
  61. return proceed;
  62. }
  63. void Validator::countingAdvance() {
  64. if (countingSetup()) {
  65. size_t index = (compoundStack_.back().pos)++;
  66. const NodePtr &node = compoundStack_.back().node;
  67. if (index < node->leaves()) {
  68. setupOperation(node->leafAt(index));
  69. } else {
  70. compoundStack_.back().pos = 0;
  71. int count = --counters_.back();
  72. if (count == 0) {
  73. counters_.pop_back();
  74. compoundStarted_ = true;
  75. nextType_ = node->type();
  76. expectedTypesFlag_ = typeToFlag(nextType_);
  77. } else {
  78. index = (compoundStack_.back().pos)++;
  79. setupOperation(node->leafAt(index));
  80. }
  81. }
  82. }
  83. }
  84. void Validator::unionAdvance() {
  85. if (compoundStarted_) {
  86. setWaitingForCount();
  87. compoundStarted_ = false;
  88. } else {
  89. waitingForCount_ = false;
  90. NodePtr node = compoundStack_.back().node;
  91. if (count_ < static_cast<int64_t>(node->leaves())) {
  92. compoundStack_.pop_back();
  93. setupOperation(node->leafAt(static_cast<int>(count_)));
  94. } else {
  95. throw Exception(
  96. boost::format("Union selection out of range, got %1%,"
  97. " expecting 0-%2%")
  98. % count_ % (node->leaves() - 1));
  99. }
  100. }
  101. }
  102. void Validator::fixedAdvance() {
  103. compoundStarted_ = false;
  104. compoundStack_.pop_back();
  105. }
  106. int Validator::nextSizeExpected() const {
  107. return compoundStack_.back().node->fixedSize();
  108. }
  109. void Validator::doAdvance() {
  110. using AdvanceFunc = void (Validator::*)();
  111. // only the compound types need advance functions here
  112. static const AdvanceFunc funcs[] = {
  113. nullptr, // string
  114. nullptr, // bytes
  115. nullptr, // int
  116. nullptr, // long
  117. nullptr, // float
  118. nullptr, // double
  119. nullptr, // bool
  120. nullptr, // null
  121. &Validator::countingAdvance, // Record is treated like counting with count == 1
  122. &Validator::enumAdvance,
  123. &Validator::countingAdvance,
  124. &Validator::countingAdvance,
  125. &Validator::unionAdvance,
  126. &Validator::fixedAdvance};
  127. static_assert((sizeof(funcs) / sizeof(AdvanceFunc)) == (AVRO_NUM_TYPES),
  128. "Invalid number of advance functions");
  129. expectedTypesFlag_ = 0;
  130. // loop until we encounter a next expected type, or we've exited all compound types
  131. while (!expectedTypesFlag_ && !compoundStack_.empty()) {
  132. Type type = compoundStack_.back().node->type();
  133. AdvanceFunc func = funcs[type];
  134. // only compound functions are put on the status stack so it is ok to
  135. // assume that func is not null
  136. assert(func);
  137. ((this)->*(func))();
  138. }
  139. if (compoundStack_.empty()) {
  140. nextType_ = AVRO_NULL;
  141. }
  142. }
  143. void Validator::advance() {
  144. if (!waitingForCount_) {
  145. doAdvance();
  146. }
  147. }
  148. void Validator::setCount(int64_t count) {
  149. if (!waitingForCount_) {
  150. throw Exception("Not expecting count");
  151. } else if (count_ < 0) {
  152. throw Exception("Count cannot be negative");
  153. }
  154. count_ = count;
  155. doAdvance();
  156. }
  157. void Validator::setupFlag(Type type) {
  158. // use flags instead of strictly types, so that we can be more lax about the type
  159. // (for example, a long should be able to accept an int type, but not vice versa)
  160. static const flag_t flags[] = {
  161. typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
  162. typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
  163. typeToFlag(AVRO_INT),
  164. typeToFlag(AVRO_INT) | typeToFlag(AVRO_LONG),
  165. typeToFlag(AVRO_FLOAT),
  166. typeToFlag(AVRO_DOUBLE),
  167. typeToFlag(AVRO_BOOL),
  168. typeToFlag(AVRO_NULL),
  169. typeToFlag(AVRO_RECORD),
  170. typeToFlag(AVRO_ENUM),
  171. typeToFlag(AVRO_ARRAY),
  172. typeToFlag(AVRO_MAP),
  173. typeToFlag(AVRO_UNION),
  174. typeToFlag(AVRO_FIXED)};
  175. static_assert((sizeof(flags) / sizeof(flag_t)) == (AVRO_NUM_TYPES),
  176. "Invalid number of avro type flags");
  177. expectedTypesFlag_ = flags[type];
  178. }
  179. void Validator::setupOperation(const NodePtr &node) {
  180. nextType_ = node->type();
  181. if (nextType_ == AVRO_SYMBOLIC) {
  182. NodePtr actualNode = resolveSymbol(node);
  183. assert(actualNode);
  184. setupOperation(actualNode);
  185. return;
  186. }
  187. assert(nextType_ < AVRO_SYMBOLIC);
  188. setupFlag(nextType_);
  189. if (!isPrimitive(nextType_)) {
  190. compoundStack_.emplace_back(node);
  191. compoundStarted_ = true;
  192. }
  193. }
  194. bool Validator::getCurrentRecordName(std::string &name) const {
  195. auto found = false;
  196. name.clear();
  197. // if the top of the stack is a record I want this record name
  198. auto idx = static_cast<int>(compoundStack_.size() - ((!compoundStack_.empty() && (isPrimitive(nextType_) || nextType_ == AVRO_RECORD)) ? 1 : 2));
  199. if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
  200. name = compoundStack_[idx].node->name().simpleName();
  201. found = true;
  202. }
  203. return found;
  204. }
  205. bool Validator::getNextFieldName(std::string &name) const {
  206. auto found = false;
  207. name.clear();
  208. auto idx = static_cast<int>(compoundStack_.size() - (isCompound(nextType_) ? 2 : 1));
  209. if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
  210. size_t pos = compoundStack_[idx].pos - 1;
  211. const NodePtr &node = compoundStack_[idx].node;
  212. if (pos < node->leaves()) {
  213. name = node->nameAt(pos);
  214. found = true;
  215. }
  216. }
  217. return found;
  218. }
  219. } // namespace avro