Skip to content

Commit 39aa8ea

Browse files
authored
Turn ValueTypes into a bitset (#551)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent deba89c commit 39aa8ea

9 files changed

Lines changed: 318 additions & 146 deletions

File tree

src/compiler/default_compiler_draft4.h

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,11 @@ auto compiler_draft4_validation_type(const Context &context,
378378

379379
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
380380
context, schema_context, dynamic_context,
381-
std::vector<sourcemeta::core::JSON::Type>{
382-
sourcemeta::core::JSON::Type::Real,
383-
sourcemeta::core::JSON::Type::Integer})};
381+
static_cast<ValueTypes>(
382+
(1U << static_cast<std::uint8_t>(
383+
sourcemeta::core::JSON::Type::Real)) |
384+
(1U << static_cast<std::uint8_t>(
385+
sourcemeta::core::JSON::Type::Integer))))};
384386
} else if (type == "integer") {
385387
if (context.mode == Mode::FastValidation &&
386388
schema_context.schema.defines("enum") &&
@@ -455,9 +457,11 @@ auto compiler_draft4_validation_type(const Context &context,
455457
} else if (type == "number") {
456458
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
457459
context, schema_context, dynamic_context,
458-
std::vector<sourcemeta::core::JSON::Type>{
459-
sourcemeta::core::JSON::Type::Real,
460-
sourcemeta::core::JSON::Type::Integer})};
460+
static_cast<ValueTypes>(
461+
(1U << static_cast<std::uint8_t>(
462+
sourcemeta::core::JSON::Type::Real)) |
463+
(1U << static_cast<std::uint8_t>(
464+
sourcemeta::core::JSON::Type::Integer))))};
461465
} else if (type == "integer") {
462466
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrict,
463467
context, schema_context, dynamic_context,
@@ -470,33 +474,40 @@ auto compiler_draft4_validation_type(const Context &context,
470474
return {};
471475
}
472476
} else if (schema_context.schema.at(dynamic_context.keyword).is_array()) {
473-
std::vector<sourcemeta::core::JSON::Type> types;
477+
ValueTypes types{0};
474478
for (const auto &type :
475479
schema_context.schema.at(dynamic_context.keyword).as_array()) {
476480
assert(type.is_string());
477481
const auto &type_string{type.to_string()};
478482
if (type_string == "null") {
479-
types.push_back(sourcemeta::core::JSON::Type::Null);
483+
types |= (1U << static_cast<std::uint8_t>(
484+
sourcemeta::core::JSON::Type::Null));
480485
} else if (type_string == "boolean") {
481-
types.push_back(sourcemeta::core::JSON::Type::Boolean);
486+
types |= (1U << static_cast<std::uint8_t>(
487+
sourcemeta::core::JSON::Type::Boolean));
482488
} else if (type_string == "object") {
483-
types.push_back(sourcemeta::core::JSON::Type::Object);
489+
types |= (1U << static_cast<std::uint8_t>(
490+
sourcemeta::core::JSON::Type::Object));
484491
} else if (type_string == "array") {
485-
types.push_back(sourcemeta::core::JSON::Type::Array);
492+
types |= (1U << static_cast<std::uint8_t>(
493+
sourcemeta::core::JSON::Type::Array));
486494
} else if (type_string == "number") {
487-
types.push_back(sourcemeta::core::JSON::Type::Integer);
488-
types.push_back(sourcemeta::core::JSON::Type::Real);
495+
types |= (1U << static_cast<std::uint8_t>(
496+
sourcemeta::core::JSON::Type::Integer));
497+
types |= (1U << static_cast<std::uint8_t>(
498+
sourcemeta::core::JSON::Type::Real));
489499
} else if (type_string == "integer") {
490-
types.push_back(sourcemeta::core::JSON::Type::Integer);
500+
types |= (1U << static_cast<std::uint8_t>(
501+
sourcemeta::core::JSON::Type::Integer));
491502
} else if (type_string == "string") {
492-
types.push_back(sourcemeta::core::JSON::Type::String);
503+
types |= (1U << static_cast<std::uint8_t>(
504+
sourcemeta::core::JSON::Type::String));
493505
}
494506
}
495507

496-
assert(types.size() >=
497-
schema_context.schema.at(dynamic_context.keyword).size());
508+
assert(types != 0);
498509
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
499-
context, schema_context, dynamic_context, std::move(types))};
510+
context, schema_context, dynamic_context, types)};
500511
}
501512

502513
return {};
@@ -703,33 +714,39 @@ auto compiler_draft4_applicator_anyof(const Context &context,
703714
sourcemeta::blaze::InstructionIndex::
704715
AssertionTypeStrictAny);
705716
})) {
706-
ValueTypes types;
717+
ValueTypes types{0};
707718
for (const auto &instruction : disjunctors) {
708719
if (instruction.children.front().type ==
709720
sourcemeta::blaze::InstructionIndex::AssertionTypeStrict) {
710721
const auto &value{
711722
*std::get_if<ValueType>(&instruction.children.front().value)};
712-
types.push_back(value);
723+
types |= (1U << static_cast<std::uint8_t>(value));
713724
}
714725

715726
if (instruction.children.front().type ==
716727
sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny) {
717728
const auto &value{
718729
*std::get_if<ValueTypes>(&instruction.children.front().value)};
719-
for (const auto type : value) {
720-
types.push_back(type);
721-
}
730+
types |= value;
722731
}
723732
}
724733

725-
assert(!types.empty());
726-
if (types.size() > 1) {
734+
assert(types != 0);
735+
std::uint8_t popcount{0};
736+
for (std::uint8_t temp{types}; temp != 0; temp >>= 1) {
737+
popcount += (temp & 1);
738+
}
739+
if (popcount > 1) {
727740
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
728-
context, schema_context, dynamic_context, std::move(types))};
741+
context, schema_context, dynamic_context, types)};
729742
} else {
743+
std::uint8_t type_index{0};
744+
for (std::uint8_t temp{types}; (temp & 1) == 0; temp >>= 1) {
745+
type_index++;
746+
}
730747
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrict,
731748
context, schema_context, dynamic_context,
732-
ValueType{*types.cbegin()})};
749+
static_cast<ValueType>(type_index))};
733750
}
734751
}
735752

src/compiler/default_compiler_draft6.h

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,11 @@ auto compiler_draft6_validation_type(const Context &context,
167167

168168
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
169169
context, schema_context, dynamic_context,
170-
std::vector<sourcemeta::core::JSON::Type>{
171-
sourcemeta::core::JSON::Type::Real,
172-
sourcemeta::core::JSON::Type::Integer})};
170+
static_cast<ValueTypes>(
171+
(1U << static_cast<std::uint8_t>(
172+
sourcemeta::core::JSON::Type::Real)) |
173+
(1U << static_cast<std::uint8_t>(
174+
sourcemeta::core::JSON::Type::Integer))))};
173175
} else if (type == "integer") {
174176
if (context.mode == Mode::FastValidation &&
175177
schema_context.schema.defines("enum") &&
@@ -263,9 +265,11 @@ auto compiler_draft6_validation_type(const Context &context,
263265
} else if (type == "number") {
264266
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeStrictAny,
265267
context, schema_context, dynamic_context,
266-
std::vector<sourcemeta::core::JSON::Type>{
267-
sourcemeta::core::JSON::Type::Real,
268-
sourcemeta::core::JSON::Type::Integer})};
268+
static_cast<ValueTypes>(
269+
(1U << static_cast<std::uint8_t>(
270+
sourcemeta::core::JSON::Type::Real)) |
271+
(1U << static_cast<std::uint8_t>(
272+
sourcemeta::core::JSON::Type::Integer))))};
269273
} else if (type == "integer") {
270274
return {make(sourcemeta::blaze::InstructionIndex::AssertionType, context,
271275
schema_context, dynamic_context,
@@ -282,37 +286,44 @@ auto compiler_draft6_validation_type(const Context &context,
282286
return {};
283287
}
284288
} else if (schema_context.schema.at(dynamic_context.keyword).is_array()) {
285-
std::vector<sourcemeta::core::JSON::Type> types;
289+
ValueTypes types{0};
286290
for (const auto &type :
287291
schema_context.schema.at(dynamic_context.keyword).as_array()) {
288292
assert(type.is_string());
289293
const auto &type_string{type.to_string()};
290294
if (type_string == "null") {
291-
types.push_back(sourcemeta::core::JSON::Type::Null);
295+
types |= (1U << static_cast<std::uint8_t>(
296+
sourcemeta::core::JSON::Type::Null));
292297
} else if (type_string == "boolean") {
293-
types.push_back(sourcemeta::core::JSON::Type::Boolean);
298+
types |= (1U << static_cast<std::uint8_t>(
299+
sourcemeta::core::JSON::Type::Boolean));
294300
} else if (type_string == "object") {
295-
types.push_back(sourcemeta::core::JSON::Type::Object);
301+
types |= (1U << static_cast<std::uint8_t>(
302+
sourcemeta::core::JSON::Type::Object));
296303
} else if (type_string == "array") {
297-
types.push_back(sourcemeta::core::JSON::Type::Array);
304+
types |= (1U << static_cast<std::uint8_t>(
305+
sourcemeta::core::JSON::Type::Array));
298306
} else if (type_string == "number") {
299-
types.push_back(sourcemeta::core::JSON::Type::Integer);
300-
types.push_back(sourcemeta::core::JSON::Type::Real);
307+
types |= (1U << static_cast<std::uint8_t>(
308+
sourcemeta::core::JSON::Type::Integer));
309+
types |= (1U << static_cast<std::uint8_t>(
310+
sourcemeta::core::JSON::Type::Real));
301311
} else if (type_string == "integer") {
302-
types.push_back(sourcemeta::core::JSON::Type::Integer);
312+
types |= (1U << static_cast<std::uint8_t>(
313+
sourcemeta::core::JSON::Type::Integer));
303314
} else if (type_string == "string") {
304315
if (dynamic_context.property_as_target) {
305316
continue;
306317
}
307318

308-
types.push_back(sourcemeta::core::JSON::Type::String);
319+
types |= (1U << static_cast<std::uint8_t>(
320+
sourcemeta::core::JSON::Type::String));
309321
}
310322
}
311323

312-
assert(types.size() >=
313-
schema_context.schema.at(dynamic_context.keyword).size());
324+
assert(types != 0);
314325
return {make(sourcemeta::blaze::InstructionIndex::AssertionTypeAny, context,
315-
schema_context, dynamic_context, std::move(types))};
326+
schema_context, dynamic_context, types)};
316327
}
317328

318329
return {};

src/evaluator/dispatch.inc.h

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -263,20 +263,19 @@ INSTRUCTION_HANDLER(AssertionTypeAny) {
263263
SOURCEMETA_MAYBE_UNUSED(property_target);
264264
SOURCEMETA_MAYBE_UNUSED(evaluator);
265265
EVALUATE_BEGIN_NO_PRECONDITION(AssertionTypeAny);
266-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
267-
// Otherwise we are we even emitting this instruction?
268-
assert(value.size() > 1);
266+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
267+
assert(value != 0);
269268
const auto &target{get(instance, instruction.relative_instance_location)};
270269
// In non-strict mode, we consider a real number that represents an
271270
// integer to be an integer
272-
for (const auto type : value) {
273-
if (type == JSON::Type::Integer && target.is_integer_real()) {
274-
result = true;
275-
break;
276-
} else if (type == target.type()) {
277-
result = true;
278-
break;
279-
}
271+
const auto type_bit{static_cast<std::uint8_t>(
272+
1U << static_cast<std::uint8_t>(target.type()))};
273+
if ((value & type_bit) != 0) {
274+
result = true;
275+
} else if ((value & (1U << static_cast<std::uint8_t>(JSON::Type::Integer))) !=
276+
0 &&
277+
target.is_integer_real()) {
278+
result = true;
280279
}
281280

282281
EVALUATE_END(AssertionTypeAny);
@@ -304,12 +303,12 @@ INSTRUCTION_HANDLER(AssertionTypeStrictAny) {
304303
SOURCEMETA_MAYBE_UNUSED(property_target);
305304
SOURCEMETA_MAYBE_UNUSED(evaluator);
306305
EVALUATE_BEGIN_NO_PRECONDITION(AssertionTypeStrictAny);
307-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
308-
// Otherwise we are we even emitting this instruction?
309-
assert(value.size() > 1);
306+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
307+
assert(value != 0);
310308
const auto &target{get(instance, instruction.relative_instance_location)};
311-
result =
312-
(std::find(value.cbegin(), value.cend(), target.type()) != value.cend());
309+
const auto type_bit{static_cast<std::uint8_t>(
310+
1U << static_cast<std::uint8_t>(target.type()))};
311+
result = ((value & type_bit) != 0);
313312
EVALUATE_END(AssertionTypeStrictAny);
314313
}
315314

@@ -776,10 +775,12 @@ INSTRUCTION_HANDLER(AssertionPropertyTypeStrictAny) {
776775
SOURCEMETA_MAYBE_UNUSED(property_target);
777776
SOURCEMETA_MAYBE_UNUSED(evaluator);
778777
EVALUATE_BEGIN_TRY_TARGET(AssertionPropertyTypeStrictAny);
779-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
778+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
779+
assert(value != 0);
780780
// Now here we refer to the actual property
781-
result = (std::find(value.cbegin(), value.cend(), target_check->type()) !=
782-
value.cend());
781+
const auto type_bit{static_cast<std::uint8_t>(
782+
1U << static_cast<std::uint8_t>(target_check->type()))};
783+
result = ((value & type_bit) != 0);
783784
EVALUATE_END(AssertionPropertyTypeStrictAny);
784785
}
785786

@@ -791,10 +792,12 @@ INSTRUCTION_HANDLER(AssertionPropertyTypeStrictAnyEvaluate) {
791792
SOURCEMETA_MAYBE_UNUSED(property_target);
792793
SOURCEMETA_MAYBE_UNUSED(evaluator);
793794
EVALUATE_BEGIN_TRY_TARGET(AssertionPropertyTypeStrictAnyEvaluate);
794-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
795+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
796+
assert(value != 0);
795797
// Now here we refer to the actual property
796-
result = (std::find(value.cbegin(), value.cend(), target_check->type()) !=
797-
value.cend());
798+
const auto type_bit{static_cast<std::uint8_t>(
799+
1U << static_cast<std::uint8_t>(target_check->type()))};
800+
result = ((value & type_bit) != 0);
798801

799802
if (result) {
800803
evaluator.evaluate(target_check);
@@ -2042,10 +2045,12 @@ INSTRUCTION_HANDLER(LoopPropertiesTypeStrictAny) {
20422045
SOURCEMETA_MAYBE_UNUSED(evaluator);
20432046
EVALUATE_BEGIN_NON_STRING(LoopPropertiesTypeStrictAny, target.is_object());
20442047
result = true;
2045-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
2048+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
2049+
assert(value != 0);
20462050
for (const auto &entry : target.as_object()) {
2047-
if (std::find(value.cbegin(), value.cend(), entry.second.type()) ==
2048-
value.cend()) {
2051+
const auto type_bit{static_cast<std::uint8_t>(
2052+
1U << static_cast<std::uint8_t>(entry.second.type()))};
2053+
if ((value & type_bit) == 0) {
20492054
result = false;
20502055
break;
20512056
}
@@ -2064,10 +2069,12 @@ INSTRUCTION_HANDLER(LoopPropertiesTypeStrictAnyEvaluate) {
20642069
EVALUATE_BEGIN_NON_STRING(LoopPropertiesTypeStrictAnyEvaluate,
20652070
target.is_object());
20662071
result = true;
2067-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
2072+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
2073+
assert(value != 0);
20682074
for (const auto &entry : target.as_object()) {
2069-
if (std::find(value.cbegin(), value.cend(), entry.second.type()) ==
2070-
value.cend()) {
2075+
const auto type_bit{static_cast<std::uint8_t>(
2076+
1U << static_cast<std::uint8_t>(entry.second.type()))};
2077+
if ((value & type_bit) == 0) {
20712078
result = false;
20722079
EVALUATE_END(LoopPropertiesTypeStrictAnyEvaluate);
20732080
}
@@ -2311,12 +2318,14 @@ INSTRUCTION_HANDLER(LoopItemsTypeStrictAny) {
23112318
SOURCEMETA_MAYBE_UNUSED(property_target);
23122319
SOURCEMETA_MAYBE_UNUSED(evaluator);
23132320
EVALUATE_BEGIN_NON_STRING(LoopItemsTypeStrictAny, target.is_array());
2314-
const auto &value{*std::get_if<ValueTypes>(&instruction.value)};
2315-
// Otherwise we are we even emitting this instruction?
2316-
assert(value.size() > 1);
2321+
const auto value{*std::get_if<ValueTypes>(&instruction.value)};
2322+
assert(value != 0);
2323+
23172324
result = true;
23182325
for (const auto &entry : target.as_array()) {
2319-
if (std::find(value.cbegin(), value.cend(), entry.type()) == value.cend()) {
2326+
const auto type_bit{static_cast<std::uint8_t>(
2327+
1U << static_cast<std::uint8_t>(entry.type()))};
2328+
if ((value & type_bit) == 0) {
23202329
result = false;
23212330
break;
23222331
}

0 commit comments

Comments
 (0)