2 * Copyright (c) 2015, Vsevolod Stakhov
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.
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.
32 // C++11 API inspired by json11: https://github.com/dropbox/json11/
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();
45 void operator() (ucl_object_t *obj) {
46 ucl_object_unref (obj);
51 append_char (unsigned char c, size_t nchars, void *ud)
53 std::string *out = reinterpret_cast<std::string *>(ud);
55 out->append (nchars, (char)c);
60 append_len (unsigned const char *str, size_t len, void *ud)
62 std::string *out = reinterpret_cast<std::string *>(ud);
64 out->append ((const char *)str, len);
69 append_int (int64_t elt, void *ud)
71 std::string *out = reinterpret_cast<std::string *>(ud);
72 auto nstr = std::to_string (elt);
79 append_double (double elt, void *ud)
81 std::string *out = reinterpret_cast<std::string *>(ud);
82 auto nstr = std::to_string (elt);
89 static struct ucl_emitter_functions default_emit_funcs()
91 struct ucl_emitter_functions func = {
103 std::unique_ptr<ucl_object_t, ucl_deleter> obj;
106 class const_iterator {
108 struct ucl_iter_deleter {
109 void operator() (ucl_object_iter_t it) {
110 ucl_object_iterate_free (it);
113 std::shared_ptr<void> it;
114 std::unique_ptr<Ucl> cur;
116 typedef std::forward_iterator_tag iterator_category;
118 const_iterator(const Ucl &obj) {
119 it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
121 cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
129 const_iterator(const const_iterator &other) = delete;
130 const_iterator(const_iterator &&other) = default;
133 const_iterator& operator=(const const_iterator &other) = delete;
134 const_iterator& operator=(const_iterator &&other) = default;
136 bool operator==(const const_iterator &other) const
138 if (cur && other.cur) {
139 return cur->obj.get() == other.cur->obj.get();
142 return !cur && !other.cur;
145 bool operator!=(const const_iterator &other) const
147 return !(*this == other);
150 const_iterator& operator++()
153 cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
164 const Ucl& operator*() const
168 const Ucl* operator->() const
174 // We grab ownership if get non-const ucl_object_t
175 Ucl(ucl_object_t *other) {
180 Ucl(const ucl_object_t *other) {
181 obj.reset (ucl_object_ref (other));
184 Ucl(const Ucl &other) {
185 obj.reset (ucl_object_ref (other.obj.get()));
189 obj.swap (other.obj);
193 obj.reset (ucl_object_typed_new (UCL_NULL));
195 Ucl(std::nullptr_t) noexcept {
196 obj.reset (ucl_object_typed_new (UCL_NULL));
199 obj.reset (ucl_object_typed_new (UCL_FLOAT));
200 obj->value.dv = value;
203 obj.reset (ucl_object_typed_new (UCL_INT));
204 obj->value.iv = value;
207 obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
208 obj->value.iv = static_cast<int64_t>(value);
210 Ucl(const std::string &value) {
211 obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
214 Ucl(const char * value) {
215 obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
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()) {}
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,
228 obj.reset (ucl_object_typed_new (UCL_OBJECT));
229 auto cobj = obj.get ();
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);
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,
242 obj.reset (ucl_object_typed_new (UCL_ARRAY));
243 auto cobj = obj.get ();
245 for (const auto &e : v) {
246 ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
250 ucl_type_t type () const {
252 return ucl_object_type (obj.get ());
257 const std::string key () const {
261 res.assign (obj->key, obj->keylen);
267 double number_value (const double default_val = 0.0) const
271 if (ucl_object_todouble_safe(obj.get(), &res)) {
278 int64_t int_value (const int64_t default_val = 0) const
282 if (ucl_object_toint_safe(obj.get(), &res)) {
289 bool bool_value (const bool default_val = false) const
293 if (ucl_object_toboolean_safe(obj.get(), &res)) {
300 const std::string string_value (const std::string& default_val = "") const
302 const char* res = nullptr;
304 if (ucl_object_tostring_safe(obj.get(), &res)) {
311 const Ucl at (size_t i) const
313 if (type () == UCL_ARRAY) {
314 return Ucl (ucl_array_find_index (obj.get(), i));
317 return Ucl (nullptr);
320 const Ucl lookup (const std::string &key) const
322 if (type () == UCL_OBJECT) {
323 return Ucl (ucl_object_lookup_len (obj.get(),
324 key.data (), key.size ()));
327 return Ucl (nullptr);
330 inline const Ucl operator[] (size_t i) const
335 inline const Ucl operator[](const std::string &key) const
340 void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
342 struct ucl_emitter_functions cbdata;
344 cbdata = Ucl::default_emit_funcs();
345 cbdata.ud = reinterpret_cast<void *>(&out);
347 ucl_object_emit_full (obj.get(), type, &cbdata, nullptr);
350 std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
359 static Ucl parse (const std::string & in, std::string & err)
361 auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
363 if (!ucl_parser_add_chunk (parser, (const unsigned char *)in.data (),
365 err.assign (ucl_parser_get_error (parser));
366 ucl_parser_free (parser);
371 auto obj = ucl_parser_get_object (parser);
372 ucl_parser_free (parser);
374 // Obj will handle ownership
378 static Ucl parse (const char * in, std::string & err)
381 return parse (std::string(in), err);
388 static Ucl parse (std::istream &ifs, std::string &err)
390 return Ucl::parse (std::string(std::istreambuf_iterator<char>(ifs),
391 std::istreambuf_iterator<char>()), err);
394 Ucl& operator= (Ucl rhs)
400 bool operator== (const Ucl &rhs) const
402 return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
404 bool operator< (const Ucl &rhs) const
406 return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
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); }
413 explicit operator bool () const
415 if (!obj || type() == UCL_NULL) {
419 if (type () == UCL_BOOLEAN) {
420 return bool_value ();
426 const_iterator begin() const
428 return const_iterator(*this);
430 const_iterator cbegin() const
432 return const_iterator(*this);
434 const_iterator end() const
436 return const_iterator();
438 const_iterator cend() const
440 return const_iterator();