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