@@ -113,8 +113,10 @@ auto compile(const sourcemeta::core::JSON &schema,
113113 const Compiler &compiler,
114114 const sourcemeta::core::SchemaFrame &frame, const Mode mode,
115115 const std::optional<std::string> &default_dialect,
116- const std::optional<std::string> &default_id) -> Template {
116+ const std::optional<std::string> &default_id,
117+ const std::optional<Tweaks> &tweaks) -> Template {
117118 assert (is_schema (schema));
119+ const auto effective_tweaks{tweaks.value_or (Tweaks{})};
118120
119121 // /////////////////////////////////////////////////////////////////
120122 // (1) Determine the root frame entry
@@ -173,12 +175,9 @@ auto compile(const sourcemeta::core::JSON &schema,
173175 // Use string views to avoid copying the actual strings, as we know
174176 // that the frame survives the entire compilation process
175177 std::vector<std::tuple<std::string_view, std::size_t , std::size_t >>
176- sorted_references ;
178+ sorted_precompile_references ;
177179
178- constexpr auto PRECOMPILED_SCHEMAS_MAXIMUM{10 };
179- constexpr auto PRECOMPILED_SCHEMAS_MINIMUM_COUNT{10 };
180-
181- {
180+ if (effective_tweaks.precompile_static_references ) {
182181 std::unordered_map<std::string_view, std::pair<std::size_t , std::size_t >>
183182 static_reference_destinations;
184183 for (const auto &reference : frame.references ()) {
@@ -187,10 +186,9 @@ auto compile(const sourcemeta::core::JSON &schema,
187186 frame.locations ().contains (
188187 {sourcemeta::core::SchemaReferenceType::Static,
189188 reference.second .destination })) {
190- // TODO: Maybe try circular references or non-circular with >100 inbound
191- // locations or something like that?
192189 std::unordered_set<std::string> visited;
193- if (!is_circular (frame, reference.first .second , reference.second ,
190+ if (!effective_tweaks.precompile_static_references_non_circular &&
191+ !is_circular (frame, reference.first .second , reference.second ,
194192 visited)) {
195193 continue ;
196194 }
@@ -204,36 +202,45 @@ auto compile(const sourcemeta::core::JSON &schema,
204202 }
205203 }
206204
207- sorted_references .reserve (static_reference_destinations.size ());
205+ sorted_precompile_references .reserve (static_reference_destinations.size ());
208206 for (const auto &reference : static_reference_destinations) {
209- if (reference.second .second >= PRECOMPILED_SCHEMAS_MINIMUM_COUNT) {
210- sorted_references.emplace_back (reference.first , reference.second .first ,
211- reference.second .second );
207+ if (reference.second .second >=
208+ effective_tweaks
209+ .precompile_static_references_minimum_reference_count ) {
210+ sorted_precompile_references.emplace_back (
211+ reference.first , reference.second .first , reference.second .second );
212212 }
213213 }
214- std::ranges::sort (sorted_references ,
214+ std::ranges::sort (sorted_precompile_references ,
215215 [](const auto &left, const auto &right) {
216216 return std::get<2 >(left) > std::get<2 >(right);
217217 });
218218
219- if (sorted_references.size () > PRECOMPILED_SCHEMAS_MAXIMUM) {
220- sorted_references.erase (sorted_references.begin () +
221- PRECOMPILED_SCHEMAS_MAXIMUM,
222- sorted_references.end ());
219+ if (sorted_precompile_references.size () >
220+ effective_tweaks.precompile_static_references_maximum_schemas ) {
221+ sorted_precompile_references.erase (
222+ sorted_precompile_references.begin () +
223+ static_cast <std::ptrdiff_t >(
224+ effective_tweaks
225+ .precompile_static_references_maximum_schemas ),
226+ sorted_precompile_references.end ());
223227 }
224228
225229 // We do not apply this pre-compilation optimisation on meta-schemas
226230 if (sourcemeta::core::schema_official_resolver (base).has_value () ||
227231 (uses_dynamic_scopes && schema.is_object () &&
228232 schema.defines (" $vocabulary" ))) {
229- sorted_references .clear ();
233+ sorted_precompile_references .clear ();
230234 }
231235 }
232236
233- assert (sorted_references.size () <= PRECOMPILED_SCHEMAS_MAXIMUM);
237+ assert (sorted_precompile_references.size () <=
238+ effective_tweaks.precompile_static_references_maximum_schemas );
234239 std::unordered_set<std::size_t > precompiled_labels;
235- for (const auto &reference : sorted_references) {
236- assert (std::get<2 >(reference) >= PRECOMPILED_SCHEMAS_MINIMUM_COUNT);
240+ for (const auto &reference : sorted_precompile_references) {
241+ assert (
242+ std::get<2 >(reference) >=
243+ effective_tweaks.precompile_static_references_minimum_reference_count );
237244 precompiled_labels.emplace (std::get<1 >(reference));
238245 }
239246
@@ -265,7 +272,8 @@ auto compile(const sourcemeta::core::JSON &schema,
265272 .mode = mode,
266273 .uses_dynamic_scopes = uses_dynamic_scopes,
267274 .unevaluated = std::move (unevaluated),
268- .precompiled_labels = std::move (precompiled_labels)};
275+ .precompiled_labels = std::move (precompiled_labels),
276+ .tweaks = effective_tweaks};
269277
270278 // /////////////////////////////////////////////////////////////////
271279 // (7) Build the initial dynamic context
@@ -304,7 +312,7 @@ auto compile(const sourcemeta::core::JSON &schema,
304312
305313 // Attempt to precompile static destinations to avoid explosive compilation
306314 Instructions static_reference_template;
307- for (const auto &reference : sorted_references ) {
315+ for (const auto &reference : sorted_precompile_references ) {
308316 const auto entry{context.frame .locations ().find (
309317 {sourcemeta::core::SchemaReferenceType::Static,
310318 std::string{std::get<0 >(reference)}})};
@@ -377,7 +385,8 @@ auto compile(const sourcemeta::core::JSON &schema,
377385 const sourcemeta::core::SchemaResolver &resolver,
378386 const Compiler &compiler, const Mode mode,
379387 const std::optional<std::string> &default_dialect,
380- const std::optional<std::string> &default_id) -> Template {
388+ const std::optional<std::string> &default_id,
389+ const std::optional<Tweaks> &tweaks) -> Template {
381390 assert (is_schema (schema));
382391
383392 // Make sure the input schema is bundled, otherwise we won't be able to
@@ -391,7 +400,7 @@ auto compile(const sourcemeta::core::JSON &schema,
391400 frame.analyse (result, walker, resolver, default_dialect, default_id);
392401
393402 return compile (result, walker, resolver, compiler, frame, mode,
394- default_dialect, default_id);
403+ default_dialect, default_id, tweaks );
395404}
396405
397406auto compile (const Context &context, const SchemaContext &schema_context,
0 commit comments