count_elements did not like empty arrays. (#1631)

* count_elements did not like empty arrays.

* Minor cleaning.

* I don't understand.

* More cleaning.
This commit is contained in:
Daniel Lemire 2021-06-24 11:08:13 -04:00 committed by GitHub
parent 1ba73b9e6b
commit 5b99a75ae1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 22 deletions

View File

@ -73,6 +73,9 @@ simdjson_really_inline simdjson_result<array_iterator> array::end() noexcept {
}
simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcept {
// If the array is empty (i.e., we already scanned past it), then we use a
// fast path and return 0.
if(!iter.is_open()) { return 0; }
// The count_elements method should always be called before you have begun
// iterating through the array.
// To open a new array you need to be at a `[`.
@ -80,15 +83,14 @@ simdjson_really_inline simdjson_result<size_t> array::count_elements() & noexcep
// array::begin() makes the same check.
if(!iter.is_at_container_start()) { return OUT_OF_ORDER_ITERATION; }
#endif
// Otherwise, we need to iterate through the array.
iter.enter_at_container_start(); // sets the depth to indicate that we are inside the container and accesses the first element
size_t count{0};
// Important: we do not consume any of the values.
for(simdjson_unused auto v : *this) { count++; }
// The above loop will always succeed, but we want to report errors.
if(iter.error()) { return iter.error(); }
// We need to move back at the start because we expect users to iterator through
// We need to move back at the start because we expect users to iterate through
// the array after counting the number of elements.
// enter_at_container_start is safe here because we know that we do not have an empty array.
iter.enter_at_container_start(); // sets the depth to indicate that we are inside the container and accesses the first element
return count;
}

View File

@ -64,31 +64,23 @@ namespace array_tests {
for (auto value : array) {
ondemand::object current_object;
ASSERT_SUCCESS( value.get_object().get(current_object) );
std::cout << "[ondemand::issue1588::sequence] acquired a new object ==========" << std::endl;
simdjson::ondemand::array rotation;
if(expected_value[i][0]) {
ASSERT_SUCCESS( current_object["rotation"].get(rotation) );
std::cout << "[ondemand::issue1588::sequence] found 'rotation' " << std::endl;
} else {
ASSERT_ERROR( current_object["rotation"].get(rotation), NO_SUCH_FIELD );
std::cout << "[ondemand::issue1588::sequence] rotation not found" << std::endl;
}
simdjson::ondemand::array scale;
if(expected_value[i][1]) {
ASSERT_SUCCESS( current_object["scale"].get(scale) );
std::cout << "[ondemand::issue1588::sequence] found 'scale' " << std::endl;
} else {
ASSERT_ERROR( current_object["scale"].get(scale), NO_SUCH_FIELD );
std::cout << "[ondemand::issue1588::sequence] scale not found" << std::endl;
}
simdjson::ondemand::array translation;
if(expected_value[i][2]) {
ASSERT_SUCCESS( current_object["translation"].get(translation) );
std::cout << "[ondemand::issue1588::sequence] found 'translation' " << std::endl;
} else {
ASSERT_ERROR( current_object["translation"].get(translation), NO_SUCH_FIELD );
std::cout << "[ondemand::issue1588::sequence] translation not found" << std::endl;
}
i++;
}
@ -139,15 +131,23 @@ namespace array_tests {
bool iterate_complex_array_count() {
TEST_START();
ondemand::parser parser;
auto cars_json = R"( { "test":[ { "val1":1, "val2":2 }, { "val1":1, "val2":2 } ] } )"_padded;
auto cars_json = R"( { "zero":[], "test":[ { "val1":1, "val2":2 }, { "val1":1, "val2":2 } ] } )"_padded;
ondemand::document doc;
ASSERT_SUCCESS(parser.iterate(cars_json).get(doc));
ondemand::array myarray;
ASSERT_SUCCESS(doc.find_field("test").get_array().get(myarray));
size_t count;
ASSERT_SUCCESS(myarray.count_elements().get(count));
size_t new_count = 0;
for(simdjson_unused auto elem: myarray) { new_count++; }
ondemand::array firstmyarray;
ondemand::array secondmyarray;
ASSERT_SUCCESS(doc.find_field("zero").get_array().get(firstmyarray));
size_t count{0};
ASSERT_SUCCESS(firstmyarray.count_elements().get(count));
ASSERT_EQUAL(count, 0);
size_t new_count{0};
for(simdjson_unused auto elem: firstmyarray) { new_count++; }
ASSERT_EQUAL(new_count, 0);
ASSERT_SUCCESS(doc.find_field("test").get_array().get(secondmyarray));
ASSERT_SUCCESS(secondmyarray.count_elements().get(count));
ASSERT_EQUAL(count, 2);
new_count = 0;
for(simdjson_unused auto elem: secondmyarray) { new_count++; }
ASSERT_EQUAL(count, new_count);
TEST_SUCCEED();
}

View File

@ -70,10 +70,6 @@ int test_main(int argc, char *argv[], const F& test_function) {
std::abort();
}
// We want to know what we are testing.
// Next line would be the runtime dispatched implementation but that's not necessarily what gets tested.
// std::cout << "Running tests against this implementation: " << simdjson::active_implementation->name();
// Rather, we want to display builtin_implementation()->name().
// In practice, by default, we often end up testing against fallback.
std::cout << "builtin_implementation -- " << simdjson::builtin_implementation()->name() << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;