]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/include/ucl++.h
Merge LLDB 3.8
[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 #include <strstream>
30
31 #include "ucl.h"
32
33 // C++11 API inspired by json11: https://github.com/dropbox/json11/
34
35 namespace ucl {
36
37 struct ucl_map_construct_t { };
38 constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
39 struct ucl_array_construct_t { };
40 constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
41
42 class Ucl final {
43 private:
44
45         struct ucl_deleter {
46                 void operator() (ucl_object_t *obj) {
47                         ucl_object_unref (obj);
48                 }
49         };
50
51         static int
52         append_char (unsigned char c, size_t nchars, void *ud)
53         {
54                 std::string *out = reinterpret_cast<std::string *>(ud);
55
56                 out->append (nchars, (char)c);
57
58                 return nchars;
59         }
60         static int
61         append_len (unsigned const char *str, size_t len, void *ud)
62         {
63                 std::string *out = reinterpret_cast<std::string *>(ud);
64
65                 out->append ((const char *)str, len);
66
67                 return len;
68         }
69         static int
70         append_int (int64_t elt, void *ud)
71         {
72                 std::string *out = reinterpret_cast<std::string *>(ud);
73                 auto nstr = std::to_string (elt);
74
75                 out->append (nstr);
76
77                 return nstr.size ();
78         }
79         static int
80         append_double (double elt, void *ud)
81         {
82                 std::string *out = reinterpret_cast<std::string *>(ud);
83                 auto nstr = std::to_string (elt);
84
85                 out->append (nstr);
86
87                 return nstr.size ();
88         }
89
90         static struct ucl_emitter_functions default_emit_funcs()
91         {
92                 struct ucl_emitter_functions func = {
93                         Ucl::append_char,
94                         Ucl::append_len,
95                         Ucl::append_int,
96                         Ucl::append_double,
97                         nullptr,
98                         nullptr
99                 };
100
101                 return func;
102         };
103
104         std::unique_ptr<ucl_object_t, ucl_deleter> obj;
105
106 public:
107         class const_iterator {
108         private:
109                 struct ucl_iter_deleter {
110                         void operator() (ucl_object_iter_t it) {
111                                 ucl_object_iterate_free (it);
112                         }
113                 };
114                 std::shared_ptr<void> it;
115                 std::unique_ptr<Ucl> cur;
116         public:
117                 typedef std::forward_iterator_tag iterator_category;
118
119                 const_iterator(const Ucl &obj) {
120                         it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
121                                         ucl_iter_deleter());
122                         cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
123                 }
124
125                 const_iterator() {}
126                 const_iterator(const const_iterator &other) {
127                         it = other.it;
128                 }
129                 ~const_iterator() {}
130
131                 const_iterator& operator=(const const_iterator &other) {
132                         it = other.it;
133                         return *this;
134                 }
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
268         {
269                 if (obj) {
270                         return ucl_object_todouble (obj.get());
271                 }
272
273                 return 0.0;
274         }
275
276         int64_t int_value () const
277         {
278                 if (obj) {
279                         return ucl_object_toint (obj.get());
280                 }
281
282                 return 0;
283         }
284
285         bool bool_value () const
286         {
287                 if (obj) {
288                         return ucl_object_toboolean (obj.get());
289                 }
290
291                 return false;
292         }
293
294         const std::string string_value () const
295         {
296                 std::string res;
297
298                 if (obj) {
299                         res.assign (ucl_object_tostring (obj.get()));
300                 }
301
302                 return res;
303         }
304
305         const Ucl operator[] (size_t i) const
306         {
307                 if (type () == UCL_ARRAY) {
308                         return Ucl (ucl_array_find_index (obj.get(), i));
309                 }
310
311                 return Ucl (nullptr);
312         }
313
314         const Ucl operator[](const std::string &key) const
315         {
316                 if (type () == UCL_OBJECT) {
317                         return Ucl (ucl_object_find_keyl (obj.get(),
318                                         key.data (), key.size ()));
319                 }
320
321                 return Ucl (nullptr);
322         }
323         // Serialize.
324         void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
325         {
326                 struct ucl_emitter_functions cbdata;
327
328                 cbdata = Ucl::default_emit_funcs();
329                 cbdata.ud = reinterpret_cast<void *>(&out);
330
331                 ucl_object_emit_full (obj.get(), type, &cbdata);
332         }
333
334         std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
335         {
336                 std::string out;
337
338                 dump (out, type);
339
340                 return out;
341         }
342
343         static Ucl parse (const std::string & in, std::string & err)
344         {
345                 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
346
347                 if (!ucl_parser_add_chunk (parser, (const unsigned char *)in.data (),
348                                 in.size ())) {
349                         err.assign (ucl_parser_get_error (parser));
350                         ucl_parser_free (parser);
351
352                         return nullptr;
353                 }
354
355                 auto obj = ucl_parser_get_object (parser);
356                 ucl_parser_free (parser);
357
358                 // Obj will handle ownership
359                 return Ucl (obj);
360         }
361
362         static Ucl parse (const char * in, std::string & err)
363         {
364                 if (in) {
365                         return parse (std::string(in), err);
366                 } else {
367                         err = "null input";
368                         return nullptr;
369                 }
370         }
371
372         static Ucl parse (std::istream &ifs, std::string &err)
373         {
374                 return Ucl::parse (std::string(std::istreambuf_iterator<char>(ifs),
375                                 std::istreambuf_iterator<char>()), err);
376         }
377
378         bool operator== (const Ucl &rhs) const
379         {
380                 return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
381         }
382         bool operator< (const Ucl &rhs) const
383         {
384                 return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
385         }
386         bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
387         bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
388         bool operator> (const Ucl &rhs) const { return (rhs < *this); }
389         bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
390
391         operator bool () const
392         {
393                 if (!obj || type() == UCL_NULL) {
394                         return false;
395                 }
396
397                 if (type () == UCL_BOOLEAN) {
398                         return bool_value ();
399                 }
400
401                 return true;
402         }
403
404         const_iterator begin() const
405         {
406                 return const_iterator(*this);
407         }
408         const_iterator cbegin() const
409         {
410                 return const_iterator(*this);
411         }
412         const_iterator end() const
413         {
414                 return const_iterator();
415         }
416         const_iterator cend() const
417         {
418                 return const_iterator();
419         }
420 };
421
422 };