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
21 changes: 12 additions & 9 deletions benchmark/jsonschema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,22 @@ static void Schema_Frame_KrakenD_Reachable(benchmark::State &state) {
frame.analyse(schema, sourcemeta::core::schema_walker,
sourcemeta::core::schema_resolver);

const auto &base{frame.traverse(frame.root())->get()};

for (auto _ : state) {
for (const auto &entry : frame.locations()) {
if (entry.second.type ==
sourcemeta::core::SchemaFrame::LocationType::Pointer) {
continue;
sourcemeta::core::SchemaFrame::LocationType::Resource) {
for (const auto &subentry : frame.locations()) {
if (subentry.second.type ==
sourcemeta::core::SchemaFrame::LocationType::Pointer) {
continue;
}

auto result{frame.is_reachable(entry.second, subentry.second,
sourcemeta::core::schema_walker,
sourcemeta::core::schema_resolver)};
benchmark::DoNotOptimize(result);
}
}

auto result{frame.is_reachable(base, entry.second,
sourcemeta::core::schema_walker,
sourcemeta::core::schema_resolver)};
benchmark::DoNotOptimize(result);
}
}
}
Expand Down
62 changes: 46 additions & 16 deletions src/core/jsonschema/frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1435,14 +1435,14 @@ auto SchemaFrame::populate_reachability(const Location &base,
// ---------------------------------------------------------------------------

std::vector<std::reference_wrapper<const WeakPointer>> unreachable_pointers;
std::unordered_set<std::reference_wrapper<const WeakPointer>,
WeakPointer::Hasher, WeakPointer::Comparator>
pointers_with_non_orphan;

if (this->pointer_to_location_.empty()) {
std::unordered_set<std::reference_wrapper<const WeakPointer>,
WeakPointer::Hasher, WeakPointer::Comparator>
has_non_pointer_location;
std::unordered_set<std::reference_wrapper<const WeakPointer>,
WeakPointer::Hasher, WeakPointer::Comparator>
has_non_orphan;

for (const auto &entry : this->locations_) {
auto [iterator, inserted] = this->pointer_to_location_.try_emplace(
Expand All @@ -1451,13 +1451,20 @@ auto SchemaFrame::populate_reachability(const Location &base,
if (entry.second.type != LocationType::Pointer) {
has_non_pointer_location.insert(iterator->first);
if (!entry.second.orphan) {
has_non_orphan.insert(iterator->first);
pointers_with_non_orphan.insert(iterator->first);
}
}
}

for (const auto &pointer_reference : has_non_pointer_location) {
const bool is_reachable = has_non_orphan.contains(pointer_reference);
const auto &pointer{pointer_reference.get()};
bool is_reachable{false};
if (pointer == base.pointer) {
is_reachable = true;
} else if (pointer.starts_with(base.pointer)) {
is_reachable = pointers_with_non_orphan.contains(pointer_reference);
}

cache.emplace(pointer_reference, is_reachable);
if (!is_reachable) {
unreachable_pointers.push_back(pointer_reference);
Expand All @@ -1474,12 +1481,24 @@ auto SchemaFrame::populate_reachability(const Location &base,
continue;
}

const auto any_non_orphan{
const bool has_non_orphan{
std::ranges::any_of(locations, [](const Location *location) {
return location->type != LocationType::Pointer && !location->orphan;
})};
cache.emplace(pointer_reference, any_non_orphan);
if (!any_non_orphan) {
if (has_non_orphan) {
pointers_with_non_orphan.insert(pointer_reference);
}

const auto &pointer{pointer_reference.get()};
bool is_reachable{false};
if (pointer == base.pointer) {
is_reachable = true;
} else if (pointer.starts_with(base.pointer)) {
is_reachable = has_non_orphan;
}

cache.emplace(pointer_reference, is_reachable);
if (!is_reachable) {
unreachable_pointers.push_back(pointer_reference);
}
}
Expand Down Expand Up @@ -1567,7 +1586,8 @@ auto SchemaFrame::populate_reachability(const Location &base,
PotentialReach entry{.pointer = pointer_reference, .potential_sources = {}};

WeakPointer ancestor = pointer;
while (!ancestor.empty()) {
bool first_iteration{true};
while (first_iteration || !ancestor.empty()) {
auto destination_iterator =
references_by_destination.find(std::cref(ancestor));
if (destination_iterator != references_by_destination.end()) {
Expand Down Expand Up @@ -1619,7 +1639,12 @@ auto SchemaFrame::populate_reachability(const Location &base,
.source_pointer = source_pointer, .crosses = crosses});
}
}

if (ancestor.empty()) {
break;
}
ancestor = ancestor.initial();
first_iteration = false;
}

if (!entry.potential_sources.empty()) {
Expand Down Expand Up @@ -1651,13 +1676,10 @@ auto SchemaFrame::populate_reachability(const Location &base,
}

const auto &source_parent{potential_source.source_pointer->initial()};
bool source_parent_reachable{source_parent.empty()};
if (!source_parent_reachable) {
const auto reachability_iterator{
cache.find(std::cref(source_parent))};
source_parent_reachable = reachability_iterator != cache.end() &&
reachability_iterator->second;
}
const auto reachability_iterator{cache.find(std::cref(source_parent))};
const bool source_parent_reachable{reachability_iterator !=
cache.end() &&
reachability_iterator->second};

if (source_parent_reachable) {
became_reachable = true;
Expand All @@ -1666,7 +1688,15 @@ auto SchemaFrame::populate_reachability(const Location &base,
}

if (became_reachable) {
const auto &reached_pointer{read_iterator->pointer.get()};
cache[read_iterator->pointer] = true;
for (auto &[cache_pointer, cache_reachable] : cache) {
if (!cache_reachable &&
cache_pointer.get().starts_with(reached_pointer) &&
pointers_with_non_orphan.contains(cache_pointer)) {
cache_reachable = true;
}
}
changed = true;
} else {
if (write_iterator != read_iterator) {
Expand Down
4 changes: 4 additions & 0 deletions test/jsonschema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ target_link_libraries(sourcemeta_core_jsonschema_unit
target_link_libraries(sourcemeta_core_jsonschema_unit
PRIVATE sourcemeta::core::uri)

if(MSVC)
target_compile_options(sourcemeta_core_jsonschema_unit PRIVATE /bigobj)
endif()

# JSON Schema Referencing Suite
# See https://github.com/python-jsonschema/referencing-suite
sourcemeta_googletest(NAMESPACE sourcemeta PROJECT core NAME jsonschema_referencing_suite
Expand Down
Loading