userver: userver/formats/json/parser/array_parser.hpp Source File
Loading...
Searching...
No Matches
array_parser.hpp
1#pragma once
2
3#include <userver/formats/common/path.hpp>
4#include <userver/formats/json/parser/typed_parser.hpp>
5#include <userver/utils/meta.hpp>
6
7USERVER_NAMESPACE_BEGIN
8
9namespace formats::json::parser {
10
11// Parser for array -> vector/set/unordered_set
12template <typename Item, typename ItemParser, typename Array = std::vector<Item>>
13class ArrayParser final : public TypedParser<Array>, public Subscriber<Item> {
14public:
15 explicit ArrayParser(ItemParser& item_parser)
16 : item_parser_(item_parser)
17 {
18 this->item_parser_.Subscribe(*this);
19 }
20
21 void Reset() override {
22 index_ = 0;
23 state_ = State::kStart;
24 storage_.clear();
25
26 if constexpr (meta::kIsVector<Array>) {
27 /*
28 * Heuristics:
29 * STL impls have a small initial capacity of vector.
30 * It leads to multiple reallocations during inserts.
31 * We intentionally give up some maybe-unused space to lower realloc
32 * count.
33 */
34 storage_.reserve(16);
35 }
36 }
37
38protected:
39 void StartArray() override {
40 if (state_ == State::kStart) {
41 state_ = State::kInside;
42 } else {
43 PushParser("array");
44 Parser().StartArray();
45 }
46 }
47 void EndArray() override {
48 if (state_ == State::kInside) {
49 this->SetResult(std::move(storage_));
50 return;
51 }
52 // impossible?
53 this->Throw("end of array");
54 }
55
56 void Int64(int64_t i) override {
57 PushParser("integer");
58 Parser().Int64(i);
59 }
60 void Uint64(uint64_t i) override {
61 PushParser("integer");
62 Parser().Uint64(i);
63 }
64 void Null() override {
65 PushParser("null");
66 Parser().Null();
67 }
68 void Bool(bool b) override {
69 PushParser("bool");
70 Parser().Bool(b);
71 }
72 void Double(double d) override {
73 PushParser("double");
74 Parser().Double(d);
75 }
76 void String(std::string_view sw) override {
77 PushParser("string");
78 Parser().String(sw);
79 }
80 void StartObject() override {
81 PushParser("object");
82 Parser().StartObject();
83 }
84
85 std::string Expected() const override { return "array"; }
86
87 void PushParser(std::string_view what) {
88 if (state_ != State::kInside) {
89 // Error path must not include [x] - we're not inside an array yet
90 this->parser_state_->PopMe(*this);
91
92 this->Throw(std::string(what));
93 }
94
95 this->item_parser_.Reset();
96 this->parser_state_->PushParser(item_parser_.GetParser());
97 index_++;
98 }
99
100 void OnSend(Item&& item) override {
101 if constexpr (!meta::kIsVector<Array>) {
102 this->storage_.insert(std::move(item));
103 } else {
104 this->storage_.push_back(std::move(item));
105 }
106 }
107
108 std::string GetPathItem() const override { return common::GetIndexString(index_ - 1); }
109
110 BaseParser& Parser() { return item_parser_.GetParser(); }
111
112private:
113 ItemParser& item_parser_;
114 std::optional<size_t> min_items_, max_items_;
115
116 enum class State {
117 kStart,
118 kInside,
119 };
120 size_t index_{0};
121 State state_{State::kStart};
122 Array storage_;
123};
124
125} // namespace formats::json::parser
126
127USERVER_NAMESPACE_END