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