]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libucl/include/ucl++.h
Merge ^/vendor/llvm-project/release-10.x up to its last change (upstream
[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 <vector>
28 #include <map>
29 #include <set>
30 #include <memory>
31 #include <iostream>
32
33 #include "ucl.h"
34
35 // C++11 API inspired by json11: https://github.com/dropbox/json11/
36
37 namespace ucl {
38
39 struct ucl_map_construct_t { };
40 constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
41 struct ucl_array_construct_t { };
42 constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
43
44 class Ucl final {
45 private:
46
47         struct ucl_deleter {
48                 void operator() (ucl_object_t *obj) {
49                         ucl_object_unref (obj);
50                 }
51         };
52
53         static int
54         append_char (unsigned char c, size_t nchars, void *ud)
55         {
56                 std::string *out = reinterpret_cast<std::string *>(ud);
57
58                 out->append (nchars, (char)c);
59
60                 return nchars;
61         }
62         static int
63         append_len (unsigned const char *str, size_t len, void *ud)
64         {
65                 std::string *out = reinterpret_cast<std::string *>(ud);
66
67                 out->append ((const char *)str, len);
68
69                 return len;
70         }
71         static int
72         append_int (int64_t elt, void *ud)
73         {
74                 std::string *out = reinterpret_cast<std::string *>(ud);
75                 auto nstr = std::to_string (elt);
76
77                 out->append (nstr);
78
79                 return nstr.size ();
80         }
81         static int
82         append_double (double elt, void *ud)
83         {
84                 std::string *out = reinterpret_cast<std::string *>(ud);
85                 auto nstr = std::to_string (elt);
86
87                 out->append (nstr);
88
89                 return nstr.size ();
90         }
91
92         static struct ucl_emitter_functions default_emit_funcs()
93         {
94                 struct ucl_emitter_functions func = {
95                         Ucl::append_char,
96                         Ucl::append_len,
97                         Ucl::append_int,
98                         Ucl::append_double,
99                         nullptr,
100                         nullptr
101                 };
102
103                 return func;
104         };
105
106         static bool ucl_variable_getter(const unsigned char *data, size_t len,
107                         unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
108         {
109         *need_free = false;
110
111                 auto vars = reinterpret_cast<std::set<std::string> *>(ud);
112                 if (vars && data && len != 0) {
113                         vars->emplace (data, data + len);
114                 }
115                 return false;
116         }
117
118         static bool ucl_variable_replacer (const unsigned char *data, size_t len,
119                         unsigned char **replace, size_t *replace_len, bool *need_free, void* ud)
120         {
121                 *need_free = false;
122
123                 auto replacer = reinterpret_cast<variable_replacer *>(ud);
124                 if (!replacer) {
125                         return false;
126         }
127
128                 std::string var_name (data, data + len);
129                 if (!replacer->is_variable (var_name)) {
130                         return false;
131         }
132
133                 std::string var_value = replacer->replace (var_name);
134                 if (var_value.empty ()) {
135                         return false;
136         }
137
138                 *replace = (unsigned char *)UCL_ALLOC (var_value.size ());
139                 memcpy (*replace, var_value.data (), var_value.size ());
140
141                 *replace_len = var_value.size ();
142                 *need_free = true;
143
144                 return true;
145         }
146
147         template <typename C, typename P>
148         static Ucl parse_with_strategy_function (C config_func, P parse_func, std::string &err)
149         {
150                 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
151
152                 config_func (parser);
153
154                 if (!parse_func (parser)) {
155                         err.assign (ucl_parser_get_error (parser));
156                         ucl_parser_free (parser);
157
158                         return nullptr;
159                 }
160
161                 auto obj = ucl_parser_get_object (parser);
162                 ucl_parser_free (parser);
163
164                 // Obj will handle ownership
165                 return Ucl (obj);
166         }
167
168         std::unique_ptr<ucl_object_t, ucl_deleter> obj;
169
170 public:
171         class const_iterator {
172         private:
173                 struct ucl_iter_deleter {
174                         void operator() (ucl_object_iter_t it) {
175                                 ucl_object_iterate_free (it);
176                         }
177                 };
178                 std::shared_ptr<void> it;
179                 std::unique_ptr<Ucl> cur;
180         public:
181                 typedef std::forward_iterator_tag iterator_category;
182
183                 const_iterator(const Ucl &obj) {
184                         it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
185                                 ucl_iter_deleter());
186                         cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
187                         if (cur->type() == UCL_NULL) {
188                                 it.reset ();
189                                 cur.reset ();
190                         }
191                 }
192
193                 const_iterator() {}
194                 const_iterator(const const_iterator &other) = delete;
195                 const_iterator(const_iterator &&other) = default;
196                 ~const_iterator() {}
197
198                 const_iterator& operator=(const const_iterator &other) = delete;
199                 const_iterator& operator=(const_iterator &&other) = default;
200
201                 bool operator==(const const_iterator &other) const
202                 {
203                         if (cur && other.cur) {
204                                 return cur->obj.get() == other.cur->obj.get();
205                         }
206
207                         return !cur && !other.cur;
208                 }
209
210                 bool operator!=(const const_iterator &other) const
211                 {
212                         return !(*this == other);
213                 }
214
215                 const_iterator& operator++()
216                 {
217                         if (it) {
218                                 cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
219                         }
220
221                         if (cur && cur->type() == UCL_NULL) {
222                                 it.reset ();
223                                 cur.reset ();
224                         }
225
226                         return *this;
227                 }
228
229                 const Ucl& operator*() const
230                 {
231                         return *cur;
232                 }
233                 const Ucl* operator->() const
234                 {
235                         return cur.get();
236                 }
237         };
238
239         struct variable_replacer {
240                 virtual ~variable_replacer() {}
241
242                 virtual bool is_variable (const std::string &str) const
243                 {
244                         return !str.empty ();
245                 }
246
247                 virtual std::string replace (const std::string &var) const = 0;
248         };
249
250         // We grab ownership if get non-const ucl_object_t
251         Ucl(ucl_object_t *other) {
252                 obj.reset (other);
253         }
254
255         // Shared ownership
256         Ucl(const ucl_object_t *other) {
257                 obj.reset (ucl_object_ref (other));
258         }
259
260         Ucl(const Ucl &other) {
261                 obj.reset (ucl_object_ref (other.obj.get()));
262         }
263
264         Ucl(Ucl &&other) {
265                 obj.swap (other.obj);
266         }
267
268         Ucl() noexcept {
269                 obj.reset (ucl_object_typed_new (UCL_NULL));
270         }
271         Ucl(std::nullptr_t) noexcept {
272                 obj.reset (ucl_object_typed_new (UCL_NULL));
273         }
274         Ucl(double value) {
275                 obj.reset (ucl_object_typed_new (UCL_FLOAT));
276                 obj->value.dv = value;
277         }
278         Ucl(int64_t value) {
279                 obj.reset (ucl_object_typed_new (UCL_INT));
280                 obj->value.iv = value;
281         }
282         Ucl(bool value) {
283                 obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
284                 obj->value.iv = static_cast<int64_t>(value);
285         }
286         Ucl(const std::string &value) {
287                 obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
288                                 UCL_STRING_RAW));
289         }
290         Ucl(const char *value) {
291                 obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
292         }
293
294         // Implicit constructor: anything with a to_json() function.
295         template <class T, class = decltype(&T::to_ucl)>
296         Ucl(const T &t) : Ucl(t.to_ucl()) {}
297
298         // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
299         template <class M, typename std::enable_if<
300                 std::is_constructible<std::string, typename M::key_type>::value
301                 && std::is_constructible<Ucl, typename M::mapped_type>::value,
302                 int>::type = 0>
303         Ucl(const M &m) {
304                 obj.reset (ucl_object_typed_new (UCL_OBJECT));
305                 auto cobj = obj.get ();
306
307                 for (const auto &e : m) {
308                         ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
309                                         e.first.data (), e.first.size (), true);
310                 }
311         }
312
313         // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
314         template <class V, typename std::enable_if<
315                 std::is_constructible<Ucl, typename V::value_type>::value,
316                 int>::type = 0>
317         Ucl(const V &v) {
318                 obj.reset (ucl_object_typed_new (UCL_ARRAY));
319                 auto cobj = obj.get ();
320
321                 for (const auto &e : v) {
322                         ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
323                 }
324         }
325
326         ucl_type_t type () const {
327                 if (obj) {
328                         return ucl_object_type (obj.get ());
329                 }
330                 return UCL_NULL;
331         }
332
333         const std::string key () const {
334                 std::string res;
335
336                 if (obj->key) {
337                         res.assign (obj->key, obj->keylen);
338                 }
339
340                 return res;
341         }
342
343         double number_value (const double default_val = 0.0) const
344         {
345                 double res;
346
347                 if (ucl_object_todouble_safe(obj.get(), &res)) {
348                         return res;
349                 }
350
351                 return default_val;
352         }
353
354         int64_t int_value (const int64_t default_val = 0) const
355         {
356                 int64_t res;
357
358                 if (ucl_object_toint_safe(obj.get(), &res)) {
359                         return res;
360                 }
361
362                 return default_val;
363         }
364
365         bool bool_value (const bool default_val = false) const
366         {
367                 bool res;
368
369                 if (ucl_object_toboolean_safe(obj.get(), &res)) {
370                         return res;
371                 }
372
373                 return default_val;
374         }
375
376         const std::string string_value (const std::string& default_val = "") const
377         {
378                 const char* res = nullptr;
379
380                 if (ucl_object_tostring_safe(obj.get(), &res)) {
381                         return res;
382                 }
383
384                 return default_val;
385         }
386
387         const Ucl at (size_t i) const
388         {
389                 if (type () == UCL_ARRAY) {
390                         return Ucl (ucl_array_find_index (obj.get(), i));
391                 }
392
393                 return Ucl (nullptr);
394         }
395
396         const Ucl lookup (const std::string &key) const
397         {
398                 if (type () == UCL_OBJECT) {
399                         return Ucl (ucl_object_lookup_len (obj.get(),
400                                         key.data (), key.size ()));
401                 }
402
403                 return Ucl (nullptr);
404         }
405
406         inline const Ucl operator[] (size_t i) const
407         {
408                 return at(i);
409         }
410
411         inline const Ucl operator[](const std::string &key) const
412         {
413                 return lookup(key);
414         }
415         // Serialize.
416         void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
417         {
418                 struct ucl_emitter_functions cbdata;
419
420                 cbdata = Ucl::default_emit_funcs();
421                 cbdata.ud = reinterpret_cast<void *>(&out);
422
423                 ucl_object_emit_full (obj.get(), type, &cbdata, nullptr);
424         }
425
426         std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
427         {
428                 std::string out;
429
430                 dump (out, type);
431
432                 return out;
433         }
434
435         static Ucl parse (const std::string &in, std::string &err)
436         {
437                 return parse (in, std::map<std::string, std::string>(), err);
438         }
439
440         static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars, std::string &err)
441         {
442                 auto config_func = [&vars] (ucl_parser *parser) {
443                         for (const auto & item : vars) {
444                                 ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
445             }
446                 };
447
448                 auto parse_func = [&in] (ucl_parser *parser) {
449                         return ucl_parser_add_chunk (parser, (unsigned char *)in.data (), in.size ());
450                 };
451
452                 return parse_with_strategy_function (config_func, parse_func, err);
453         }
454
455         static Ucl parse (const std::string &in, const variable_replacer &replacer, std::string &err)
456         {
457                 auto config_func = [&replacer] (ucl_parser *parser) {
458                         ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
459                                 &const_cast<variable_replacer &>(replacer));
460                 };
461
462                 auto parse_func = [&in] (ucl_parser *parser) {
463                         return ucl_parser_add_chunk (parser, (unsigned char *) in.data (), in.size ());
464                 };
465
466                 return parse_with_strategy_function (config_func, parse_func, err);
467         }
468
469         static Ucl parse (const char *in, std::string &err)
470         {
471                 return parse (in, std::map<std::string, std::string>(), err);
472         }
473
474         static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
475         {
476                 if (!in) {
477                         err = "null input";
478                         return nullptr;
479                 }
480                 return parse (std::string (in), vars, err);
481         }
482
483         static Ucl parse (const char *in, const variable_replacer &replacer, std::string &err)
484         {
485                 if (!in) {
486                         err = "null input";
487                         return nullptr;
488                 }
489                 return parse (std::string(in), replacer, err);
490         }
491
492         static Ucl parse_from_file (const std::string &filename, std::string &err)
493         {
494                 return parse_from_file (filename, std::map<std::string, std::string>(), err);
495         }
496
497         static Ucl parse_from_file (const std::string &filename, const std::map<std::string, std::string> &vars, std::string &err)
498         {
499                 auto config_func = [&vars] (ucl_parser *parser) {
500                         for (const auto & item : vars) {
501                                 ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
502             }
503                 };
504
505                 auto parse_func = [&filename] (ucl_parser *parser) {
506                         return ucl_parser_add_file (parser, filename.c_str ());
507                 };
508
509                 return parse_with_strategy_function (config_func, parse_func, err);
510         }
511
512         static Ucl parse_from_file (const std::string &filename, const variable_replacer &replacer, std::string &err)
513         {
514                 auto config_func = [&replacer] (ucl_parser *parser) {
515                         ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
516                                 &const_cast<variable_replacer &>(replacer));
517                 };
518
519                 auto parse_func = [&filename] (ucl_parser *parser) {
520                         return ucl_parser_add_file (parser, filename.c_str ());
521                 };
522
523                 return parse_with_strategy_function (config_func, parse_func, err);
524         }
525
526         static std::vector<std::string> find_variable (const std::string &in)
527         {
528                 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
529
530                 std::set<std::string> vars;
531                 ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
532                 ucl_parser_add_chunk (parser, (const unsigned char *)in.data (), in.size ());
533                 ucl_parser_free (parser);
534
535                 std::vector<std::string> result;
536                 std::move (vars.begin (), vars.end (), std::back_inserter (result));
537                 return result;
538         }
539
540         static std::vector<std::string> find_variable (const char *in)
541         {
542                 if (!in) {
543                         return std::vector<std::string>();
544                 }
545                 return find_variable (std::string (in));
546         }
547
548         static std::vector<std::string> find_variable_from_file (const std::string &filename)
549         {
550                 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
551
552                 std::set<std::string> vars;
553                 ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
554                 ucl_parser_add_file (parser, filename.c_str ());
555                 ucl_parser_free (parser);
556
557                 std::vector<std::string> result;
558                 std::move (vars.begin (), vars.end (), std::back_inserter (result));
559                 return std::move (result);
560         }
561
562         Ucl& operator= (Ucl rhs)
563         {
564                 obj.swap (rhs.obj);
565                 return *this;
566         }
567
568         bool operator== (const Ucl &rhs) const
569         {
570                 return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
571         }
572         bool operator< (const Ucl &rhs) const
573         {
574                 return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
575         }
576         bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
577         bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
578         bool operator> (const Ucl &rhs) const { return (rhs < *this); }
579         bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
580
581         explicit operator bool () const
582         {
583                 if (!obj || type() == UCL_NULL) {
584                         return false;
585                 }
586
587                 if (type () == UCL_BOOLEAN) {
588                         return bool_value ();
589                 }
590
591                 return true;
592         }
593
594         const_iterator begin() const
595         {
596                 return const_iterator(*this);
597         }
598         const_iterator cbegin() const
599         {
600                 return const_iterator(*this);
601         }
602         const_iterator end() const
603         {
604                 return const_iterator();
605         }
606         const_iterator cend() const
607         {
608                 return const_iterator();
609         }
610 };
611
612 };