]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/include/ucl++.h
Since contrib/libcxxrt's ancestry was never correct, subversion 1.8 and
[FreeBSD/FreeBSD.git] / contrib / libucl / include / ucl++.h
1 /*
2  * Copyright (c) 2015, Vsevolod Stakhov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *       * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *       * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #pragma once
26 #include <string>
27 #include <memory>
28 #include <iostream>
29
30 #include "ucl.h"
31
32 // C++11 API inspired by json11: https://github.com/dropbox/json11/
33
34 namespace ucl {
35
36 struct ucl_map_construct_t { };
37 constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
38 struct ucl_array_construct_t { };
39 constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
40
41 class Ucl final {
42 private:
43
44         struct ucl_deleter {
45                 void operator() (ucl_object_t *obj) {
46                         ucl_object_unref (obj);
47                 }
48         };
49
50         static int
51         append_char (unsigned char c, size_t nchars, void *ud)
52         {
53                 std::string *out = reinterpret_cast<std::string *>(ud);
54
55                 out->append (nchars, (char)c);
56
57                 return nchars;
58         }
59         static int
60         append_len (unsigned const char *str, size_t len, void *ud)
61         {
62                 std::string *out = reinterpret_cast<std::string *>(ud);
63
64                 out->append ((const char *)str, len);
65
66                 return len;
67         }
68         static int
69         append_int (int64_t elt, void *ud)
70         {
71                 std::string *out = reinterpret_cast<std::string *>(ud);
72                 auto nstr = std::to_string (elt);
73
74                 out->append (nstr);
75
76                 return nstr.size ();
77         }
78         static int
79         append_double (double elt, void *ud)
80         {
81                 std::string *out = reinterpret_cast<std::string *>(ud);
82                 auto nstr = std::to_string (elt);
83
84                 out->append (nstr);
85
86                 return nstr.size ();
87         }
88
89         static struct ucl_emitter_functions default_emit_funcs()
90         {
91                 struct ucl_emitter_functions func = {
92                         Ucl::append_char,
93                         Ucl::append_len,
94                         Ucl::append_int,
95                         Ucl::append_double,
96                         nullptr,
97                         nullptr
98                 };
99
100                 return func;
101         };
102
103         std::unique_ptr<ucl_object_t, ucl_deleter> obj;
104
105 public:
106         class const_iterator {
107         private:
108                 struct ucl_iter_deleter {
109                         void operator() (ucl_object_iter_t it) {
110                                 ucl_object_iterate_free (it);
111                         }
112                 };
113                 std::shared_ptr<void> it;
114                 std::unique_ptr<Ucl> cur;
115         public:
116                 typedef std::forward_iterator_tag iterator_category;
117
118                 const_iterator(const Ucl &obj) {
119                         it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
120                                         ucl_iter_deleter());
121                         cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
122                         if (!*cur) {
123                                 it.reset ();
124                                 cur.reset ();
125                         }
126                 }
127
128                 const_iterator() {}
129                 const_iterator(const const_iterator &other) = delete;
130                 const_iterator(const_iterator &&other) = default;
131                 ~const_iterator() {}
132
133                 const_iterator& operator=(const const_iterator &other) = delete;
134                 const_iterator& operator=(const_iterator &&other) = default;
135
136                 bool operator==(const const_iterator &other) const
137                 {
138                         if (cur && other.cur) {
139                                 return cur->obj.get() == other.cur->obj.get();
140                         }
141
142                         return !cur && !other.cur;
143                 }
144
145                 bool operator!=(const const_iterator &other) const
146                 {
147                         return !(*this == other);
148                 }
149
150                 const_iterator& operator++()
151                 {
152                         if (it) {
153                                 cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
154                         }
155
156                         if (!*cur) {
157                                 it.reset ();
158                                 cur.reset ();
159                         }
160
161                         return *this;
162                 }
163
164                 const Ucl& operator*() const
165                 {
166                         return *cur;
167                 }
168                 const Ucl* operator->() const
169                 {
170                         return cur.get();
171                 }
172         };
173
174         // We grab ownership if get non-const ucl_object_t
175         Ucl(ucl_object_t *other) {
176                 obj.reset (other);
177         }
178
179         // Shared ownership
180         Ucl(const ucl_object_t *other) {
181                 obj.reset (ucl_object_ref (other));
182         }
183
184         Ucl(const Ucl &other) {
185                 obj.reset (ucl_object_ref (other.obj.get()));
186         }
187
188         Ucl(Ucl &&other) {
189                 obj.swap (other.obj);
190         }
191
192         Ucl() noexcept {
193                 obj.reset (ucl_object_typed_new (UCL_NULL));
194         }
195         Ucl(std::nullptr_t) noexcept {
196                 obj.reset (ucl_object_typed_new (UCL_NULL));
197         }
198         Ucl(double value) {
199                 obj.reset (ucl_object_typed_new (UCL_FLOAT));
200                 obj->value.dv = value;
201         }
202         Ucl(int64_t value) {
203                 obj.reset (ucl_object_typed_new (UCL_INT));
204                 obj->value.iv = value;
205         }
206         Ucl(bool value) {
207                 obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
208                 obj->value.iv = static_cast<int64_t>(value);
209         }
210         Ucl(const std::string &value) {
211                 obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
212                                 UCL_STRING_RAW));
213         }
214         Ucl(const char * value) {
215                 obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
216         }
217
218         // Implicit constructor: anything with a to_json() function.
219         template <class T, class = decltype(&T::to_ucl)>
220         Ucl(const T & t) : Ucl(t.to_ucl()) {}
221
222         // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
223         template <class M, typename std::enable_if<
224                 std::is_constructible<std::string, typename M::key_type>::value
225                 && std::is_constructible<Ucl, typename M::mapped_type>::value,
226                 int>::type = 0>
227         Ucl(const M & m) {
228                 obj.reset (ucl_object_typed_new (UCL_OBJECT));
229                 auto cobj = obj.get ();
230
231                 for (const auto &e : m) {
232                         ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
233                                         e.first.data (), e.first.size (), true);
234                 }
235         }
236
237         // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
238         template <class V, typename std::enable_if<
239                 std::is_constructible<Ucl, typename V::value_type>::value,
240                 int>::type = 0>
241         Ucl(const V & v) {
242                 obj.reset (ucl_object_typed_new (UCL_ARRAY));
243                 auto cobj = obj.get ();
244
245                 for (const auto &e : v) {
246                         ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
247                 }
248         }
249
250         ucl_type_t type () const {
251                 if (obj) {
252                         return ucl_object_type (obj.get ());
253                 }
254                 return UCL_NULL;
255         }
256
257         const std::string key () const {
258                 std::string res;
259
260                 if (obj->key) {
261                         res.assign (obj->key, obj->keylen);
262                 }
263
264                 return res;
265         }
266
267         double number_value (const double default_val = 0.0) const
268         {
269                 double res;
270
271                 if (ucl_object_todouble_safe(obj.get(), &res)) {
272                         return res;
273                 }
274
275                 return default_val;
276         }
277
278         int64_t int_value (const int64_t default_val = 0) const
279         {
280                 int64_t res;
281
282                 if (ucl_object_toint_safe(obj.get(), &res)) {
283                         return res;
284                 }
285
286                 return default_val;
287         }
288
289         bool bool_value (const bool default_val = false) const
290         {
291                 bool res;
292
293                 if (ucl_object_toboolean_safe(obj.get(), &res)) {
294                         return res;
295                 }
296
297                 return default_val;
298         }
299
300         const std::string string_value (const std::string& default_val = "") const
301         {
302                 const char* res = nullptr;
303
304                 if (ucl_object_tostring_safe(obj.get(), &res)) {
305                         return res;
306                 }
307
308                 return default_val;
309         }
310
311         const Ucl at (size_t i) const
312         {
313                 if (type () == UCL_ARRAY) {
314                         return Ucl (ucl_array_find_index (obj.get(), i));
315                 }
316
317                 return Ucl (nullptr);
318         }
319
320         const Ucl lookup (const std::string &key) const
321         {
322                 if (type () == UCL_OBJECT) {
323                         return Ucl (ucl_object_lookup_len (obj.get(),
324                                         key.data (), key.size ()));
325                 }
326
327                 return Ucl (nullptr);
328         }
329
330         inline const Ucl operator[] (size_t i) const
331         {
332                 return at(i);
333         }
334
335         inline const Ucl operator[](const std::string &key) const
336         {
337                 return lookup(key);
338         }
339         // Serialize.
340         void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
341         {
342                 struct ucl_emitter_functions cbdata;
343
344                 cbdata = Ucl::default_emit_funcs();
345                 cbdata.ud = reinterpret_cast<void *>(&out);
346
347                 ucl_object_emit_full (obj.get(), type, &cbdata, nullptr);
348         }
349
350         std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
351         {
352                 std::string out;
353
354                 dump (out, type);
355
356                 return out;
357         }
358
359         static Ucl parse (const std::string & in, std::string & err)
360         {
361                 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
362
363                 if (!ucl_parser_add_chunk (parser, (const unsigned char *)in.data (),
364                                 in.size ())) {
365                         err.assign (ucl_parser_get_error (parser));
366                         ucl_parser_free (parser);
367
368                         return nullptr;
369                 }
370
371                 auto obj = ucl_parser_get_object (parser);
372                 ucl_parser_free (parser);
373
374                 // Obj will handle ownership
375                 return Ucl (obj);
376         }
377
378         static Ucl parse (const char * in, std::string & err)
379         {
380                 if (in) {
381                         return parse (std::string(in), err);
382                 } else {
383                         err = "null input";
384                         return nullptr;
385                 }
386         }
387
388         static Ucl parse (std::istream &ifs, std::string &err)
389         {
390                 return Ucl::parse (std::string(std::istreambuf_iterator<char>(ifs),
391                                 std::istreambuf_iterator<char>()), err);
392         }
393
394     Ucl& operator= (Ucl rhs)
395     {
396         obj.swap (rhs.obj);
397         return *this;
398     }
399
400         bool operator== (const Ucl &rhs) const
401         {
402                 return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
403         }
404         bool operator< (const Ucl &rhs) const
405         {
406                 return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
407         }
408         bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
409         bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
410         bool operator> (const Ucl &rhs) const { return (rhs < *this); }
411         bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
412
413         explicit operator bool () const
414         {
415                 if (!obj || type() == UCL_NULL) {
416                         return false;
417                 }
418
419                 if (type () == UCL_BOOLEAN) {
420                         return bool_value ();
421                 }
422
423                 return true;
424         }
425
426         const_iterator begin() const
427         {
428                 return const_iterator(*this);
429         }
430         const_iterator cbegin() const
431         {
432                 return const_iterator(*this);
433         }
434         const_iterator end() const
435         {
436                 return const_iterator();
437         }
438         const_iterator cend() const
439         {
440                 return const_iterator();
441         }
442 };
443
444 };