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
28WEAK_FOR_LTO_START
29
30namespace panda {
31
32class JsonObject {
33public:
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);
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>
65        T *Get()
66        {
67            return std::get_if<T>(&value_);
68        }
69        template <typename T>
70        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:
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
118public:
119    JsonObject() = default;
120    ~JsonObject() = default;
121    NO_COPY_SEMANTIC(JsonObject);
122    NO_MOVE_SEMANTIC(JsonObject);
123    explicit JsonObject(const std::string &text)
124    {
125        Parser(this).Parse(text);
126    }
127    explicit JsonObject(std::streambuf *stream_buf)
128    {
129        Parser(this).Parse(stream_buf);
130    }
131
132    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
139    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    }
147    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
181private:
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
193WEAK_FOR_LTO_END
194
195#endif  // LIBPANDABASE_UTILS_JSON_PARSER_H
196