Validator.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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(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. size_t 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_ < node->leaves()) {
  92. compoundStack_.pop_back();
  93. setupOperation(node->leafAt(static_cast<int>(count_)));
  94. } else {
  95. throw Exception(
  96. "Union selection out of range, got {}, expecting 0-{}",
  97. count_, node->leaves() - 1);
  98. }
  99. }
  100. }
  101. void Validator::fixedAdvance() {
  102. compoundStarted_ = false;
  103. compoundStack_.pop_back();
  104. }
  105. size_t Validator::nextSizeExpected() const {
  106. return compoundStack_.back().node->fixedSize();
  107. }
  108. void Validator::doAdvance() {
  109. using AdvanceFunc = void (Validator::*)();
  110. // only the compound types need advance functions here
  111. static const AdvanceFunc funcs[] = {
  112. nullptr, // string
  113. nullptr, // bytes
  114. nullptr, // int
  115. nullptr, // long
  116. nullptr, // float
  117. nullptr, // double
  118. nullptr, // bool
  119. nullptr, // null
  120. &Validator::countingAdvance, // Record is treated like counting with count == 1
  121. &Validator::enumAdvance,
  122. &Validator::countingAdvance,
  123. &Validator::countingAdvance,
  124. &Validator::unionAdvance,
  125. &Validator::fixedAdvance};
  126. static_assert((sizeof(funcs) / sizeof(AdvanceFunc)) == (AVRO_NUM_TYPES),
  127. "Invalid number of advance functions");
  128. expectedTypesFlag_ = 0;
  129. // loop until we encounter a next expected type, or we've exited all compound types
  130. while (!expectedTypesFlag_ && !compoundStack_.empty()) {
  131. Type type = compoundStack_.back().node->type();
  132. AdvanceFunc func = funcs[type];
  133. // only compound functions are put on the status stack so it is ok to
  134. // assume that func is not null
  135. assert(func);
  136. ((this)->*(func))();
  137. }
  138. if (compoundStack_.empty()) {
  139. nextType_ = AVRO_NULL;
  140. }
  141. }
  142. void Validator::advance() {
  143. if (!waitingForCount_) {
  144. doAdvance();
  145. }
  146. }
  147. void Validator::setCount(size_t count) {
  148. if (!waitingForCount_) {
  149. throw Exception("Not expecting count");
  150. }
  151. count_ = count;
  152. doAdvance();
  153. }
  154. void Validator::setupFlag(Type type) {
  155. // use flags instead of strictly types, so that we can be more lax about the type
  156. // (for example, a long should be able to accept an int type, but not vice versa)
  157. static const flag_t flags[] = {
  158. typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
  159. typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
  160. typeToFlag(AVRO_INT),
  161. typeToFlag(AVRO_INT) | typeToFlag(AVRO_LONG),
  162. typeToFlag(AVRO_FLOAT),
  163. typeToFlag(AVRO_DOUBLE),
  164. typeToFlag(AVRO_BOOL),
  165. typeToFlag(AVRO_NULL),
  166. typeToFlag(AVRO_RECORD),
  167. typeToFlag(AVRO_ENUM),
  168. typeToFlag(AVRO_ARRAY),
  169. typeToFlag(AVRO_MAP),
  170. typeToFlag(AVRO_UNION),
  171. typeToFlag(AVRO_FIXED)};
  172. static_assert((sizeof(flags) / sizeof(flag_t)) == (AVRO_NUM_TYPES),
  173. "Invalid number of avro type flags");
  174. expectedTypesFlag_ = flags[type];
  175. }
  176. void Validator::setupOperation(const NodePtr &node) {
  177. nextType_ = node->type();
  178. if (nextType_ == AVRO_SYMBOLIC) {
  179. NodePtr actualNode = resolveSymbol(node);
  180. assert(actualNode);
  181. setupOperation(actualNode);
  182. return;
  183. }
  184. assert(nextType_ < AVRO_SYMBOLIC);
  185. setupFlag(nextType_);
  186. if (!isPrimitive(nextType_)) {
  187. compoundStack_.emplace_back(node);
  188. compoundStarted_ = true;
  189. }
  190. }
  191. bool Validator::getCurrentRecordName(std::string &name) const {
  192. auto found = false;
  193. name.clear();
  194. // if the top of the stack is a record I want this record name
  195. auto idx = static_cast<int>(compoundStack_.size() - ((!compoundStack_.empty() && (isPrimitive(nextType_) || nextType_ == AVRO_RECORD)) ? 1 : 2));
  196. if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
  197. name = compoundStack_[idx].node->name().simpleName();
  198. found = true;
  199. }
  200. return found;
  201. }
  202. bool Validator::getNextFieldName(std::string &name) const {
  203. auto found = false;
  204. name.clear();
  205. auto idx = static_cast<int>(compoundStack_.size() - (isCompound(nextType_) ? 2 : 1));
  206. if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
  207. size_t pos = compoundStack_[idx].pos - 1;
  208. const NodePtr &node = compoundStack_[idx].node;
  209. if (pos < node->leaves()) {
  210. name = node->nameAt(pos);
  211. found = true;
  212. }
  213. }
  214. return found;
  215. }
  216. } // namespace avro