Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions src/core/jsonschema/frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,8 @@ auto SchemaFrame::reset() -> void {
this->descendants_by_pointer_.clear();
this->potential_sources_by_location_.clear();
this->reachability_graph_.clear();
this->canonical_pointer_.clear();
this->location_to_canonical_.clear();
this->root_.clear();
this->locations_.clear();
this->references_.clear();
Expand Down Expand Up @@ -1679,6 +1681,13 @@ auto SchemaFrame::populate_reachability_graph(
}
}
}

for (const auto &entry : this->locations_) {
auto result = this->canonical_pointer_.emplace(
std::cref(entry.second.pointer), &entry.second.pointer);
this->location_to_canonical_[&entry.second] =
result.second ? &entry.second.pointer : result.first->second;
}
}

auto SchemaFrame::populate_reachability(const Location &base,
Expand All @@ -1693,25 +1702,18 @@ auto SchemaFrame::populate_reachability(const Location &base,

auto &cache = this->reachability_[key];
this->populate_reachability_graph(walker, resolver);

const Location *base_location{&base};
std::vector<const Location *> queue;
std::unordered_set<const Location *> visited;

auto mark_pointer_reachable = [this, &cache](const WeakPointer &pointer) {
auto locations_iterator =
this->pointer_to_location_.find(std::cref(pointer));
if (locations_iterator != this->pointer_to_location_.end()) {
for (const auto *location : locations_iterator->second) {
if (location->type != LocationType::Pointer) {
cache.emplace(std::cref(location->pointer), true);
}
}
}
};

queue.push_back(base_location);
visited.insert(base_location);
mark_pointer_reachable(base_location->pointer);
auto base_canonical_iterator =
this->location_to_canonical_.find(base_location);
if (base_canonical_iterator != this->location_to_canonical_.end()) {
cache.emplace(base_canonical_iterator->second, true);
}

std::size_t queue_index{0};
while (queue_index < queue.size()) {
Expand Down Expand Up @@ -1744,7 +1746,12 @@ auto SchemaFrame::populate_reachability(const Location &base,

visited.insert(edge.target);
queue.push_back(edge.target);
mark_pointer_reachable(edge.target->pointer);

auto target_canonical_iterator =
this->location_to_canonical_.find(edge.target);
if (target_canonical_iterator != this->location_to_canonical_.end()) {
cache.emplace(target_canonical_iterator->second, true);
}
}
}

Expand All @@ -1756,7 +1763,11 @@ auto SchemaFrame::is_reachable(const Location &base, const Location &location,
const SchemaResolver &resolver) const -> bool {
assert(location.type != LocationType::Pointer);
const auto &cache{this->populate_reachability(base, walker, resolver)};
const auto iterator{cache.find(std::cref(location.pointer))};
auto canonical_iterator = this->location_to_canonical_.find(&location);
if (canonical_iterator == this->location_to_canonical_.end()) {
return false;
}
const auto iterator{cache.find(canonical_iterator->second)};
return iterator != cache.end() && iterator->second;
}

Expand Down
10 changes: 7 additions & 3 deletions src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame {
mutable std::unordered_set<std::reference_wrapper<const WeakPointer>,
WeakPointer::Hasher, WeakPointer::Comparator>
pointers_with_non_orphan_;
using ReachabilityCache =
std::unordered_map<std::reference_wrapper<const WeakPointer>, bool,
WeakPointer::Hasher, WeakPointer::Comparator>;
using ReachabilityCache = std::unordered_map<const WeakPointer *, bool>;
struct ReachabilityKey {
const WeakPointer *pointer;
bool orphan;
Expand Down Expand Up @@ -309,6 +307,12 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame {
};
mutable std::unordered_map<const Location *, std::vector<ReachabilityEdge>>
reachability_graph_;
mutable std::unordered_map<std::reference_wrapper<const WeakPointer>,
const WeakPointer *, WeakPointer::Hasher,
WeakPointer::Comparator>
canonical_pointer_;
mutable std::unordered_map<const Location *, const WeakPointer *>
location_to_canonical_;
bool standalone_{false};

auto populate_pointer_to_location() const -> void;
Expand Down