123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <utility>
- #include "NodeImpl.hh"
- #include "ValidSchema.hh"
- #include "Validator.hh"
- namespace avro {
- Validator::Validator(ValidSchema schema) : schema_(std::move(schema)),
- nextType_(AVRO_NULL),
- expectedTypesFlag_(0),
- compoundStarted_(false),
- waitingForCount_(false),
- count_(0) {
- setupOperation(schema_.root());
- }
- void Validator::setWaitingForCount() {
- waitingForCount_ = true;
- count_ = 0;
- expectedTypesFlag_ = typeToFlag(AVRO_INT) | typeToFlag(AVRO_LONG);
- nextType_ = AVRO_LONG;
- }
- void Validator::enumAdvance() {
- if (compoundStarted_) {
- setWaitingForCount();
- compoundStarted_ = false;
- } else {
- waitingForCount_ = false;
- compoundStack_.pop_back();
- }
- }
- bool Validator::countingSetup() {
- auto proceed = true;
- if (compoundStarted_) {
- setWaitingForCount();
- compoundStarted_ = false;
- proceed = false;
- } else if (waitingForCount_) {
- waitingForCount_ = false;
- if (count_ == 0) {
- compoundStack_.pop_back();
- proceed = false;
- } else {
- counters_.push_back(static_cast<size_t>(count_));
- }
- }
- return proceed;
- }
- void Validator::countingAdvance() {
- if (countingSetup()) {
- size_t index = (compoundStack_.back().pos)++;
- const NodePtr &node = compoundStack_.back().node;
- if (index < node->leaves()) {
- setupOperation(node->leafAt(index));
- } else {
- compoundStack_.back().pos = 0;
- int count = --counters_.back();
- if (count == 0) {
- counters_.pop_back();
- compoundStarted_ = true;
- nextType_ = node->type();
- expectedTypesFlag_ = typeToFlag(nextType_);
- } else {
- index = (compoundStack_.back().pos)++;
- setupOperation(node->leafAt(index));
- }
- }
- }
- }
- void Validator::unionAdvance() {
- if (compoundStarted_) {
- setWaitingForCount();
- compoundStarted_ = false;
- } else {
- waitingForCount_ = false;
- NodePtr node = compoundStack_.back().node;
- if (count_ < static_cast<int64_t>(node->leaves())) {
- compoundStack_.pop_back();
- setupOperation(node->leafAt(static_cast<int>(count_)));
- } else {
- throw Exception(
- boost::format("Union selection out of range, got %1%,"
- " expecting 0-%2%")
- % count_ % (node->leaves() - 1));
- }
- }
- }
- void Validator::fixedAdvance() {
- compoundStarted_ = false;
- compoundStack_.pop_back();
- }
- int Validator::nextSizeExpected() const {
- return compoundStack_.back().node->fixedSize();
- }
- void Validator::doAdvance() {
- using AdvanceFunc = void (Validator::*)();
- // only the compound types need advance functions here
- static const AdvanceFunc funcs[] = {
- nullptr, // string
- nullptr, // bytes
- nullptr, // int
- nullptr, // long
- nullptr, // float
- nullptr, // double
- nullptr, // bool
- nullptr, // null
- &Validator::countingAdvance, // Record is treated like counting with count == 1
- &Validator::enumAdvance,
- &Validator::countingAdvance,
- &Validator::countingAdvance,
- &Validator::unionAdvance,
- &Validator::fixedAdvance};
- static_assert((sizeof(funcs) / sizeof(AdvanceFunc)) == (AVRO_NUM_TYPES),
- "Invalid number of advance functions");
- expectedTypesFlag_ = 0;
- // loop until we encounter a next expected type, or we've exited all compound types
- while (!expectedTypesFlag_ && !compoundStack_.empty()) {
- Type type = compoundStack_.back().node->type();
- AdvanceFunc func = funcs[type];
- // only compound functions are put on the status stack so it is ok to
- // assume that func is not null
- assert(func);
- ((this)->*(func))();
- }
- if (compoundStack_.empty()) {
- nextType_ = AVRO_NULL;
- }
- }
- void Validator::advance() {
- if (!waitingForCount_) {
- doAdvance();
- }
- }
- void Validator::setCount(int64_t count) {
- if (!waitingForCount_) {
- throw Exception("Not expecting count");
- } else if (count_ < 0) {
- throw Exception("Count cannot be negative");
- }
- count_ = count;
- doAdvance();
- }
- void Validator::setupFlag(Type type) {
- // use flags instead of strictly types, so that we can be more lax about the type
- // (for example, a long should be able to accept an int type, but not vice versa)
- static const flag_t flags[] = {
- typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
- typeToFlag(AVRO_STRING) | typeToFlag(AVRO_BYTES),
- typeToFlag(AVRO_INT),
- typeToFlag(AVRO_INT) | typeToFlag(AVRO_LONG),
- typeToFlag(AVRO_FLOAT),
- typeToFlag(AVRO_DOUBLE),
- typeToFlag(AVRO_BOOL),
- typeToFlag(AVRO_NULL),
- typeToFlag(AVRO_RECORD),
- typeToFlag(AVRO_ENUM),
- typeToFlag(AVRO_ARRAY),
- typeToFlag(AVRO_MAP),
- typeToFlag(AVRO_UNION),
- typeToFlag(AVRO_FIXED)};
- static_assert((sizeof(flags) / sizeof(flag_t)) == (AVRO_NUM_TYPES),
- "Invalid number of avro type flags");
- expectedTypesFlag_ = flags[type];
- }
- void Validator::setupOperation(const NodePtr &node) {
- nextType_ = node->type();
- if (nextType_ == AVRO_SYMBOLIC) {
- NodePtr actualNode = resolveSymbol(node);
- assert(actualNode);
- setupOperation(actualNode);
- return;
- }
- assert(nextType_ < AVRO_SYMBOLIC);
- setupFlag(nextType_);
- if (!isPrimitive(nextType_)) {
- compoundStack_.emplace_back(node);
- compoundStarted_ = true;
- }
- }
- bool Validator::getCurrentRecordName(std::string &name) const {
- auto found = false;
- name.clear();
- // if the top of the stack is a record I want this record name
- auto idx = static_cast<int>(compoundStack_.size() - ((!compoundStack_.empty() && (isPrimitive(nextType_) || nextType_ == AVRO_RECORD)) ? 1 : 2));
- if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
- name = compoundStack_[idx].node->name().simpleName();
- found = true;
- }
- return found;
- }
- bool Validator::getNextFieldName(std::string &name) const {
- auto found = false;
- name.clear();
- auto idx = static_cast<int>(compoundStack_.size() - (isCompound(nextType_) ? 2 : 1));
- if (idx >= 0 && compoundStack_[idx].node->type() == AVRO_RECORD) {
- size_t pos = compoundStack_[idx].pos - 1;
- const NodePtr &node = compoundStack_[idx].node;
- if (pos < node->leaves()) {
- name = node->nameAt(pos);
- found = true;
- }
- }
- return found;
- }
- } // namespace avro
|