1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef LIBPANDABASE_UTILS_JSON_PARSER_H
17 #define LIBPANDABASE_UTILS_JSON_PARSER_H
18 
19 #include <string>
20 #include <vector>
21 #include <unordered_map>
22 #include <variant>
23 #include <memory>
24 #include <algorithm>
25 
26 #include "macros.h"
27 
28 WEAK_FOR_LTO_START
29 
30 namespace panda {
31 
32 class JsonObject {
33 public:
34     class Value;
35     using StringT = std::string;
36     using NumT = double;
37     using BoolT = bool;
38     using ArrayT = std::vector<Value>;
39     using Key = StringT;
40     using JsonObjPointer = std::unique_ptr<JsonObject>;
41 
42     class Value {
43     public:
44         Value() = default;
45         ~Value() = default;
46         NO_COPY_SEMANTIC(Value);
move(rhs.value_)47         Value(Value &&rhs) noexcept: value_(std::move(rhs.value_))
48         {
49             rhs.value_ = std::monostate {};
50         }
51         Value &operator=(Value &&rhs) noexcept
52         {
53             value_ = std::move(rhs.value_);
54             rhs.value_ = std::monostate {};
55             return *this;
56         }
57 
58         template <typename T>
59         void SetValue(T &&rhs) noexcept
60         {
61             value_ = std::forward<T>(rhs);
62         }
63 
64         template <typename T>
Get()65         T *Get()
66         {
67             return std::get_if<T>(&value_);
68         }
69         template <typename T>
Get() const70         const T *Get() const
71         {
72             return std::get_if<T>(&value_);
73         }
74 
75     private:
76         std::variant<std::monostate, StringT, NumT, BoolT, ArrayT, JsonObjPointer> value_;
77     };
78 
79     // Recursive descent parser:
80     class Parser {
81     public:
Parser(JsonObject *target)82         explicit Parser(JsonObject *target) : current_obj_(target) {}
83         bool Parse(const std::string &text);
84         bool Parse(std::streambuf *stream_buf);
85 
86         virtual ~Parser() = default;
87 
88         NO_COPY_SEMANTIC(Parser);
89         NO_MOVE_SEMANTIC(Parser);
90 
91     private:
92         bool Parse();
93 
94         bool GetJsonObject(JsonObject *empty_obj);
95         bool GetValue();
96         bool GetString(char delim);
97         bool GetJsonString();
98         bool GetNum();
99         bool GetBool();
100         bool GetArray();
101         bool InsertKeyValuePairIn(JsonObject *obj);
102 
103         char GetSymbol();
104         char PeekSymbol();
105         bool TryGetSymbol(int symbol);
106 
107         static bool IsWhitespace(int symbol);
108 
109     private:
110         std::istream istream_ {nullptr};
111         JsonObject *current_obj_ {nullptr};
112         Value parsed_temp_;
113         StringT string_temp_;
114 
115         size_t log_recursion_level_ {0};
116     };
117 
118 public:
119     JsonObject() = default;
120     ~JsonObject() = default;
121     NO_COPY_SEMANTIC(JsonObject);
122     NO_MOVE_SEMANTIC(JsonObject);
JsonObject(const std::string &text)123     explicit JsonObject(const std::string &text)
124     {
125         Parser(this).Parse(text);
126     }
JsonObject(std::streambuf *stream_buf)127     explicit JsonObject(std::streambuf *stream_buf)
128     {
129         Parser(this).Parse(stream_buf);
130     }
131 
GetSize() const132     size_t GetSize() const
133     {
134         ASSERT(values_map_.size() == keys_.size());
135         ASSERT(values_map_.size() == string_map_.size());
136         return values_map_.size();
137     }
138 
GetIndexByKey(const Key &key) const139     size_t GetIndexByKey(const Key &key) const
140     {
141         auto it = std::find(keys_.begin(), keys_.end(), key);
142         if (it != keys_.end()) {
143             return it - keys_.begin();
144         }
145         return static_cast<size_t>(-1);
146     }
GetKeyByIndex(size_t idx) const147     const auto &GetKeyByIndex(size_t idx) const
148     {
149         ASSERT(idx < GetSize());
150         return keys_[idx];
151     }
152 
153     template <typename T>
154     const T *GetValue(const Key &key) const
155     {
156         auto iter = values_map_.find(key);
157         return (iter == values_map_.end()) ? nullptr : iter->second.Get<T>();
158     }
159     const StringT *GetValueSourceString(const Key &key) const
160     {
161         auto iter = string_map_.find(key);
162         return (iter == string_map_.end()) ? nullptr : &iter->second;
163     }
164     template <typename T>
165     const T *GetValue(size_t idx) const
166     {
167         auto iter = values_map_.find(GetKeyByIndex(idx));
168         return (iter == values_map_.end()) ? nullptr : iter->second.Get<T>();
169     }
170 
171     const auto &GetUnorderedMap() const
172     {
173         return values_map_;
174     }
175 
176     bool IsValid() const
177     {
178         return is_valid_;
179     }
180 
181 private:
182     bool is_valid_ {false};
183     std::unordered_map<Key, Value> values_map_;
184     // String representation is stored additionally as a "source" of scalar values:
185     std::unordered_map<Key, StringT> string_map_;
186 
187     // Stores the order in which keys were added (allows to access elements by index):
188     std::vector<Key> keys_;
189 };
190 
191 }  // namespace panda
192 
193 WEAK_FOR_LTO_END
194 
195 #endif  // LIBPANDABASE_UTILS_JSON_PARSER_H
196