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