Skip to content

Commit 4e822b5

Browse files
committed
Ensure only leaf values can push the iterator
1 parent 638bf47 commit 4e822b5

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

src/generic/ondemand/json_iterator-inl.h

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ simdjson_really_inline json_iterator &json_iterator::operator=(json_iterator &&o
1919
return *this;
2020
}
2121
simdjson_really_inline json_iterator::json_iterator(ondemand::parser *_parser) noexcept
22-
: token_iterator(_parser->dom_parser.buf, _parser->dom_parser.structural_indexes.get()), parser{_parser}
22+
: token_iterator(_parser->dom_parser.buf, _parser->dom_parser.structural_indexes.get()),
23+
parser{_parser},
24+
current_string_buf_loc{parser->string_buf.get()},
25+
active_lease_depth{0}
2326
{
2427
// Release the string buf so it can be reused by the next document
2528
logger::log_headers();
26-
current_string_buf_loc = parser->string_buf.get();
2729
}
2830
simdjson_really_inline json_iterator::~json_iterator() noexcept = default;
2931

@@ -261,56 +263,69 @@ simdjson_really_inline bool json_iterator::is_alive() const noexcept {
261263
}
262264

263265
simdjson_really_inline json_iterator_ref json_iterator::borrow() noexcept {
264-
return json_iterator_ref(this);
266+
SIMDJSON_ASSUME(active_lease_depth == 0);
267+
const uint32_t child_depth = 1;
268+
active_lease_depth = child_depth;
269+
return json_iterator_ref(this, child_depth);
265270
}
266271

267272
//
268273
// json_iterator_ref
269274
//
270275
simdjson_really_inline json_iterator_ref::json_iterator_ref() noexcept = default;
271276
simdjson_really_inline json_iterator_ref::json_iterator_ref(json_iterator_ref &&other) noexcept
272-
: iter{std::forward<json_iterator_ref>(other).iter}
277+
: iter{std::exchange(other.iter, nullptr)},
278+
lease_depth{other.lease_depth}
273279
{
274-
other.iter = nullptr;
275280
}
276281
simdjson_really_inline json_iterator_ref &json_iterator_ref::operator=(json_iterator_ref &&other) noexcept {
277-
iter = std::forward<json_iterator_ref>(other).iter;
278-
other.iter = nullptr;
282+
SIMDJSON_ASSUME(!is_active());
283+
iter = std::exchange(other.iter, nullptr);
284+
lease_depth = other.lease_depth;
279285
return *this;
280286
}
281-
simdjson_really_inline json_iterator_ref::json_iterator_ref(json_iterator *_iter) noexcept
282-
: iter{_iter}
287+
simdjson_really_inline json_iterator_ref::json_iterator_ref(json_iterator *_iter, uint32_t _lease_depth) noexcept
288+
: iter{_iter},
289+
lease_depth{_lease_depth}
283290
{
291+
SIMDJSON_ASSUME(is_active());
284292
}
285293
simdjson_really_inline json_iterator_ref::~json_iterator_ref() noexcept {
286294
// The caller MUST consume their value and release the iterator before they die
287-
SIMDJSON_ASSUME(!iter);
295+
SIMDJSON_ASSUME(!is_alive());
288296
}
289297

290298
simdjson_really_inline json_iterator_ref json_iterator_ref::borrow() noexcept {
291-
return json_iterator_ref(iter);
299+
SIMDJSON_ASSUME(is_active());
300+
const uint32_t child_depth = lease_depth + 1;
301+
iter->active_lease_depth = child_depth;
302+
return json_iterator_ref(iter, child_depth);
292303
}
293304
simdjson_really_inline void json_iterator_ref::release() noexcept {
294-
SIMDJSON_ASSUME(is_alive());
305+
SIMDJSON_ASSUME(is_active());
306+
iter->active_lease_depth = lease_depth - 1;
295307
iter = nullptr;
296308
}
297309

298310
simdjson_really_inline json_iterator *json_iterator_ref::operator->() noexcept {
299-
SIMDJSON_ASSUME(is_alive());
311+
SIMDJSON_ASSUME(is_active());
300312
return iter;
301313
}
302314
simdjson_really_inline json_iterator &json_iterator_ref::operator*() noexcept {
303-
SIMDJSON_ASSUME(is_alive());
315+
SIMDJSON_ASSUME(is_active());
304316
return *iter;
305317
}
306318
simdjson_really_inline const json_iterator &json_iterator_ref::operator*() const noexcept {
307-
SIMDJSON_ASSUME(is_alive());
319+
SIMDJSON_ASSUME(is_active());
308320
return *iter;
309321
}
310322

311323
simdjson_really_inline bool json_iterator_ref::is_alive() const noexcept {
312324
return iter != nullptr;
313325
}
326+
simdjson_really_inline bool json_iterator_ref::is_active() const noexcept {
327+
return is_alive() && lease_depth == iter->active_lease_depth;
328+
}
314329

315330

316331
} // namespace ondemand

src/generic/ondemand/json_iterator.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class json_iterator : public token_iterator {
137137
protected:
138138
ondemand::parser *parser{};
139139
uint8_t *current_string_buf_loc{};
140+
uint32_t active_lease_depth{};
140141

141142
simdjson_really_inline json_iterator(ondemand::parser *parser) noexcept;
142143
template<int N>
@@ -150,6 +151,7 @@ class json_iterator : public token_iterator {
150151
friend class value;
151152
friend class raw_json_string;
152153
friend class parser;
154+
friend class json_iterator_ref;
153155
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;
154156
}; // json_iterator
155157

@@ -170,10 +172,12 @@ class json_iterator_ref {
170172
simdjson_really_inline const json_iterator &operator*() const noexcept;
171173

172174
simdjson_really_inline bool is_alive() const noexcept;
175+
simdjson_really_inline bool is_active() const noexcept;
173176

174177
private:
175-
simdjson_really_inline json_iterator_ref(json_iterator *iter) noexcept;
176-
json_iterator *iter;
178+
simdjson_really_inline json_iterator_ref(json_iterator *iter, uint32_t lease_depth) noexcept;
179+
json_iterator *iter{};
180+
uint32_t lease_depth{};
177181

178182
friend class json_iterator;
179183
}; // class json_iterator_ref

0 commit comments

Comments
 (0)