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