Iterate value without going through indirection

Avoids issues with value being released early
This commit is contained in:
John Keiser 2020-09-05 01:34:13 -07:00
parent fe7a4d42d3
commit 8fd0cdc732
13 changed files with 390 additions and 329 deletions

View File

@ -40,7 +40,7 @@ simdjson_really_inline bool OnDemand::Run(const padded_string &json) {
// Walk the document, parsing the tweets as we go
auto doc = parser.iterate(json);
for (ondemand::object tweet : doc["statuses"].get_array()) {
for (ondemand::object tweet : doc["statuses"]) {
tweets.emplace_back(partial_tweets::tweet{
tweet["created_at"],
tweet["id"],

View File

@ -2,6 +2,8 @@
#include "generic/ondemand/raw_json_string.h"
#include "generic/ondemand/token_iterator.h"
#include "generic/ondemand/json_iterator.h"
#include "generic/ondemand/array_iterator.h"
#include "generic/ondemand/object_iterator.h"
#include "generic/ondemand/array.h"
#include "generic/ondemand/document.h"
#include "generic/ondemand/value.h"
@ -13,6 +15,8 @@
#include "generic/ondemand/raw_json_string-inl.h"
#include "generic/ondemand/token_iterator-inl.h"
#include "generic/ondemand/json_iterator-inl.h"
#include "generic/ondemand/array_iterator-inl.h"
#include "generic/ondemand/object_iterator-inl.h"
#include "generic/ondemand/array-inl.h"
#include "generic/ondemand/document-inl.h"
#include "generic/ondemand/value-inl.h"

View File

@ -42,7 +42,7 @@ namespace ondemand {
simdjson_really_inline array::array() noexcept = default;
simdjson_really_inline array::array(json_iterator_ref &&_iter) noexcept
: iter{std::forward<json_iterator_ref>(_iter)}, error{SUCCESS}
: iter{std::forward<json_iterator_ref>(_iter)}
{
}
simdjson_really_inline array::array(array &&other) noexcept = default;
@ -66,36 +66,14 @@ simdjson_really_inline array array::started(json_iterator_ref &&iter) noexcept {
if (!iter->started_array()) { iter.release(); }
return array(std::forward<json_iterator_ref>(iter));
}
simdjson_really_inline array::iterator array::begin() & noexcept {
return *this;
simdjson_really_inline array_iterator array::begin() & noexcept {
return iter;
}
simdjson_really_inline array::iterator array::end() & noexcept {
simdjson_really_inline array_iterator array::end() & noexcept {
return {};
}
simdjson_really_inline array::iterator::iterator(array &_a) noexcept : a{&_a} {}
simdjson_really_inline array::iterator::iterator() noexcept = default;
simdjson_really_inline array::iterator::iterator(const array::iterator &_a) noexcept = default;
simdjson_really_inline array::iterator &array::iterator::operator=(const array::iterator &_a) noexcept = default;
simdjson_really_inline simdjson_result<value> array::iterator::operator*() noexcept {
if (a->error) { a->iter.release(); return a->error; }
return value::start(a->iter.borrow());
}
simdjson_really_inline bool array::iterator::operator==(const array::iterator &other) noexcept {
return !(*this != other);
}
simdjson_really_inline bool array::iterator::operator!=(const array::iterator &) noexcept {
return a->iter.is_alive();
}
simdjson_really_inline array::iterator &array::iterator::operator++() noexcept {
bool has_value;
a->error = a->iter->has_next_element().get(has_value); // If there's an error, has_next stays true.
if (!(a->error || has_value)) { a->iter.release(); }
return *this;
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // unnamed namespace
@ -117,69 +95,13 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::begin() & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::begin() & noexcept {
if (error()) { return error(); }
return first.begin();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::end() & noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array>::end() & noexcept {
if (error()) { return error(); }
return first.end();
}
//
// array::iterator
//
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::simdjson_result() noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>({}, SUCCESS)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::simdjson_result(
SIMDJSON_IMPLEMENTATION::ondemand::array::iterator &&value
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>(value))
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>({}, error)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::simdjson_result(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &a
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>(a)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::operator=(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &a
) noexcept {
first = a.first;
second = a.second;
return *this;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::operator*() noexcept {
if (error()) { second = SUCCESS; return error(); }
return *first;
}
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &other) noexcept {
if (error()) { return true; }
return first == other.first;
}
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &other) noexcept {
if (error()) { return false; }
return first != other.first;
}
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator>::operator++() noexcept {
if (error()) { return *this; }
++first;
return *this;
}
} // namespace simdjson

View File

@ -19,33 +19,8 @@ public:
array(const array &) = delete;
array &operator=(const array &) = delete;
class iterator {
public:
simdjson_really_inline iterator(array &a) noexcept;
simdjson_really_inline iterator(const array::iterator &a) noexcept;
simdjson_really_inline iterator &operator=(const array::iterator &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const array::iterator &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const array::iterator &) noexcept;
// Checks for ']' and ','
simdjson_really_inline array::iterator &operator++() noexcept;
private:
array *a{};
simdjson_really_inline iterator() noexcept;
friend class array;
friend struct simdjson_result<array::iterator>;
};
simdjson_really_inline array::iterator begin() & noexcept;
simdjson_really_inline array::iterator end() & noexcept;
simdjson_really_inline array_iterator begin() & noexcept;
simdjson_really_inline array_iterator end() & noexcept;
protected:
/**
@ -77,15 +52,6 @@ protected:
* is first used, and never changes afterwards.
*/
json_iterator_ref iter{};
/**
* Error, if there is one. Errors are only yielded once.
*
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
* this is not elided, we should make sure it's at least not using up a register. Failing that,
* we should store it in document so there's only one of them.
*/
error_code error{};
friend class value;
friend struct simdjson_result<value>;
@ -104,31 +70,8 @@ public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> end() & noexcept;
};
template<>
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> : public internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> {
public:
simdjson_really_inline simdjson_result() noexcept;
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array::iterator &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &a) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &operator=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &) noexcept;
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> &operator++() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
};
} // namespace simdjson

View File

@ -0,0 +1,86 @@
namespace {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
simdjson_really_inline array_iterator::array_iterator(json_iterator_ref &_iter) noexcept : iter{&_iter} {}
simdjson_really_inline array_iterator::array_iterator() noexcept = default;
simdjson_really_inline array_iterator::array_iterator(const array_iterator &_a) noexcept = default;
simdjson_really_inline array_iterator &array_iterator::operator=(const array_iterator &_a) noexcept = default;
simdjson_really_inline simdjson_result<value> array_iterator::operator*() noexcept {
if (error) { iter->release(); return error; }
return value::start(iter->borrow());
}
simdjson_really_inline bool array_iterator::operator==(const array_iterator &other) noexcept {
return !(*this != other);
}
simdjson_really_inline bool array_iterator::operator!=(const array_iterator &) noexcept {
return iter->is_alive();
}
simdjson_really_inline array_iterator &array_iterator::operator++() noexcept {
bool has_value;
error = (*iter)->has_next_element().get(has_value); // If there's an error, has_next stays true.
if (!(error || has_value)) { iter->release(); }
return *this;
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // unnamed namespace
namespace simdjson {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::simdjson_result() noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>({}, SUCCESS)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::simdjson_result(
SIMDJSON_IMPLEMENTATION::ondemand::array_iterator &&value
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>(value))
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>({}, error)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::simdjson_result(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &a
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>(a)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::operator=(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &a
) noexcept {
first = a.first;
second = a.second;
return *this;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::operator*() noexcept {
if (error()) { second = SUCCESS; return error(); }
return *first;
}
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &other) noexcept {
if (error()) { return true; }
return first == other.first;
}
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &other) noexcept {
if (error()) { return false; }
return first != other.first;
}
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator>::operator++() noexcept {
if (error()) { return *this; }
++first;
return *this;
}
} // namespace simdjson

View File

@ -0,0 +1,78 @@
#include "simdjson/error.h"
namespace {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
class value;
class document;
/**
* A forward-only JSON array.
*/
class array_iterator {
public:
simdjson_really_inline array_iterator(json_iterator_ref &iter) noexcept;
simdjson_really_inline array_iterator(const array_iterator &a) noexcept;
simdjson_really_inline array_iterator &operator=(const array_iterator &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const array_iterator &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const array_iterator &) noexcept;
// Checks for ']' and ','
simdjson_really_inline array_iterator &operator++() noexcept;
private:
json_iterator_ref *iter{};
/**
* Error, if there is one. Errors are only yielded once.
*
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
* this is not elided, we should make sure it's at least not using up a register. Failing that,
* we should store it in document so there's only one of them.
*/
error_code error{};
simdjson_really_inline array_iterator() noexcept;
friend class array;
friend struct simdjson_result<array_iterator>;
};
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // unnamed namespace
namespace simdjson {
template<>
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> : public internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> {
public:
simdjson_really_inline simdjson_result() noexcept;
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::array_iterator &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &a) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &operator=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &) noexcept;
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> &operator++() noexcept;
};
} // namespace simdjson

View File

@ -22,7 +22,7 @@ protected:
static simdjson_really_inline simdjson_result<field> start(json_iterator_ref &&iter) noexcept;
static simdjson_really_inline simdjson_result<field> start(json_iterator_ref &&iter, raw_json_string key) noexcept;
friend struct simdjson_result<field>;
friend class object;
friend class object_iterator;
};
} // namespace ondemand

View File

@ -46,8 +46,7 @@ namespace ondemand {
simdjson_really_inline object::object() noexcept = default;
simdjson_really_inline object::object(json_iterator_ref &&_iter) noexcept
: iter{std::forward<json_iterator_ref>(_iter)},
at_start{true},
error{SUCCESS}
at_start{true}
{
}
simdjson_really_inline object::object(object &&other) noexcept = default;
@ -63,22 +62,22 @@ simdjson_really_inline object::~object() noexcept {
}
simdjson_really_inline error_code object::find_field(const std::string_view key) noexcept {
if (error) { return report_error(); }
if (!iter.is_alive()) { return NO_SUCH_FIELD; }
// Unless this is the first field, we need to advance past the , and check for }
error_code error;
bool has_value;
if (at_start) {
at_start = false;
has_value = true;
} else {
if ((error = iter->has_next_field().get(has_value) )) { return report_error(); }
if ((error = iter->has_next_field().get(has_value) )) { iter.release(); return error; }
}
while (has_value) {
// Get the key
raw_json_string actual_key;
if ((error = iter->field_key().get(actual_key) )) { return report_error(); };
if ((error = iter->field_value() )) { return report_error(); }
if ((error = iter->field_key().get(actual_key) )) { iter.release(); return error; };
if ((error = iter->field_value() )) { iter.release(); return error; }
// Check if it matches
if (actual_key == key) {
@ -87,7 +86,7 @@ simdjson_really_inline error_code object::find_field(const std::string_view key)
}
logger::log_event(*iter, "no match", key, -2);
SIMDJSON_TRY( iter->skip() ); // Skip the value entirely
if ((error = iter->has_next_field().get(has_value) )) { return report_error(); }
if ((error = iter->has_next_field().get(has_value) )) { iter.release(); return error; }
}
// If the loop ended, we're out of fields to look at.
@ -115,46 +114,13 @@ simdjson_really_inline object object::started(json_iterator_ref &&iter) noexcept
if (!iter->started_object()) { iter.release(); }
return object(std::forward<json_iterator_ref>(iter));
}
simdjson_really_inline object::iterator object::begin() noexcept {
return *this;
simdjson_really_inline object_iterator object::begin() noexcept {
SIMDJSON_ASSUME(!iter.is_alive() || at_start);
at_start = false;
return iter;
}
simdjson_really_inline object::iterator object::end() noexcept {
return *this;
}
simdjson_really_inline error_code object::report_error() noexcept {
SIMDJSON_ASSUME(error);
iter.release();
return error;
}
//
// object::iterator
//
simdjson_really_inline object::iterator::iterator(object &_o) noexcept : o{&_o} {}
simdjson_really_inline object::iterator::iterator() noexcept = default;
simdjson_really_inline object::iterator::iterator(const object::iterator &_o) noexcept = default;
simdjson_really_inline object::iterator &object::iterator::operator=(const object::iterator &_o) noexcept = default;
simdjson_really_inline simdjson_result<field> object::iterator::operator*() noexcept {
if (o->error) { return o->report_error(); }
return field::start(o->iter.borrow());
}
simdjson_really_inline bool object::iterator::operator==(const object::iterator &other) noexcept {
return !(*this != other);
}
simdjson_really_inline bool object::iterator::operator!=(const object::iterator &) noexcept {
return o->iter.is_alive();
}
simdjson_really_inline object::iterator &object::iterator::operator++() noexcept {
if (o->error) { return *this; }
o->at_start = false;
bool has_value;
o->error = o->iter->has_next_field().get(has_value);
if (!(o->error || has_value)) { o->iter.release(); }
return *this;
simdjson_really_inline object_iterator object::end() noexcept {
return {};
}
} // namespace ondemand
@ -168,13 +134,13 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object>(error) {}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::begin() noexcept {
if (error()) { return error(); }
return SIMDJSON_IMPLEMENTATION::ondemand::object::iterator(first);
return first.begin();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::end() noexcept {
if (error()) { return error(); }
return {};
return first.end();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::operator[](std::string_view key) & noexcept {
if (error()) { return error(); }
@ -185,60 +151,4 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first)[key];
}
//
// object::iterator
//
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::simdjson_result() noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>({}, SUCCESS)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::simdjson_result(
SIMDJSON_IMPLEMENTATION::ondemand::object::iterator &&value
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>(value))
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>({}, error)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::simdjson_result(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &o
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>(o)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::operator=(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &o
) noexcept {
first = o.first;
second = o.second;
return *this;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::operator*() noexcept {
if (error()) { second = SUCCESS; return error(); }
return *first;
}
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &other) noexcept {
if (error()) { return true; }
return first == other.first;
}
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &other) noexcept {
if (error()) { return false; }
return first != other.first;
}
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator>::operator++() noexcept {
if (error()) { return *this; }
++first;
return *this;
}
} // namespace simdjson

View File

@ -16,32 +16,8 @@ public:
object(const object &) = delete;
object &operator=(const object &) = delete;
class iterator {
public:
simdjson_really_inline iterator(object &o) noexcept;
simdjson_really_inline iterator(const object::iterator &o) noexcept;
simdjson_really_inline iterator &operator=(const object::iterator &o) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const object::iterator &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const object::iterator &) noexcept;
// Checks for ']' and ','
simdjson_really_inline object::iterator &operator++() noexcept;
private:
object *o{};
simdjson_really_inline iterator() noexcept;
friend struct simdjson_result<object::iterator>;
};
simdjson_really_inline object::iterator begin() noexcept;
simdjson_really_inline object::iterator end() noexcept;
simdjson_really_inline object_iterator begin() noexcept;
simdjson_really_inline object_iterator end() noexcept;
simdjson_really_inline simdjson_result<value> operator[](const std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<value> operator[](const std::string_view key) && noexcept;
@ -63,8 +39,6 @@ protected:
*/
simdjson_really_inline object(json_iterator_ref &&_iter) noexcept;
simdjson_really_inline error_code report_error() noexcept;
simdjson_really_inline error_code find_field(const std::string_view key) noexcept;
/**
@ -81,15 +55,6 @@ protected:
* or * call, and SSA optimizers commonly do first-iteration loop optimization.
*/
bool at_start{};
/**
* Error, if there is one. Errors are only yielded once.
*
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
* this is not elided, we should make sure it's at least not using up a register. Failing that,
* we should store it in document so there's only one of them.
*/
error_code error{};
friend class value;
friend class document;
@ -108,33 +73,10 @@ public:
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> begin() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> end() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> begin() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> end() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) && noexcept;
};
template<>
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> : public internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> {
public:
simdjson_really_inline simdjson_result() noexcept;
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object::iterator &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &a) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &operator=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &) noexcept;
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object::iterator> &operator++() noexcept;
};
} // namespace simdjson

View File

@ -0,0 +1,91 @@
namespace {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
//
// object_iterator
//
simdjson_really_inline object_iterator::object_iterator(json_iterator_ref &_iter) noexcept : iter{&_iter} {}
simdjson_really_inline object_iterator::object_iterator() noexcept = default;
simdjson_really_inline object_iterator::object_iterator(const object_iterator &_o) noexcept = default;
simdjson_really_inline object_iterator &object_iterator::operator=(const object_iterator &_o) noexcept = default;
simdjson_really_inline simdjson_result<field> object_iterator::operator*() noexcept {
if (error) { iter->release(); return error; }
return field::start(iter->borrow());
}
simdjson_really_inline bool object_iterator::operator==(const object_iterator &other) noexcept {
return !(*this != other);
}
simdjson_really_inline bool object_iterator::operator!=(const object_iterator &) noexcept {
return iter->is_alive();
}
simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
if (error) { return *this; }
bool has_value;
error = (*iter)->has_next_field().get(has_value);
if (!(error || has_value)) { iter->release(); }
return *this;
}
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // unnamed namespace
namespace simdjson {
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result() noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>({}, SUCCESS)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(
SIMDJSON_IMPLEMENTATION::ondemand::object_iterator &&value
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(value))
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>({}, error)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::simdjson_result(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &o
) noexcept
: internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>(o)
{
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator=(
const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &o
) noexcept {
first = o.first;
second = o.second;
return *this;
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator*() noexcept {
if (error()) { second = SUCCESS; return error(); }
return *first;
}
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) noexcept {
if (error()) { return true; }
return first == other.first;
}
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &other) noexcept {
if (error()) { return false; }
return first != other.first;
}
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator>::operator++() noexcept {
if (error()) { return *this; }
++first;
return *this;
}
} // namespace simdjson

View File

@ -0,0 +1,73 @@
#include "simdjson/error.h"
namespace {
namespace SIMDJSON_IMPLEMENTATION {
namespace ondemand {
class field;
class object_iterator {
public:
simdjson_really_inline object_iterator(json_iterator_ref &iter) noexcept;
simdjson_really_inline object_iterator(const object_iterator &o) noexcept;
simdjson_really_inline object_iterator &operator=(const object_iterator &o) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
// MUST ONLY BE CALLED ONCE PER ITERATION.
simdjson_really_inline simdjson_result<field> operator*() noexcept;
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const object_iterator &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const object_iterator &) noexcept;
// Checks for ']' and ','
simdjson_really_inline object_iterator &operator++() noexcept;
private:
json_iterator_ref *iter{};
/**
* Error, if there is one. Errors are only yielded once.
*
* PERF NOTE: we *hope* this will be elided into control flow, as it is only used (a) in the first
* iteration of the loop, or (b) for the final iteration after a missing comma is found in ++. If
* this is not elided, we should make sure it's at least not using up a register. Failing that,
* we should store it in document so there's only one of them.
*/
error_code error{};
simdjson_really_inline object_iterator() noexcept;
friend struct simdjson_result<object_iterator>;
friend class object;
};
} // namespace ondemand
} // namespace SIMDJSON_IMPLEMENTATION
} // unnamed namespace
namespace simdjson {
template<>
struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> : public internal::simdjson_result_base<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> {
public:
simdjson_really_inline simdjson_result() noexcept;
simdjson_really_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::object_iterator &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &a) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &operator=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &a) noexcept;
//
// Iterator interface
//
// Reads key and value, yielding them to the user.
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::field> operator*() noexcept; // MUST ONLY BE CALLED ONCE PER ITERATION.
// Assumes it's being compared with the end. true if depth < iter->depth.
simdjson_really_inline bool operator==(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &) noexcept;
// Assumes it's being compared with the end. true if depth >= iter->depth.
simdjson_really_inline bool operator!=(const simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &) noexcept;
// Checks for ']' and ','
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> &operator++() noexcept;
};
} // namespace simdjson

View File

@ -141,6 +141,17 @@ simdjson_really_inline value::operator bool() && noexcept(false) {
}
#endif
simdjson_really_inline simdjson_result<array_iterator> value::begin() & noexcept {
if (*json != '[') {
log_error("not an array");
return INCORRECT_TYPE;
}
if (!iter->started_array()) { iter.release(); }
return array_iterator(iter);
}
simdjson_really_inline simdjson_result<array_iterator> value::end() & noexcept {
return {};
}
simdjson_really_inline simdjson_result<value> value::operator[](std::string_view key) && noexcept {
return std::forward<value>(*this).get_object()[key];
}
@ -188,14 +199,14 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
{
}
// simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::begin() & noexcept {
// if (error()) { return error(); }
// return std::move(first).get_array().begin();
// }
// simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::end() & noexcept {
// if (error()) { return error(); }
// return {};
// }
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::begin() & noexcept {
if (error()) { return error(); }
return first.begin();
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::end() & noexcept {
if (error()) { return error(); }
return {};
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::operator[](std::string_view key) noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::value>(first)[key];

View File

@ -9,6 +9,7 @@ class document;
class field;
class object;
class raw_json_string;
class array_iterator;
/**
* An ephemeral JSON value returned during iteration.
@ -49,8 +50,8 @@ public:
simdjson_really_inline operator bool() && noexcept(false);
#endif
// simdjson_really_inline simdjson_result<array_iterator<value>> begin() & noexcept;
// simdjson_really_inline simdjson_result<array_iterator<value>> end() & noexcept;
simdjson_really_inline simdjson_result<array_iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<array_iterator> end() & noexcept;
simdjson_really_inline simdjson_result<value> operator[](std::string_view key) && noexcept;
simdjson_really_inline simdjson_result<value> operator[](const char *key) && noexcept;
@ -78,7 +79,7 @@ protected:
const uint8_t *json{}; // The JSON text of the value
friend class document;
friend class array;
friend class array_iterator;
friend class field;
friend class object;
friend struct simdjson_result<value>;
@ -121,8 +122,8 @@ public:
simdjson_really_inline operator bool() && noexcept(false);
#endif
// simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> begin() & noexcept;
// simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array::iterator> end() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> begin() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> end() & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) noexcept;
};