lichao
2021-06-02 94f2a94f38261528d98a8ece4fcdb386cbca6566
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#ifndef JSON_B360EKF1
#define JSON_B360EKF1
 
#include <algorithm>
#include <boost/variant.hpp>
#include <map>
#include <string>
#include <vector>
 
namespace ssjson
{
 
class JValue
{
public:
    typedef std::string key_type;
    typedef long long int_type;
    typedef long double float_type;
    typedef JValue value_type;
    typedef std::map<key_type, value_type> object_type;
    typedef object_type::value_type pair_type;
    typedef std::vector<value_type> array_type;
 
    enum JVType { jv_null,
                  jv_int,
                  jv_float,
                  jv_bool,
                  jv_string,
                  jv_object,
                  jv_array };
    std::string name() const
    {
        static const char *names[] = {"jv_null", "jv_int", "jv_float", "jv_bool", "jv_string", "jv_object", "jv_array"};
        return names[type()];
    }
 
private:
    typedef boost::variant<std::nullptr_t, int_type, float_type, bool, std::string, object_type, array_type> data_type;
 
    template <class C>
    const C &val() const { return ref_val<C>(); }
    template <class C>
    C &val() { return const_cast<C &>(ref_val<C>()); }
 
    template <class C>
    class TInitValue
    {
        typedef C value_t;
        typedef std::vector<TInitValue> list_t;
        mutable boost::variant<value_t, list_t> data_;
 
    public:
        template <class T>
        TInitValue(const T &t) :
            data_(value_t(t)) {}
        template <class T>
        TInitValue(T &&t) :
            data_(value_t(std::move(t))) {}
        TInitValue(std::initializer_list<TInitValue> l) :
            data_(list_t(l)){};
        bool is_value() const { return data_.which() == 0; }
        bool is_list() const { return data_.which() == 1; }
        const list_t &list() const { return boost::get<list_t>(data_); }
        const value_t &value() const { return boost::get<value_t>(data_); }
    };
    typedef TInitValue<JValue> InitValue;
    typedef std::initializer_list<InitValue> InitList;
 
    template <class Iter>
    static object_type MakeObject(Iter begin, Iter end)
    {
        object_type obj;
        for (auto it = begin; it != end; ++it) {
            obj.emplace(std::move(it->list()[0].value().template val<key_type>()), (it->list()[1]));
        }
        return obj;
    }
    template <class Iter>
    static array_type MakeArray(Iter begin, Iter end) { return array_type(begin, end); }
    template <class Iter>
    static JValue FromInit(Iter begin, Iter end)
    {
        auto like_object_item = [](const InitValue &v) {
            return v.is_list() &&
                   v.list().size() == 2 &&
                   v.list()[0].is_value() &&
                   v.list()[0].value().type() == jv_string;
        };
        if (std::all_of(begin, end, like_object_item)) {
            return MakeObject(begin, end);
        } else {
            return MakeArray(begin, end);
        }
    }
    static JValue FromInit(const InitValue &ji)
    {
        if (ji.is_value()) {
            return std::move(ji.value());
        } else {
            return FromInit(ji.list().begin(), ji.list().end());
        }
    }
 
public:
    struct DumpOptions {
        int indent_step_ = 0;
        int indent_level_ = 0;
        bool escape_unicode_ = false;
    };
    JValue() :
        data_(object_type()) { static_assert(sizeof(JValue) == sizeof(data_type), "JValue should simple wrap data_type with no other fields."); }
#define SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(decl, expr) \
    JValue(decl) : data_(expr) {}                      \
    JValue &operator=(decl)                            \
    {                                                  \
        data_ = (expr);                                \
        return *this;                                  \
    }
    // operator=() seems faster than JValue(exer).swap(data_).
    // copy
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(const JValue &v, v.data_) // self;
#define MAP_TYPE_TO_JSON_TYPE(decl, expr)          \
public:                                            \
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(decl, expr) \
private:                                           \
    static auto JVTypeAccept(decl)->std::remove_reference<decltype(expr)>::type
#define MAP_TYPE_TO_JSON_TYPE_BIDIR(decl, expr) \
    MAP_TYPE_TO_JSON_TYPE(decl, expr);          \
                                                \
private:                                        \
    static auto JVTypeReturn(decl)->std::remove_reference<decltype(expr)>::type
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const std::nullptr_t, nullptr);
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const short v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned short v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const int v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned int v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const long v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned long v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const long long v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const unsigned long long v, int_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const float v, float_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const double v, float_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const long double v, float_type(v));
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const bool v, v);
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const std::string &v, v);
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const object_type &v, v);
    MAP_TYPE_TO_JSON_TYPE_BIDIR(const array_type &v, v);
    MAP_TYPE_TO_JSON_TYPE(const char *v, std::string(v));
#undef MAP_TYPE_TO_JSON_TYPE_BIDIR
#undef MAP_TYPE_TO_JSON_TYPE
    template <class T>
    static void JVTypeAccept(T); // use void to disable other types.
    template <class T>
    static void JVTypeReturn(T); // use void to disable other types.
public:
    // move
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(JValue &&v, std::move(v.data_)) // self
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(std::string &&v, std::move(v))  // and other classes
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(object_type &&v, std::move(v))
    SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT(array_type &&v, std::move(v))
#undef SUPPORT_CONSTRUCTOR_AND_ASSIGNMENT
 
    static JValue Object()
    {
        return (object_type());
    }
    static JValue Object(InitList l) { return (MakeObject(l.begin(), l.end())); }
    static JValue Array() { return (array_type()); }
    static JValue Array(InitList l) { return (MakeArray(l.begin(), l.end())); }
    JValue(InitList l) :
        JValue(FromInit(l.begin(), l.end())) {}
    JValue(const InitValue &ji) :
        JValue(FromInit(ji)) {}
    JVType type() const { return static_cast<JVType>(data_.which()); }
 
    std::string dump(const DumpOptions &opt_in) const;
    std::string dump(const int indent_step = 0, const int indent_level = 0, const bool escape_unicode = false) const
    {
        DumpOptions opt;
        opt.indent_step_ = indent_step;
        opt.indent_level_ = indent_level;
        opt.escape_unicode_ = escape_unicode;
        return dump(opt);
    }
    bool parse(const std::string &s) { return parse(s.c_str(), s.c_str() + s.size()) > 0; }
    int parse(const char *begin, const char *end);
    void swap(JValue &a) { data_.swap(a.data_); }
 
    template <class T>
    T get_value() const { return val<decltype(JVTypeReturn(T()))>(); }
    template <class T>
    void put_value(T &&v) { *this = v; }
    const object_type &object() const { return val<object_type>(); }
    object_type &object() { return val<object_type>(); }
    const array_type &array() const { return val<array_type>(); }
    array_type &array() { return val<array_type>(); }
    bool is_object() const { return type() == jv_object; }
    bool is_array() const { return type() == jv_array; }
 
    // array ops
    const value_type &operator[](const size_t idx) const { return array()[idx]; }
    value_type &operator[](const size_t idx) { return array()[idx]; }
    const value_type &at(const size_t idx) const { return array().at(idx); }
    value_type &at(const size_t idx) { return array().at(idx); }
    void push_back(const value_type &v) { array().push_back(v); }
    void push_back(value_type &&v) { array().push_back(std::move(v)); }
 
    // object ops
    value_type &operator[](const key_type &key) { return object()[key]; }
    const value_type &at(const key_type &key) const { return object().at(key); }
    value_type &at(const key_type &key) { return object().at(key); }
    const value_type &child(const key_type &path) const { return ref_child(path); }
    value_type &child(const key_type &path) { return const_cast<value_type &>(ref_child(path)); }
    template <class T>
    T get(const key_type &path) const { return child(path).val<decltype(JVTypeReturn(T()))>(); }
    template <class T>
    auto get(const key_type &path, const T &def) const -> typename std::remove_reference<decltype(JVTypeAccept(def))>::type
    {
        try {
            return get<decltype(JVTypeAccept(def))>(path);
        } catch (...) {
            return def;
        }
    }
    value_type &put(pair_type &&elem)
    {
        const key_type &key = elem.first;
        auto sep = key.find('.');
        if (sep == key_type::npos) {
            auto r = object().lower_bound(elem.first);
            if (r != object().end() && r->first == elem.first) {
                r->second = std::move(elem.second);
                return r->second;
            } else {
                return object().emplace_hint(r, std::move(elem))->second;
            }
        } else {
            return (*this)[key.substr(0, sep)].put(pair_type(key.substr(sep + 1), std::move(elem.second)));
        }
    }
    value_type &put(const pair_type &elem)
    {
        pair_type tmp(elem);
        return put(std::move(tmp));
    }
    value_type &put(const key_type &k, const value_type &v) { return put(pair_type(k, v)); }
    value_type &put(const key_type &k, value_type &&v) { return put(pair_type(k, std::move(v))); }
    value_type &put(key_type &&k, const value_type &v) { return put(pair_type(std::move(k), v)); }
    value_type &put(key_type &&k, value_type &&v) { return put(pair_type(std::move(k), std::move(v))); }
 
private:
    template <class C>
    const C &ref_val() const
    {
        try {
            return boost::get<C>(data_);
        } catch (std::exception &) {
            throw std::runtime_error("json get error, " + name() + " is not a " + JValue(C()).name());
        }
    }
    const value_type &ref_child(const key_type &path) const
    {
        auto sep = path.find('.');
        if (sep == key_type::npos) {
            return at(path);
        } else {
            return at(path.substr(0, sep)).ref_child(path.substr(sep + 1));
        }
    }
    data_type data_;
};
 
typedef JValue Json;
 
} // namespace ssjson
 
#endif // end of include guard: JSON_B360EKF1