Skip to content

Commit d670906

Browse files
committed
Don't keep a separate at_start boolean in object
1 parent f9c6ded commit d670906

12 files changed

+95
-131
lines changed

.circleci/config.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,12 @@ commands:
105105
ctest $CTEST_FLAGS -L acceptance &&
106106
ctest $CTEST_FLAGS -LE acceptance -LE explicitonly
107107
108-
cmake_test:
108+
cmake_assert_test:
109109
steps:
110110
- run: |
111111
cd build &&
112112
tools/json2json -h &&
113-
ctest $CTEST_FLAGS -L assert &&
114-
ctest $CTEST_FLAGS -LE acceptance -LE explicitonly
113+
ctest $CTEST_FLAGS -L assert
115114
116115
cmake_test_all:
117116
steps:
@@ -155,12 +154,12 @@ jobs:
155154
assert-gcc10:
156155
description: Build the library with asserts on, install it and run tests
157156
executor: gcc10
158-
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCXX_CMAKE_FLAGS_RELEASE=-O3 }
157+
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
159158
steps: [ cmake_test, cmake_assert_test ]
160159
assert-clang10:
161160
description: Build just the library, install it and do a basic test
162161
executor: clang10
163-
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCXX_CMAKE_FLAGS_RELEASE=-O3 }
162+
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
164163
steps: [ cmake_test, cmake_assert_test ]
165164
gcc10-perftest:
166165
description: Build and run performance tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression

include/simdjson/generic/implementation_simdjson_result_base-inl.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@ namespace SIMDJSON_IMPLEMENTATION {
55
// internal::implementation_simdjson_result_base<T> inline implementation
66
//
77

8-
/**
9-
* Create a new empty result with error = UNINITIALIZED.
10-
*/
11-
template<typename T>
12-
simdjson_really_inline implementation_simdjson_result_base<T>::~implementation_simdjson_result_base() noexcept {
13-
}
14-
158
template<typename T>
169
simdjson_really_inline void implementation_simdjson_result_base<T>::tie(T &value, error_code &error) && noexcept {
1710
// on the clang compiler that comes with current macOS (Apple clang version 11.0.0),
@@ -70,9 +63,6 @@ simdjson_really_inline implementation_simdjson_result_base<T>::implementation_si
7063
template<typename T>
7164
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base(T &&value) noexcept
7265
: implementation_simdjson_result_base(std::forward<T>(value), SUCCESS) {}
73-
template<typename T>
74-
simdjson_really_inline implementation_simdjson_result_base<T>::implementation_simdjson_result_base() noexcept
75-
: implementation_simdjson_result_base(T{}, UNINITIALIZED) {}
7666

7767
} // namespace SIMDJSON_IMPLEMENTATION
7868
} // namespace simdjson

include/simdjson/generic/implementation_simdjson_result_base.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct implementation_simdjson_result_base {
3030
/**
3131
* Create a new empty result with error = UNINITIALIZED.
3232
*/
33-
simdjson_really_inline implementation_simdjson_result_base() noexcept;
33+
simdjson_really_inline implementation_simdjson_result_base() noexcept = default;
3434

3535
/**
3636
* Create a new error result.
@@ -47,11 +47,6 @@ struct implementation_simdjson_result_base {
4747
*/
4848
simdjson_really_inline implementation_simdjson_result_base(T &&value, error_code error) noexcept;
4949

50-
/**
51-
* Create a new empty result with error = UNINITIALIZED.
52-
*/
53-
simdjson_really_inline ~implementation_simdjson_result_base() noexcept;
54-
5550
/**
5651
* Move the value and the error to the provided variables.
5752
*
@@ -104,8 +99,8 @@ struct implementation_simdjson_result_base {
10499

105100
#endif // SIMDJSON_EXCEPTIONS
106101

107-
T first;
108-
error_code second;
102+
T first{};
103+
error_code second{UNINITIALIZED};
109104
}; // struct implementation_simdjson_result_base
110105

111106
} // namespace SIMDJSON_IMPLEMENTATION

include/simdjson/generic/ondemand/document.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,16 @@ class array_iterator;
2020
*/
2121
class document {
2222
public:
23-
simdjson_really_inline document(document &&other) noexcept = default;
24-
simdjson_really_inline document &operator=(document &&other) noexcept = default;
25-
2623
/**
2724
* Create a new invalid document.
2825
*
2926
* Exists so you can declare a variable and later assign to it before use.
3027
*/
3128
simdjson_really_inline document() noexcept = default;
32-
simdjson_really_inline document(const document &other) = delete;
33-
simdjson_really_inline document &operator=(const document &other) = delete;
29+
simdjson_really_inline document(const document &other) noexcept = delete;
30+
simdjson_really_inline document(document &&other) noexcept = default;
31+
simdjson_really_inline document &operator=(const document &other) noexcept = delete;
32+
simdjson_really_inline document &operator=(document &&other) noexcept = default;
3433

3534
/**
3635
* Cast this JSON value to an array.

include/simdjson/generic/ondemand/object-inl.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,18 @@ namespace ondemand {
4343
// In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
4444
//
4545

46-
simdjson_warn_unused simdjson_really_inline error_code object::find_field_raw(const std::string_view key) noexcept {
47-
return iter.find_field_raw(key);
48-
}
49-
5046
simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) & noexcept {
51-
SIMDJSON_TRY( find_field_raw(key) );
52-
return value(iter.iter.child());
47+
bool has_value;
48+
SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
49+
if (!has_value) { return NO_SUCH_FIELD; }
50+
return value(iter.child());
5351
}
5452

5553
simdjson_really_inline simdjson_result<value> object::operator[](const std::string_view key) && noexcept {
56-
SIMDJSON_TRY( find_field_raw(key) );
57-
return value(iter.iter.child());
54+
bool has_value;
55+
SIMDJSON_TRY( iter.find_field_raw(key).get(has_value) );
56+
if (!has_value) { return NO_SUCH_FIELD; }
57+
return value(iter.child());
5858
}
5959

6060
simdjson_really_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
@@ -72,16 +72,17 @@ simdjson_really_inline object object::started(value_iterator &iter) noexcept {
7272
return iter;
7373
}
7474
simdjson_really_inline object object::resume(const value_iterator &iter) noexcept {
75-
return { iter, false };
75+
return iter;
7676
}
7777

78-
simdjson_really_inline object::object(const value_iterator &_iter, bool _at_start) noexcept
79-
: iter{_iter, _at_start}
78+
simdjson_really_inline object::object(const value_iterator &_iter) noexcept
79+
: iter{_iter}
8080
{
8181
}
8282

8383
simdjson_really_inline object_iterator object::begin() noexcept {
84-
SIMDJSON_ASSUME( iter.at_start || iter.iter._json_iter->_depth < iter.iter._depth );
84+
// Expanded version of SIMDJSON_ASSUME( iter.at_field_start() || !iter.is_open() )
85+
SIMDJSON_ASSUME( (iter._json_iter->token.index == iter._start_index + 1) || (iter._json_iter->_depth < iter._depth) );
8586
return iter;
8687
}
8788
simdjson_really_inline object_iterator object::end() noexcept {

include/simdjson/generic/ondemand/object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ class object {
5050
static simdjson_really_inline simdjson_result<object> try_start(value_iterator &iter) noexcept;
5151
static simdjson_really_inline object started(value_iterator &iter) noexcept;
5252
static simdjson_really_inline object resume(const value_iterator &iter) noexcept;
53-
simdjson_really_inline object(const value_iterator &iter, bool at_start = true) noexcept;
53+
simdjson_really_inline object(const value_iterator &iter) noexcept;
5454

5555
simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept;
5656

57-
object_iterator iter{};
57+
value_iterator iter{};
5858

5959
friend class value;
6060
friend class document;

include/simdjson/generic/ondemand/object_iterator-inl.h

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ namespace ondemand {
66
// object_iterator
77
//
88

9-
simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter, bool _at_start) noexcept
10-
: iter{_iter},
11-
at_start{_at_start}
9+
simdjson_really_inline object_iterator::object_iterator(const value_iterator &_iter) noexcept
10+
: iter{_iter}
1211
{}
1312

1413
simdjson_really_inline simdjson_result<field> object_iterator::operator*() noexcept {
@@ -80,39 +79,6 @@ simdjson_really_inline object_iterator &object_iterator::operator++() noexcept {
8079
// In this state, iter.depth < depth, at_start == false, and error == SUCCESS.
8180
//
8281

83-
simdjson_warn_unused simdjson_really_inline error_code object_iterator::find_field_raw(const std::string_view key) noexcept {
84-
if (!iter.is_open()) { return NO_SUCH_FIELD; }
85-
86-
// Unless this is the first field, we need to advance past the , and check for }
87-
error_code error;
88-
bool has_value;
89-
if (at_start) {
90-
at_start = false;
91-
has_value = true;
92-
} else {
93-
if ((error = iter.skip_child() )) { iter.abandon(); return error; }
94-
if ((error = iter.has_next_field().get(has_value) )) { iter.abandon(); return error; }
95-
}
96-
while (has_value) {
97-
// Get the key
98-
raw_json_string actual_key;
99-
if ((error = iter.field_key().get(actual_key) )) { iter.abandon(); return error; };
100-
if ((error = iter.field_value() )) { iter.abandon(); return error; }
101-
102-
// Check if it matches
103-
if (actual_key == key) {
104-
logger::log_event(iter, "match", key, -2);
105-
return SUCCESS;
106-
}
107-
logger::log_event(iter, "no match", key, -2);
108-
SIMDJSON_TRY( iter.skip_child() ); // Skip the value entirely
109-
if ((error = iter.has_next_field().get(has_value) )) { iter.abandon(); return error; }
110-
}
111-
112-
// If the loop ended, we're out of fields to look at.
113-
return NO_SUCH_FIELD;
114-
}
115-
11682
} // namespace ondemand
11783
} // namespace SIMDJSON_IMPLEMENTATION
11884
} // namespace simdjson

include/simdjson/generic/ondemand/object_iterator.h

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ class object_iterator {
2929
// Checks for ']' and ','
3030
simdjson_really_inline object_iterator &operator++() noexcept;
3131

32-
/**
33-
* Find the field with the given key. May be used in place of ++.
34-
*/
35-
simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept;
36-
3732
private:
3833
/**
3934
* The underlying JSON iterator.
@@ -42,17 +37,8 @@ class object_iterator {
4237
* is first used, and never changes afterwards.
4338
*/
4439
value_iterator iter{};
45-
/**
46-
* Whether we are at the start.
47-
*
48-
* PERF NOTE: this should be elided into inline control flow: it is only used for the first []
49-
* or * call, and SSA optimizers commonly do first-iteration loop optimization.
50-
*
51-
* SAFETY: this is not safe; the object_iterator can be copied freely, so the state CAN be lost.
52-
*/
53-
bool at_start{};
5440

55-
simdjson_really_inline object_iterator(const value_iterator &iter, bool at_start = true) noexcept;
41+
simdjson_really_inline object_iterator(const value_iterator &iter) noexcept;
5642
friend struct simdjson_result<object_iterator>;
5743
friend class object;
5844
};

include/simdjson/generic/ondemand/token_iterator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ class token_iterator {
8383

8484
friend class json_iterator;
8585
friend class value_iterator;
86+
friend class object;
8687
friend simdjson_really_inline void logger::log_line(const json_iterator &iter, const char *title_prefix, const char *title, std::string_view detail, int delta, int depth_delta) noexcept;
8788
};
8889

include/simdjson/generic/ondemand/value_iterator-inl.h

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,31 +51,38 @@ simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator
5151
}
5252
}
5353

54-
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_raw(const char *key) noexcept {
55-
// We assume we are sitting at a key: at "key": <value>
56-
assert_at_child();
57-
58-
bool has_next;
59-
do {
54+
/**
55+
* Find the field with the given key. May be used in place of ++.
56+
*/
57+
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> value_iterator::find_field_raw(const std::string_view key) noexcept {
58+
if (!is_open()) { return false; }
59+
60+
// Unless this is the first field, we need to advance past the , and check for }
61+
error_code error;
62+
bool has_value;
63+
if (at_first_field()) {
64+
has_value = true;
65+
} else {
66+
if ((error = skip_child() )) { abandon(); return error; }
67+
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
68+
}
69+
while (has_value) {
6070
// Get the key
6171
raw_json_string actual_key;
62-
SIMDJSON_TRY( require_raw_json_string().get(actual_key) );
63-
if (*_json_iter->advance() != ':') { return _json_iter->report_error(TAPE_ERROR, "Missing colon in object field"); }
72+
if ((error = field_key().get(actual_key) )) { abandon(); return error; };
73+
if ((error = field_value() )) { abandon(); return error; }
6474

65-
// Check if the key matches, and return if so
75+
// Check if it matches
6676
if (actual_key == key) {
67-
logger::log_event(*_json_iter, "match", key);
77+
logger::log_event(*this, "match", key, -2);
6878
return true;
6979
}
80+
logger::log_event(*this, "no match", key, -2);
81+
SIMDJSON_TRY( skip_child() ); // Skip the value entirely
82+
if ((error = has_next_field().get(has_value) )) { abandon(); return error; }
83+
}
7084

71-
// Skip the value so we can look at the next key
72-
logger::log_event(*_json_iter, "non-match", key);
73-
SIMDJSON_TRY( skip_child() );
74-
75-
// Check whether the next token is , or }
76-
SIMDJSON_TRY( has_next_field().get(has_next) );
77-
} while (has_next);
78-
logger::log_event(*_json_iter, "no matches", key);
85+
// If the loop ended, we're out of fields to look at.
7986
return false;
8087
}
8188

@@ -382,6 +389,11 @@ simdjson_really_inline bool value_iterator::is_open() const noexcept {
382389
return _json_iter->depth() >= depth();
383390
}
384391

392+
simdjson_really_inline bool value_iterator::at_first_field() const noexcept {
393+
SIMDJSON_ASSUME( _json_iter->token.index > _start_index );
394+
return _json_iter->token.index == _start_index + 1;
395+
}
396+
385397
simdjson_really_inline void value_iterator::abandon() noexcept {
386398
_json_iter->abandon();
387399
}

include/simdjson/generic/ondemand/value_iterator.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ class value_iterator {
5555
*/
5656
simdjson_really_inline bool is_open() const noexcept;
5757

58+
/**
59+
* Tell whether the value is at an object's first field (just after the {).
60+
*/
61+
simdjson_really_inline bool at_first_field() const noexcept;
62+
5863
/**
5964
* Abandon all iteration.
6065
*/
@@ -158,7 +163,7 @@ class value_iterator {
158163
* unescape it. This works well for typical ASCII and UTF-8 keys (almost all of them), but may
159164
* fail to match some keys with escapes (\u, \n, etc.).
160165
*/
161-
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> find_field_raw(const char *key) noexcept;
166+
simdjson_warn_unused simdjson_really_inline simdjson_result<bool> find_field_raw(const std::string_view key) noexcept;
162167

163168
/** @} */
164169

@@ -262,10 +267,10 @@ class value_iterator {
262267
simdjson_really_inline simdjson_result<double> parse_root_double(const uint8_t *json, uint32_t max_len) const noexcept;
263268

264269
simdjson_really_inline void assert_at_start() const noexcept;
265-
simdjson_really_inline void assert_at_root() const noexcept;
270+
simdjson_really_inline void assert_at_root() const noexcept;
266271
simdjson_really_inline void assert_at_child() const noexcept;
267-
simdjson_really_inline void assert_at_next() const noexcept;
268-
simdjson_really_inline void assert_at_non_root_start() const noexcept;
272+
simdjson_really_inline void assert_at_next() const noexcept;
273+
simdjson_really_inline void assert_at_non_root_start() const noexcept;
269274

270275
friend class document;
271276
friend class object;

0 commit comments

Comments
 (0)