@@ -1474,6 +1474,71 @@ auto compiler_draft4_applicator_items_array(
14741474 }
14751475}
14761476
1477+ auto is_number_type_check (const Instruction &instruction) -> bool {
1478+ if (instruction.type == InstructionIndex::AssertionTypeStrictAny) {
1479+ const auto &value{std::get<ValueTypes>(instruction.value )};
1480+ return value.test (
1481+ std::to_underlying (sourcemeta::core::JSON::Type::Integer)) &&
1482+ value.test (std::to_underlying (sourcemeta::core::JSON::Type::Real));
1483+ }
1484+
1485+ if (instruction.type == InstructionIndex::AssertionTypeStrict) {
1486+ const auto &value{std::get<ValueType>(instruction.value )};
1487+ return value == sourcemeta::core::JSON::Type::Integer ||
1488+ value == sourcemeta::core::JSON::Type::Real;
1489+ }
1490+
1491+ if (instruction.type == InstructionIndex::AssertionType) {
1492+ const auto &value{std::get<ValueType>(instruction.value )};
1493+ return value == sourcemeta::core::JSON::Type::Integer ||
1494+ value == sourcemeta::core::JSON::Type::Real;
1495+ }
1496+
1497+ return false ;
1498+ }
1499+
1500+ auto is_integer_bounded_pattern (const Instructions &children) -> bool {
1501+ if (children.size () != 3 ) {
1502+ return false ;
1503+ }
1504+
1505+ bool has_type{false };
1506+ bool has_min{false };
1507+ bool has_max{false };
1508+ for (const auto &child : children) {
1509+ if (is_number_type_check (child)) {
1510+ has_type = true ;
1511+ } else if (child.type == InstructionIndex::AssertionGreaterEqual) {
1512+ if (!std::get<ValueJSON>(child.value ).is_integer ()) {
1513+ return false ;
1514+ }
1515+ has_min = true ;
1516+ } else if (child.type == InstructionIndex::AssertionLessEqual) {
1517+ if (!std::get<ValueJSON>(child.value ).is_integer ()) {
1518+ return false ;
1519+ }
1520+ has_max = true ;
1521+ }
1522+ }
1523+
1524+ return has_type && has_min && has_max;
1525+ }
1526+
1527+ auto extract_integer_bounds (const Instructions &children)
1528+ -> ValueIntegerBounds {
1529+ std::int64_t minimum{0 };
1530+ std::int64_t maximum{0 };
1531+ for (const auto &child : children) {
1532+ if (child.type == InstructionIndex::AssertionGreaterEqual) {
1533+ minimum = std::get<ValueJSON>(child.value ).to_integer ();
1534+ } else if (child.type == InstructionIndex::AssertionLessEqual) {
1535+ maximum = std::get<ValueJSON>(child.value ).to_integer ();
1536+ }
1537+ }
1538+
1539+ return {minimum, maximum};
1540+ }
1541+
14771542auto compiler_draft4_applicator_items_with_options (
14781543 const Context &context, const SchemaContext &schema_context,
14791544 const DynamicContext &dynamic_context, const bool annotate,
@@ -1539,6 +1604,13 @@ auto compiler_draft4_applicator_items_with_options(
15391604 return {};
15401605 }
15411606
1607+ if (context.mode == Mode::FastValidation && children.size () == 3 &&
1608+ is_integer_bounded_pattern (children)) {
1609+ return {make (sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded,
1610+ context, schema_context, dynamic_context,
1611+ extract_integer_bounds (children))};
1612+ }
1613+
15421614 if (context.mode == Mode::FastValidation && children.size () == 1 ) {
15431615 if (children.front ().type == InstructionIndex::AssertionTypeStrict) {
15441616 return {make (sourcemeta::blaze::InstructionIndex::LoopItemsTypeStrict,
@@ -1614,6 +1686,15 @@ auto compiler_draft4_applicator_additionalitems_from_cursor(
16141686 Instructions children;
16151687
16161688 if (!subchildren.empty ()) {
1689+ if (context.mode == Mode::FastValidation && cursor == 0 && !annotate &&
1690+ !track_evaluation && is_integer_bounded_pattern (subchildren)) {
1691+ children.push_back (
1692+ make (sourcemeta::blaze::InstructionIndex::LoopItemsIntegerBounded,
1693+ context, schema_context, dynamic_context,
1694+ extract_integer_bounds (subchildren)));
1695+ return children;
1696+ }
1697+
16171698 children.push_back (make (sourcemeta::blaze::InstructionIndex::LoopItemsFrom,
16181699 context, schema_context, dynamic_context,
16191700 ValueUnsignedInteger{cursor},
0 commit comments