Skip to content

Commit

Permalink
Add a new Locations mode for framing (#1552)
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti authored Feb 11, 2025
1 parent 9606eec commit 7a2f3cc
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 21 deletions.
44 changes: 25 additions & 19 deletions src/core/jsonschema/frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -523,26 +523,28 @@ auto internal_analyse(const sourcemeta::core::SchemaFrame::Mode mode,
}
}

// Handle metaschema references
const auto maybe_metaschema{
sourcemeta::core::dialect(entry.common.subschema.get())};
if (maybe_metaschema.has_value()) {
sourcemeta::core::URI metaschema{maybe_metaschema.value()};
const auto nearest_bases{
find_nearest_bases(base_uris, entry.common.pointer, entry.id)};
if (!nearest_bases.first.empty()) {
metaschema.try_resolve_from(nearest_bases.first.front());
}
if (mode != SchemaFrame::Mode::Locations) {
// Handle metaschema references
const auto maybe_metaschema{
sourcemeta::core::dialect(entry.common.subschema.get())};
if (maybe_metaschema.has_value()) {
sourcemeta::core::URI metaschema{maybe_metaschema.value()};
const auto nearest_bases{
find_nearest_bases(base_uris, entry.common.pointer, entry.id)};
if (!nearest_bases.first.empty()) {
metaschema.try_resolve_from(nearest_bases.first.front());
}

metaschema.canonicalize();
const std::string destination{metaschema.recompose()};
assert(entry.common.subschema.get().defines("$schema"));
references.insert_or_assign(
{SchemaReferenceType::Static,
entry.common.pointer.concat({"$schema"})},
SchemaFrame::ReferencesEntry{destination,
metaschema.recompose_without_fragment(),
fragment_string(metaschema)});
metaschema.canonicalize();
const std::string destination{metaschema.recompose()};
assert(entry.common.subschema.get().defines("$schema"));
references.insert_or_assign({SchemaReferenceType::Static,
entry.common.pointer.concat({"$schema"})},
SchemaFrame::ReferencesEntry{
destination,
metaschema.recompose_without_fragment(),
fragment_string(metaschema)});
}
}

// Handle schema anchors
Expand Down Expand Up @@ -721,6 +723,10 @@ auto internal_analyse(const sourcemeta::core::SchemaFrame::Mode mode,
}
}

if (mode == SchemaFrame::Mode::Locations) {
return;
}

// Resolve references after all framing was performed
for (const auto &entry : subschema_entries) {
if (entry.common.subschema.get().is_object()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame {
public:
/// The mode of framing. More extensive analysis can be compute and memory
/// intensive
enum class Mode { References, Instances };
enum class Mode { Locations, References, Instances };

SchemaFrame(const Mode mode) : mode_{mode} {}

Expand Down
2 changes: 1 addition & 1 deletion src/core/jsonschema/jsonschema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ auto sourcemeta::core::reference_visit(
const std::optional<std::string> &default_dialect,
const std::optional<std::string> &default_id) -> void {
sourcemeta::core::SchemaFrame frame{
sourcemeta::core::SchemaFrame::Mode::References};
sourcemeta::core::SchemaFrame::Mode::Locations};
frame.analyse(schema, walker, resolver, default_dialect, default_id);
for (const auto &entry : frame.locations()) {
if (entry.second.type !=
Expand Down
77 changes: 77 additions & 0 deletions test/jsonschema/jsonschema_frame_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,80 @@ TEST(JSONSchema_frame, mode_references) {
"https://www.example.com#/$defs/helper",
"https://www.example.com", "/$defs/helper");
}

TEST(JSONSchema_frame, mode_locations) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.example.com",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"items": {
"$anchor": "helper",
"$ref": "#/$defs/helper"
},
"$defs": {
"helper": true
}
})JSON");

sourcemeta::core::SchemaFrame frame{
sourcemeta::core::SchemaFrame::Mode::Locations};
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 9);
EXPECT_FRAME_STATIC_RESOURCE(
frame, "https://www.example.com", "https://www.example.com", "",
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"", {}, 0, std::nullopt);

// JSON Pointers

EXPECT_FRAME_STATIC_POINTER(
frame, "https://www.example.com#/$id", "https://www.example.com", "/$id",
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"/$id", {}, 0, std::nullopt);
EXPECT_FRAME_STATIC_POINTER(
frame, "https://www.example.com#/$schema", "https://www.example.com",
"/$schema", "https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"/$schema", {}, 0, std::nullopt);

EXPECT_FRAME_STATIC_SUBSCHEMA(frame, "https://www.example.com#/items",
"https://www.example.com", "/items",
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema",
"https://www.example.com", "/items", {}, 0, "");
EXPECT_FRAME_STATIC_ANCHOR(frame, "https://www.example.com#helper",
"https://www.example.com", "/items",
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema",
"https://www.example.com", "/items", {}, 0, "");

EXPECT_FRAME_STATIC_POINTER(frame, "https://www.example.com#/items/$anchor",
"https://www.example.com", "/items/$anchor",
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema",
"https://www.example.com", "/items/$anchor", {},
0, std::nullopt);
EXPECT_FRAME_STATIC_POINTER(
frame, "https://www.example.com#/items/$ref", "https://www.example.com",
"/items/$ref", "https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"/items/$ref", {}, 0, std::nullopt);

EXPECT_FRAME_STATIC_POINTER(
frame, "https://www.example.com#/$defs", "https://www.example.com",
"/$defs", "https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"/$defs", {}, 0, std::nullopt);
EXPECT_FRAME_STATIC_SUBSCHEMA(
frame, "https://www.example.com#/$defs/helper", "https://www.example.com",
"/$defs/helper", "https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", "https://www.example.com",
"/$defs/helper", {}, 0, "");

// References

EXPECT_EQ(frame.references().size(), 0);
}

2 comments on commit 7a2f3cc

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (linux/llvm)

Benchmark suite Current: 7a2f3cc Previous: 9606eec Ratio
Regex_Lower_S_Or_Upper_S_Asterisk 2.2218109421137195 ns/iter 2.1935838739785374 ns/iter 1.01
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 2.213322657203077 ns/iter 2.184742577538555 ns/iter 1.01
Regex_Period_Asterisk 2.2065143269930183 ns/iter 2.180419829420735 ns/iter 1.01
Regex_Group_Period_Asterisk_Group 2.2162289012492424 ns/iter 2.183408097394185 ns/iter 1.02
Regex_Period_Plus 2.486398556247174 ns/iter 2.487229964015529 ns/iter 1.00
Regex_Period 2.2159272667626184 ns/iter 2.487672956211073 ns/iter 0.89
Regex_Caret_Period_Plus_Dollar 2.3563702869927767 ns/iter 2.489052334023044 ns/iter 0.95
Regex_Caret_Group_Period_Plus_Group_Dollar 2.218539837435589 ns/iter 2.4878461345491787 ns/iter 0.89
Regex_Caret_Period_Asterisk_Dollar 2.208037515505908 ns/iter 3.419947426909548 ns/iter 0.65
Regex_Caret_Group_Period_Asterisk_Group_Dollar 2.2212160218639583 ns/iter 3.42738444461771 ns/iter 0.65
Regex_Caret_X_Hyphen 13.074579789928308 ns/iter 12.591995350553159 ns/iter 1.04
Regex_Period_Md_Dollar 74.87705992012934 ns/iter 73.36000212803474 ns/iter 1.02
Regex_Caret_Slash_Period_Asterisk 5.910724463784858 ns/iter 7.167724192038374 ns/iter 0.82
Regex_Caret_Period_Range_Dollar 2.805327399729854 ns/iter 3.232127022665651 ns/iter 0.87
Regex_Nested_Backtrack 458.4097294627658 ns/iter 508.979878181218 ns/iter 0.90
JSON_Array_Of_Objects_Unique 444.1846325104642 ns/iter 434.92210653576717 ns/iter 1.02
JSON_Parse_1 31250.959199009023 ns/iter 30789.55391185463 ns/iter 1.01
JSON_Fast_Hash_Helm_Chart_Lock 56.522908590185466 ns/iter 56.19719723174113 ns/iter 1.01
JSON_Equality_Helm_Chart_Lock 146.25061862851004 ns/iter 143.86738696330843 ns/iter 1.02
JSON_String_Equal/10 6.249922605197629 ns/iter 5.609661036175298 ns/iter 1.11
JSON_String_Equal/100 6.844423313083745 ns/iter 6.2438056146769165 ns/iter 1.10
JSON_String_Equal_Small_By_Perfect_Hash/10 0.9358351456517003 ns/iter 0.937168656605943 ns/iter 1.00
JSON_String_Equal_Small_By_Runtime_Perfect_Hash/10 10.258571277997918 ns/iter 10.260669045926992 ns/iter 1.00
JSON_String_Fast_Hash/10 2.175436475790206 ns/iter 2.177949571691811 ns/iter 1.00
JSON_String_Fast_Hash/100 2.1784536009540174 ns/iter 2.1765906245564595 ns/iter 1.00
JSON_String_Key_Hash/10 1.8724899519831038 ns/iter 1.8683979073915606 ns/iter 1.00
JSON_String_Key_Hash/100 2.179136094263975 ns/iter 2.180957903931263 ns/iter 1.00
JSON_Object_Defines_Miss_Same_Length 3.7379331337510893 ns/iter 3.7353349498893107 ns/iter 1.00
JSON_Object_Defines_Miss_Too_Small 3.744285837795385 ns/iter 3.7387737575736164 ns/iter 1.00
JSON_Object_Defines_Miss_Too_Large 3.7382191208893607 ns/iter 3.7410253058615037 ns/iter 1.00
Pointer_Object_Traverse 43.726529151494574 ns/iter 44.2814240603102 ns/iter 0.99
Pointer_Object_Try_Traverse 52.614286374458324 ns/iter 52.65525116291065 ns/iter 1.00
Pointer_Push_Back_Pointer_To_Weak_Pointer 286.7887360857717 ns/iter 335.8081716652877 ns/iter 0.85
Schema_Frame_OMC_Instances 292047475.9999934 ns/iter 300065977.499969 ns/iter 0.97
Schema_Frame_OMC_References 134501565.80000794 ns/iter 140024284.39998767 ns/iter 0.96
Schema_Bundle_Meta_2020_12 6555442.641503121 ns/iter 6641007.566033621 ns/iter 0.99

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (macos/llvm)

Benchmark suite Current: 7a2f3cc Previous: aa78075 Ratio
Regex_Lower_S_Or_Upper_S_Asterisk 2.2015724148070075 ns/iter 1.624821220123495 ns/iter 1.35
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 2.3944254049942693 ns/iter 1.6609516729029161 ns/iter 1.44
Regex_Period_Asterisk 2.1556301915302853 ns/iter 1.738469265360242 ns/iter 1.24
Regex_Group_Period_Asterisk_Group 1.8285142105593937 ns/iter 1.665286856679851 ns/iter 1.10
Regex_Period_Plus 2.0783314322101574 ns/iter 2.0886126242614034 ns/iter 1.00
Regex_Period 2.34914754419808 ns/iter 2.0157375041859855 ns/iter 1.17
Regex_Caret_Period_Plus_Dollar 2.6920299349800607 ns/iter 1.9794422262284337 ns/iter 1.36
Regex_Caret_Group_Period_Plus_Group_Dollar 2.6805219264454854 ns/iter 2.022141347798067 ns/iter 1.33
Regex_Caret_Period_Asterisk_Dollar 2.5400320557072065 ns/iter 1.697260793841543 ns/iter 1.50
Regex_Caret_Group_Period_Asterisk_Group_Dollar 1.9118004196108436 ns/iter 1.7554189565591891 ns/iter 1.09
Regex_Caret_X_Hyphen 6.823109561548679 ns/iter 6.970432963732137 ns/iter 0.98
Regex_Period_Md_Dollar 75.92424704900868 ns/iter 77.10506809878159 ns/iter 0.98
Regex_Caret_Slash_Period_Asterisk 6.849098031356917 ns/iter 7.109548618340744 ns/iter 0.96
Regex_Caret_Period_Range_Dollar 2.2027515252218963 ns/iter 2.201404592172592 ns/iter 1.00
Regex_Nested_Backtrack 837.0662359396721 ns/iter 794.0259380809389 ns/iter 1.05
JSON_Array_Of_Objects_Unique 358.55120002433665 ns/iter 364.9941576528486 ns/iter 0.98
JSON_Parse_1 23768.61130078157 ns/iter 23722.968011591893 ns/iter 1.00
JSON_Fast_Hash_Helm_Chart_Lock 52.99179204806288 ns/iter 52.37299882161486 ns/iter 1.01
JSON_Equality_Helm_Chart_Lock 135.24587220651483 ns/iter 129.7343206254738 ns/iter 1.04
JSON_String_Equal/10 9.054579575332443 ns/iter 8.443786095484295 ns/iter 1.07
JSON_String_Equal/100 8.514521849378395 ns/iter 6.8355439269680005 ns/iter 1.25
JSON_String_Equal_Small_By_Perfect_Hash/10 0.36370054159122905 ns/iter 0.3352311450770995 ns/iter 1.08
JSON_String_Equal_Small_By_Runtime_Perfect_Hash/10 3.073777545033706 ns/iter 3.148956828823588 ns/iter 0.98
JSON_String_Fast_Hash/10 1.8051151221133481 ns/iter 1.7429315752878547 ns/iter 1.04
JSON_String_Fast_Hash/100 2.0997281018638496 ns/iter 2.0504273197593945 ns/iter 1.02
JSON_String_Key_Hash/10 1.3768708863444203 ns/iter 1.3578214893867433 ns/iter 1.01
JSON_String_Key_Hash/100 1.4342073521820653 ns/iter 1.384373056381755 ns/iter 1.04
JSON_Object_Defines_Miss_Same_Length 2.4158884349075005 ns/iter 2.4132222271859005 ns/iter 1.00
JSON_Object_Defines_Miss_Too_Small 2.4148949288680135 ns/iter 2.4509751922887 ns/iter 0.99
JSON_Object_Defines_Miss_Too_Large 2.425865729670866 ns/iter 2.3801474197163244 ns/iter 1.02
Pointer_Object_Traverse 16.89202233847445 ns/iter 17.1245420717089 ns/iter 0.99
Pointer_Object_Try_Traverse 26.051375945845162 ns/iter 23.956747383431757 ns/iter 1.09
Pointer_Push_Back_Pointer_To_Weak_Pointer 186.66592496591474 ns/iter 187.18831538858637 ns/iter 1.00
Schema_Frame_OMC_Instances 205686944.3333274 ns/iter 209799055.6666597 ns/iter 0.98
Schema_Frame_OMC_References 104420812.50001441 ns/iter 104314160.71428755 ns/iter 1.00
Schema_Bundle_Meta_2020_12 4798628.755239164 ns/iter 4872684.027213526 ns/iter 0.98

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.