diff --git a/src/evaluator/dispatch.inc.h b/src/evaluator/dispatch.inc.h index 62e3640c..3c915f1f 100644 --- a/src/evaluator/dispatch.inc.h +++ b/src/evaluator/dispatch.inc.h @@ -642,7 +642,7 @@ INSTRUCTION_HANDLER(AssertionPropertyTypeEvaluate) { (value == JSON::Type::Integer && target_check->is_integer_real()); if (result) { - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(target_check); } EVALUATE_END(AssertionPropertyTypeEvaluate); @@ -683,7 +683,7 @@ INSTRUCTION_HANDLER(AssertionPropertyTypeStrictEvaluate) { result = target_check->type() == value; if (result) { - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(target_check); } EVALUATE_END(AssertionPropertyTypeStrictEvaluate); @@ -726,7 +726,7 @@ INSTRUCTION_HANDLER(AssertionPropertyTypeStrictAnyEvaluate) { value.cend()); if (result) { - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(target_check); } EVALUATE_END(AssertionPropertyTypeStrictAnyEvaluate); @@ -790,10 +790,12 @@ INSTRUCTION_HANDLER(AssertionArrayPrefixEvaluate) { assert(result); if (array_size == prefixes) { - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + for (const auto &item : target.as_array()) { + evaluator.evaluate(&item); + } } else { for (std::size_t cursor = 0; cursor <= pointer; cursor++) { - evaluator.evaluate({cursor}); + evaluator.evaluate(&target.at(cursor)); } } } @@ -1120,28 +1122,41 @@ INSTRUCTION_HANDLER(ControlEvaluate) { SOURCEMETA_MAYBE_UNUSED(evaluator); EVALUATE_BEGIN_PASS_THROUGH(ControlEvaluate); +#if defined(SOURCEMETA_EVALUATOR_COMPLETE) || \ + defined(SOURCEMETA_EVALUATOR_TRACK) + const auto &value{*std::get_if(&instruction.value)}; + const auto &target{get(instance, value)}; + switch (target.type()) { + case sourcemeta::jsontoolkit::JSON::Type::Object: + for (const auto &property : target.as_object()) { + evaluator.evaluate(&property.second); + } + + break; + case sourcemeta::jsontoolkit::JSON::Type::Array: + for (const auto &item : target.as_array()) { + evaluator.evaluate(&item); + } + + break; + default: + evaluator.evaluate(&target); + break; + } +#endif + #ifdef SOURCEMETA_EVALUATOR_COMPLETE if (callback) { - const auto &value{*std::get_if(&instruction.value)}; // TODO: Optimize this case to avoid an extra pointer copy auto destination = evaluator.instance_location; destination.push_back(value); callback(EvaluationType::Pre, true, instruction, evaluator.evaluate_path, destination, Evaluator::null); - evaluator.evaluate(value); callback(EvaluationType::Post, true, instruction, evaluator.evaluate_path, destination, Evaluator::null); - } else { - const auto &value{*std::get_if(&instruction.value)}; - evaluator.evaluate(value); } #endif -#ifdef SOURCEMETA_EVALUATOR_TRACK - const auto &value{*std::get_if(&instruction.value)}; - evaluator.evaluate(value); -#endif - EVALUATE_END_PASS_THROUGH(ControlEvaluate); } @@ -1297,25 +1312,29 @@ INSTRUCTION_HANDLER(LoopPropertiesUnevaluated) { result = true; for (const auto &entry : target.as_object()) { - if (evaluator.is_evaluated({entry.first})) { + if (evaluator.is_evaluated(&entry.second)) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.push_back(entry.first); +#endif for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif EVALUATE_END(LoopPropertiesUnevaluated); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif + evaluator.evaluate(&entry.second); } - // Mark the entire object as evaluated - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); - EVALUATE_END(LoopPropertiesUnevaluated); } @@ -1337,6 +1356,7 @@ INSTRUCTION_HANDLER(LoopPropertiesUnevaluatedExcept) { for (const auto &entry : target.as_object()) { if (std::get<0>(value).contains(entry.first, entry.hash)) { + evaluator.evaluate(&entry.second); continue; } @@ -1344,6 +1364,7 @@ INSTRUCTION_HANDLER(LoopPropertiesUnevaluatedExcept) { [&entry](const auto &prefix) { return entry.first.starts_with(prefix); })) { + evaluator.evaluate(&entry.second); continue; } @@ -1351,28 +1372,33 @@ INSTRUCTION_HANDLER(LoopPropertiesUnevaluatedExcept) { [&entry](const auto &pattern) { return matches(pattern.first, entry.first); })) { + evaluator.evaluate(&entry.second); continue; } - if (evaluator.is_evaluated({entry.first})) { + if (evaluator.is_evaluated(&entry.second)) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.push_back(entry.first); +#endif for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif EVALUATE_END(LoopPropertiesUnevaluatedExcept); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif + evaluator.evaluate(&entry.second); } - // Mark the entire object as evaluated - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); - EVALUATE_END(LoopPropertiesUnevaluatedExcept); } @@ -1450,22 +1476,31 @@ INSTRUCTION_HANDLER(LoopProperties) { assert(!instruction.children.empty()); result = true; for (const auto &entry : target.as_object()) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopProperties); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopProperties); @@ -1482,25 +1517,34 @@ INSTRUCTION_HANDLER(LoopPropertiesEvaluate) { assert(!instruction.children.empty()); result = true; for (const auto &entry : target.as_object()) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopPropertiesEvaluate); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } - } +#endif - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(&entry.second); + } EVALUATE_END(LoopPropertiesEvaluate); } @@ -1521,22 +1565,31 @@ INSTRUCTION_HANDLER(LoopPropertiesRegex) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopPropertiesRegex); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopPropertiesRegex); @@ -1562,22 +1615,31 @@ INSTRUCTION_HANDLER(LoopPropertiesRegexClosed) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopPropertiesRegexClosed); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopPropertiesRegexClosed); @@ -1599,22 +1661,31 @@ INSTRUCTION_HANDLER(LoopPropertiesStartsWith) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopPropertiesStartsWith); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopPropertiesStartsWith); @@ -1654,22 +1725,31 @@ INSTRUCTION_HANDLER(LoopPropertiesExcept) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, entry.second)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopPropertiesExcept); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopPropertiesExcept); @@ -1744,9 +1824,9 @@ INSTRUCTION_HANDLER(LoopPropertiesTypeEvaluate) { result = false; EVALUATE_END(LoopPropertiesTypeEvaluate); } - } - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(&entry.second); + } EVALUATE_END(LoopPropertiesTypeEvaluate); } @@ -1875,9 +1955,9 @@ INSTRUCTION_HANDLER(LoopPropertiesTypeStrictEvaluate) { result = false; EVALUATE_END(LoopPropertiesTypeStrictEvaluate); } - } - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(&entry.second); + } EVALUATE_END(LoopPropertiesTypeStrictEvaluate); } @@ -1920,9 +2000,9 @@ INSTRUCTION_HANDLER(LoopPropertiesTypeStrictAnyEvaluate) { result = false; EVALUATE_END(LoopPropertiesTypeStrictAnyEvaluate); } - } - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); + evaluator.evaluate(&entry.second); + } EVALUATE_END(LoopPropertiesTypeStrictAnyEvaluate); } @@ -1938,23 +2018,32 @@ INSTRUCTION_HANDLER(LoopKeys) { assert(!instruction.children.empty()); result = true; for (const auto &entry : target.as_object()) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(entry.first); } +#endif + for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE_ON_PROPERTY_NAME(child, Evaluator::null, entry.first)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopKeys); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopKeys); @@ -1983,23 +2072,32 @@ INSTRUCTION_HANDLER(LoopItems) { } #else for (std::size_t index = 0; index < target.array_size(); index++) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(index); } +#endif + const auto &new_instance{target.at(index)}; for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, new_instance)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopItems); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } #endif @@ -2019,23 +2117,32 @@ INSTRUCTION_HANDLER(LoopItemsFrom) { assert(!instruction.children.empty()); result = true; for (std::size_t index = value; index < target.array_size(); index++) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(index); } +#endif + const auto &new_instance{target.at(index)}; for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, new_instance)) { result = false; + +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif + EVALUATE_END(LoopItemsFrom); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif } EVALUATE_END(LoopItemsFrom); @@ -2053,26 +2160,30 @@ INSTRUCTION_HANDLER(LoopItemsUnevaluated) { result = true; for (std::size_t index = 0; index < target.array_size(); index++) { - if (evaluator.is_evaluated(index)) { + const auto &new_instance{target.at(index)}; + if (evaluator.is_evaluated(&new_instance)) { continue; } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.push_back(index); - const auto &new_instance{target.at(index)}; +#endif for (const auto &child : instruction.children) { if (!EVALUATE_RECURSE(child, new_instance)) { result = false; +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif EVALUATE_END(LoopItemsUnevaluated); } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE evaluator.instance_location.pop_back(); +#endif + evaluator.evaluate(&new_instance); } - // Mark the entire array as evaluated - evaluator.evaluate(sourcemeta::jsontoolkit::empty_pointer); - EVALUATE_END(LoopItemsUnevaluated); } @@ -2228,9 +2339,12 @@ INSTRUCTION_HANDLER(LoopContains) { auto match_count{std::numeric_limits::min()}; for (std::size_t index = 0; index < target.array_size(); index++) { +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.push_back(index); } +#endif + const auto &new_instance{target.at(index)}; bool subresult{true}; for (const auto &child : instruction.children) { @@ -2240,9 +2354,11 @@ INSTRUCTION_HANDLER(LoopContains) { } } +#ifdef SOURCEMETA_EVALUATOR_COMPLETE if (track) { evaluator.instance_location.pop_back(); } +#endif if (subresult) { match_count += 1; diff --git a/src/evaluator/evaluator.cc b/src/evaluator/evaluator.cc index b0a91a1c..62f6bef8 100644 --- a/src/evaluator/evaluator.cc +++ b/src/evaluator/evaluator.cc @@ -100,23 +100,16 @@ auto Evaluator::hash(const std::size_t &resource, return resource + this->hasher_(fragment); } -auto Evaluator::evaluate( - const sourcemeta::jsontoolkit::Pointer &relative_instance_location) - -> void { - auto new_instance_location = this->instance_location; - new_instance_location.push_back(relative_instance_location); - Evaluation entry{std::move(new_instance_location), this->evaluate_path, - false}; - this->evaluated_.emplace_back(std::move(entry)); +auto Evaluator::evaluate(const sourcemeta::jsontoolkit::JSON *target) -> void { + Evaluation mark{target, this->evaluate_path, false}; + this->evaluated_.push_back(std::move(mark)); } -auto Evaluator::is_evaluated( - const sourcemeta::jsontoolkit::WeakPointer::Token &tail) const -> bool { +auto Evaluator::is_evaluated(const sourcemeta::jsontoolkit::JSON *target) const + -> bool { for (auto iterator = this->evaluated_.crbegin(); iterator != this->evaluated_.crend(); ++iterator) { - if (!iterator->skip && - this->instance_location.starts_with(iterator->instance_location, - tail) && + if (target == iterator->instance && !iterator->skip && // Its not possible to affect cousins iterator->evaluate_path.starts_with_initial(this->evaluate_path)) { return true; diff --git a/src/evaluator/evaluator_track.h b/src/evaluator/evaluator_track.h index 6f20642c..0b7e5630 100644 --- a/src/evaluator/evaluator_track.h +++ b/src/evaluator/evaluator_track.h @@ -11,8 +11,6 @@ return true; \ } \ evaluator.evaluate_path.push_back(instruction.relative_schema_location); \ - evaluator.instance_location.push_back( \ - instruction.relative_instance_location); \ constexpr bool track{true}; \ SOURCEMETA_MAYBE_UNUSED(track); \ bool result{false}; @@ -25,8 +23,6 @@ return true; \ } \ evaluator.evaluate_path.push_back(instruction.relative_schema_location); \ - evaluator.instance_location.push_back( \ - instruction.relative_instance_location); \ constexpr bool track{true}; \ SOURCEMETA_MAYBE_UNUSED(track); \ bool result{false}; @@ -39,8 +35,6 @@ return true; \ } \ evaluator.evaluate_path.push_back(instruction.relative_schema_location); \ - evaluator.instance_location.push_back( \ - instruction.relative_instance_location); \ const auto &target{*maybe_target}; \ bool result{false}; @@ -58,16 +52,12 @@ return true; \ } \ evaluator.evaluate_path.push_back(instruction.relative_schema_location); \ - evaluator.instance_location.push_back( \ - instruction.relative_instance_location); \ assert(!instruction.relative_instance_location.empty()); \ bool result{false}; #define EVALUATE_BEGIN_NO_PRECONDITION(instruction_type) \ assert(instruction.type == InstructionIndex::instruction_type); \ evaluator.evaluate_path.push_back(instruction.relative_schema_location); \ - evaluator.instance_location.push_back( \ - instruction.relative_instance_location); \ constexpr bool track{true}; \ SOURCEMETA_MAYBE_UNUSED(track); \ bool result{false}; @@ -83,8 +73,6 @@ #define EVALUATE_END(instruction_type) \ evaluator.evaluate_path.pop_back( \ instruction.relative_schema_location.size()); \ - evaluator.instance_location.pop_back( \ - instruction.relative_instance_location.size()); \ return result; #define EVALUATE_END_NO_POP(instruction_type) return result; @@ -114,13 +102,11 @@ inline auto evaluate(const sourcemeta::jsontoolkit::JSON &instance, if (!evaluate_instruction(instruction, schema, nullptr, instance, nullptr, 0, evaluator)) { assert(evaluator.evaluate_path.empty()); - assert(evaluator.instance_location.empty()); return false; } } assert(evaluator.evaluate_path.empty()); - assert(evaluator.instance_location.empty()); return true; } diff --git a/src/evaluator/include/sourcemeta/blaze/evaluator.h b/src/evaluator/include/sourcemeta/blaze/evaluator.h index e9e74912..8be4032f 100644 --- a/src/evaluator/include/sourcemeta/blaze/evaluator.h +++ b/src/evaluator/include/sourcemeta/blaze/evaluator.h @@ -158,12 +158,8 @@ class SOURCEMETA_BLAZE_EVALUATOR_EXPORT Evaluator { const sourcemeta::jsontoolkit::JSON::String &fragment) const noexcept -> std::size_t; - auto - evaluate(const sourcemeta::jsontoolkit::Pointer &relative_instance_location) - -> void; - auto - is_evaluated(const sourcemeta::jsontoolkit::WeakPointer::Token &tail) const - -> bool; + auto evaluate(const sourcemeta::jsontoolkit::JSON *target) -> void; + auto is_evaluated(const sourcemeta::jsontoolkit::JSON *target) const -> bool; auto unevaluate() -> void; // Exporting symbols that depends on the standard C++ library is considered @@ -179,11 +175,8 @@ class SOURCEMETA_BLAZE_EVALUATOR_EXPORT Evaluator { std::map> labels; - // TODO: Revamp the data structure we use to track evaluation - // to provide more performant lookups that don't involve so many - // pointer token string comparisons struct Evaluation { - sourcemeta::jsontoolkit::WeakPointer instance_location; + const sourcemeta::jsontoolkit::JSON *instance; sourcemeta::jsontoolkit::WeakPointer evaluate_path; bool skip; };