Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libucl/include/ucl++.h
39534 views
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
#include <tuple>
33
34
#include "ucl.h"
35
36
// C++11 API inspired by json11: https://github.com/dropbox/json11/
37
38
namespace ucl {
39
40
struct ucl_map_construct_t { };
41
constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
42
struct ucl_array_construct_t { };
43
constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
44
45
class Ucl final {
46
private:
47
48
struct ucl_deleter {
49
void operator() (ucl_object_t *obj) {
50
ucl_object_unref (obj);
51
}
52
};
53
54
static int
55
append_char (unsigned char c, size_t nchars, void *ud)
56
{
57
std::string *out = reinterpret_cast<std::string *>(ud);
58
59
out->append (nchars, (char)c);
60
61
return nchars;
62
}
63
static int
64
append_len (unsigned const char *str, size_t len, void *ud)
65
{
66
std::string *out = reinterpret_cast<std::string *>(ud);
67
68
out->append ((const char *)str, len);
69
70
return len;
71
}
72
static int
73
append_int (int64_t elt, void *ud)
74
{
75
std::string *out = reinterpret_cast<std::string *>(ud);
76
auto nstr = std::to_string (elt);
77
78
out->append (nstr);
79
80
return nstr.size ();
81
}
82
static int
83
append_double (double elt, void *ud)
84
{
85
std::string *out = reinterpret_cast<std::string *>(ud);
86
auto nstr = std::to_string (elt);
87
88
out->append (nstr);
89
90
return nstr.size ();
91
}
92
93
static struct ucl_emitter_functions default_emit_funcs()
94
{
95
struct ucl_emitter_functions func = {
96
Ucl::append_char,
97
Ucl::append_len,
98
Ucl::append_int,
99
Ucl::append_double,
100
nullptr,
101
nullptr
102
};
103
104
return func;
105
};
106
107
static bool ucl_variable_getter(const unsigned char *data, size_t len,
108
unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
109
{
110
*need_free = false;
111
112
auto vars = reinterpret_cast<std::set<std::string> *>(ud);
113
if (vars && data && len != 0) {
114
vars->emplace (data, data + len);
115
}
116
return false;
117
}
118
119
static bool ucl_variable_replacer (const unsigned char *data, size_t len,
120
unsigned char **replace, size_t *replace_len, bool *need_free, void* ud)
121
{
122
*need_free = false;
123
124
auto replacer = reinterpret_cast<variable_replacer *>(ud);
125
if (!replacer) {
126
return false;
127
}
128
129
std::string var_name (data, data + len);
130
if (!replacer->is_variable (var_name)) {
131
return false;
132
}
133
134
std::string var_value = replacer->replace (var_name);
135
if (var_value.empty ()) {
136
return false;
137
}
138
139
*replace = (unsigned char *)UCL_ALLOC (var_value.size ());
140
memcpy (*replace, var_value.data (), var_value.size ());
141
142
*replace_len = var_value.size ();
143
*need_free = true;
144
145
return true;
146
}
147
148
template <typename C, typename P>
149
static Ucl parse_with_strategy_function (C config_func, P parse_func, std::string &err)
150
{
151
auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
152
153
config_func (parser);
154
155
if (!parse_func (parser)) {
156
const char *error = ucl_parser_get_error (parser); //Assigning here without checking result first causes a
157
if( error != NULL ) err.assign(error); // crash if ucl_parser_get_error returns NULL
158
ucl_parser_free (parser);
159
160
return nullptr;
161
}
162
163
auto obj = ucl_parser_get_object (parser);
164
ucl_parser_free (parser);
165
166
// Obj will handle ownership
167
return Ucl (obj);
168
}
169
170
std::unique_ptr<ucl_object_t, ucl_deleter> obj;
171
172
public:
173
struct macro_handler_s {
174
ucl_macro_handler handler;
175
ucl_context_macro_handler ctx_handler;
176
};
177
178
struct macro_userdata_s {
179
ucl_parser *parser;
180
void *userdata;
181
};
182
183
class const_iterator {
184
private:
185
struct ucl_iter_deleter {
186
void operator() (ucl_object_iter_t it) {
187
ucl_object_iterate_free (it);
188
}
189
};
190
std::shared_ptr<void> it;
191
std::unique_ptr<Ucl> cur;
192
public:
193
typedef std::forward_iterator_tag iterator_category;
194
195
const_iterator(const Ucl &obj) {
196
it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
197
ucl_iter_deleter());
198
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
199
if (!cur->obj) {
200
it.reset ();
201
cur.reset ();
202
}
203
}
204
205
const_iterator() {}
206
const_iterator(const const_iterator &other) = delete;
207
const_iterator(const_iterator &&other) = default;
208
~const_iterator() {}
209
210
const_iterator& operator=(const const_iterator &other) = delete;
211
const_iterator& operator=(const_iterator &&other) = default;
212
213
bool operator==(const const_iterator &other) const
214
{
215
if (cur && other.cur) {
216
return cur->obj.get() == other.cur->obj.get();
217
}
218
219
return !cur && !other.cur;
220
}
221
222
bool operator!=(const const_iterator &other) const
223
{
224
return !(*this == other);
225
}
226
227
const_iterator& operator++()
228
{
229
if (it) {
230
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
231
}
232
233
if (cur && !cur->obj) {
234
it.reset ();
235
cur.reset ();
236
}
237
238
return *this;
239
}
240
241
const Ucl& operator*() const
242
{
243
return *cur;
244
}
245
const Ucl* operator->() const
246
{
247
return cur.get();
248
}
249
};
250
251
struct variable_replacer {
252
virtual ~variable_replacer() {}
253
254
virtual bool is_variable (const std::string &str) const
255
{
256
return !str.empty ();
257
}
258
259
virtual std::string replace (const std::string &var) const = 0;
260
};
261
262
// We grab ownership if get non-const ucl_object_t
263
Ucl(ucl_object_t *other) {
264
obj.reset (other);
265
}
266
267
// Shared ownership
268
Ucl(const ucl_object_t *other) {
269
obj.reset (ucl_object_ref (other));
270
}
271
272
Ucl(const Ucl &other) {
273
obj.reset (ucl_object_ref (other.obj.get()));
274
}
275
276
Ucl(Ucl &&other) {
277
obj.swap (other.obj);
278
}
279
280
Ucl() noexcept {
281
obj.reset (ucl_object_typed_new (UCL_NULL));
282
}
283
Ucl(std::nullptr_t) noexcept {
284
obj.reset (ucl_object_typed_new (UCL_NULL));
285
}
286
Ucl(double value) {
287
obj.reset (ucl_object_typed_new (UCL_FLOAT));
288
obj->value.dv = value;
289
}
290
Ucl(int64_t value) {
291
obj.reset (ucl_object_typed_new (UCL_INT));
292
obj->value.iv = value;
293
}
294
Ucl(bool value) {
295
obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
296
obj->value.iv = static_cast<int64_t>(value);
297
}
298
Ucl(const std::string &value) {
299
obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
300
UCL_STRING_RAW));
301
}
302
Ucl(const char *value) {
303
obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
304
}
305
306
// Implicit constructor: anything with a to_json() function.
307
template <class T, class = decltype(&T::to_ucl)>
308
Ucl(const T &t) : Ucl(t.to_ucl()) {}
309
310
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
311
template <class M, typename std::enable_if<
312
std::is_constructible<std::string, typename M::key_type>::value
313
&& std::is_constructible<Ucl, typename M::mapped_type>::value,
314
int>::type = 0>
315
Ucl(const M &m) {
316
obj.reset (ucl_object_typed_new (UCL_OBJECT));
317
auto cobj = obj.get ();
318
319
for (const auto &e : m) {
320
ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
321
e.first.data (), e.first.size (), true);
322
}
323
}
324
325
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
326
template <class V, typename std::enable_if<
327
std::is_constructible<Ucl, typename V::value_type>::value,
328
int>::type = 0>
329
Ucl(const V &v) {
330
obj.reset (ucl_object_typed_new (UCL_ARRAY));
331
auto cobj = obj.get ();
332
333
for (const auto &e : v) {
334
ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
335
}
336
}
337
338
ucl_type_t type () const {
339
if (obj) {
340
return ucl_object_type (obj.get ());
341
}
342
return UCL_NULL;
343
}
344
345
std::string key () const {
346
std::string res;
347
348
if (obj->key) {
349
res.assign (obj->key, obj->keylen);
350
}
351
352
return res;
353
}
354
355
double number_value (const double default_val = 0.0) const
356
{
357
double res;
358
359
if (ucl_object_todouble_safe(obj.get(), &res)) {
360
return res;
361
}
362
363
return default_val;
364
}
365
366
int64_t int_value (const int64_t default_val = 0) const
367
{
368
int64_t res;
369
370
if (ucl_object_toint_safe(obj.get(), &res)) {
371
return res;
372
}
373
374
return default_val;
375
}
376
377
bool bool_value (const bool default_val = false) const
378
{
379
bool res;
380
381
if (ucl_object_toboolean_safe(obj.get(), &res)) {
382
return res;
383
}
384
385
return default_val;
386
}
387
388
std::string string_value (const std::string& default_val = "") const
389
{
390
const char* res = nullptr;
391
392
if (ucl_object_tostring_safe(obj.get(), &res)) {
393
return res;
394
}
395
396
return default_val;
397
}
398
399
std::string forced_string_value () const
400
{
401
return ucl_object_tostring_forced(obj.get());
402
}
403
404
size_t size () const
405
{
406
if (type () == UCL_ARRAY) {
407
return ucl_array_size (obj.get());
408
}
409
410
return 0;
411
}
412
413
Ucl at (size_t i) const
414
{
415
if (type () == UCL_ARRAY) {
416
return Ucl (ucl_array_find_index (obj.get(), i));
417
}
418
419
return Ucl (nullptr);
420
}
421
422
Ucl lookup (const std::string &key) const
423
{
424
if (type () == UCL_OBJECT) {
425
return Ucl (ucl_object_lookup_len (obj.get(),
426
key.data (), key.size ()));
427
}
428
429
return Ucl (nullptr);
430
}
431
432
inline Ucl operator[] (size_t i) const
433
{
434
return at(i);
435
}
436
437
inline Ucl operator[](const std::string &key) const
438
{
439
return lookup(key);
440
}
441
// Serialize.
442
void dump (std::string &out, ucl_emitter_t type = UCL_EMIT_JSON) const
443
{
444
struct ucl_emitter_functions cbdata;
445
446
cbdata = Ucl::default_emit_funcs();
447
cbdata.ud = reinterpret_cast<void *>(&out);
448
449
ucl_object_emit_full (obj.get(), type, &cbdata, nullptr);
450
}
451
452
std::string dump (ucl_emitter_t type = UCL_EMIT_JSON) const
453
{
454
std::string out;
455
456
dump (out, type);
457
458
return out;
459
}
460
461
static Ucl parse (const std::string &in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
462
{
463
return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
464
}
465
466
static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
467
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
468
{
469
std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
470
return parse ( in, vars, emptyVector, err, duplicate_strategy );
471
}
472
473
//Macro handler will receive a macro_userdata_s as void *ud
474
static Ucl parse (const std::string &in,
475
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
476
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
477
{
478
return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
479
}
480
481
//Macro handler will receive a macro_userdata_s as void *ud
482
static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
483
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
484
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
485
{
486
//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
487
std::vector<macro_userdata_s> userdata_list;
488
userdata_list.reserve (macros.size());
489
auto config_func = [&userdata_list, &vars, &macros] (ucl_parser *parser) {
490
for (const auto & item : vars) {
491
ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
492
}
493
for (auto & macro : macros) {
494
userdata_list.push_back ({parser, std::get<2>(macro)});
495
if (std::get<1>(macro).handler != NULL) {
496
ucl_parser_register_macro (parser,
497
std::get<0>(macro).c_str(),
498
std::get<1>(macro).handler,
499
reinterpret_cast<void*>(&userdata_list.back()));
500
}
501
else if (std::get<1>(macro).ctx_handler != NULL) {
502
ucl_parser_register_context_macro (parser,
503
std::get<0>(macro).c_str(),
504
std::get<1>(macro).ctx_handler,
505
reinterpret_cast<void*>(&userdata_list.back()));
506
}
507
}
508
};
509
510
auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
511
return ucl_parser_add_chunk_full (parser,
512
(unsigned char *) in.data (),
513
in.size (),
514
(unsigned int)ucl_parser_get_default_priority (parser),
515
duplicate_strategy,
516
UCL_PARSE_UCL);
517
};
518
519
return parse_with_strategy_function (config_func, parse_func, err);
520
}
521
522
static Ucl parse (const std::string &in, const variable_replacer &replacer,
523
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
524
{
525
std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
526
return parse ( in, replacer, emptyVector, err, duplicate_strategy );
527
}
528
529
//Macro handler will receive a macro_userdata_s as void *ud
530
static Ucl parse (const std::string &in, const variable_replacer &replacer,
531
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
532
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
533
{
534
//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
535
std::vector<macro_userdata_s> userdata_list;
536
userdata_list.reserve (macros.size());
537
auto config_func = [&userdata_list, &replacer, &macros] (ucl_parser *parser) {
538
ucl_parser_set_variables_handler (parser, ucl_variable_replacer, &const_cast<variable_replacer &>(replacer));
539
for (auto & macro : macros) {
540
userdata_list.push_back ({parser, std::get<2>(macro)});
541
if (std::get<1>(macro).handler != NULL) {
542
ucl_parser_register_macro (parser,
543
std::get<0>(macro).c_str(),
544
std::get<1>(macro).handler,
545
reinterpret_cast<void*>(&userdata_list.back()));
546
}
547
else if (std::get<1>(macro).ctx_handler != NULL) {
548
ucl_parser_register_context_macro (parser,
549
std::get<0>(macro).c_str(),
550
std::get<1>(macro).ctx_handler,
551
reinterpret_cast<void*>(&userdata_list.back()));
552
}
553
}
554
};
555
556
auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
557
return ucl_parser_add_chunk_full (parser,
558
(unsigned char *) in.data (),
559
in.size (),
560
(unsigned int)ucl_parser_get_default_priority (parser),
561
duplicate_strategy,
562
UCL_PARSE_UCL);
563
};
564
565
return parse_with_strategy_function (config_func, parse_func, err);
566
}
567
568
static Ucl parse (const char *in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
569
{
570
return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
571
}
572
573
static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
574
{
575
if (!in) {
576
err = "null input";
577
return nullptr;
578
}
579
return parse (std::string (in), vars, err);
580
}
581
582
//Macro handler will receive a macro_userdata_s as void *ud
583
static Ucl parse (const char *in,
584
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
585
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
586
{
587
return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
588
}
589
590
//Macro handler will receive a macro_userdata_s as void *ud
591
static Ucl parse (const char *in, const std::map<std::string, std::string> &vars,
592
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
593
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
594
{
595
if (!in) {
596
err = "null input";
597
return nullptr;
598
}
599
return parse (std::string (in), vars, macros, err, duplicate_strategy);
600
}
601
602
static Ucl parse (const char *in, const variable_replacer &replacer,
603
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
604
{
605
if (!in) {
606
err = "null input";
607
return nullptr;
608
}
609
return parse (std::string(in), replacer, err, duplicate_strategy);
610
}
611
612
//Macro handler will receive a macro_userdata_s as void *ud
613
static Ucl parse (const char *in, const variable_replacer &replacer,
614
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > &macros,
615
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
616
{
617
if (!in) {
618
err = "null input";
619
return nullptr;
620
}
621
return parse (std::string (in), replacer, macros, err, duplicate_strategy);
622
}
623
624
static Ucl parse_from_file (const std::string &filename, std::string &err)
625
{
626
return parse_from_file (filename, std::map<std::string, std::string>(), err);
627
}
628
629
static Ucl parse_from_file (const std::string &filename, const std::map<std::string, std::string> &vars, std::string &err)
630
{
631
auto config_func = [&vars] (ucl_parser *parser) {
632
for (const auto & item : vars) {
633
ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
634
}
635
};
636
637
auto parse_func = [&filename] (ucl_parser *parser) {
638
return ucl_parser_add_file (parser, filename.c_str ());
639
};
640
641
return parse_with_strategy_function (config_func, parse_func, err);
642
}
643
644
static Ucl parse_from_file (const std::string &filename, const variable_replacer &replacer, std::string &err)
645
{
646
auto config_func = [&replacer] (ucl_parser *parser) {
647
ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
648
&const_cast<variable_replacer &>(replacer));
649
};
650
651
auto parse_func = [&filename] (ucl_parser *parser) {
652
return ucl_parser_add_file (parser, filename.c_str ());
653
};
654
655
return parse_with_strategy_function (config_func, parse_func, err);
656
}
657
658
static std::vector<std::string> find_variable (const std::string &in)
659
{
660
auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
661
662
std::set<std::string> vars;
663
ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
664
ucl_parser_add_chunk (parser, (const unsigned char *)in.data (), in.size ());
665
ucl_parser_free (parser);
666
667
std::vector<std::string> result;
668
std::move (vars.begin (), vars.end (), std::back_inserter (result));
669
return result;
670
}
671
672
static std::vector<std::string> find_variable (const char *in)
673
{
674
if (!in) {
675
return std::vector<std::string>();
676
}
677
return find_variable (std::string (in));
678
}
679
680
static std::vector<std::string> find_variable_from_file (const std::string &filename)
681
{
682
auto parser = ucl_parser_new (UCL_PARSER_DEFAULT);
683
684
std::set<std::string> vars;
685
ucl_parser_set_variables_handler (parser, ucl_variable_getter, &vars);
686
ucl_parser_add_file (parser, filename.c_str ());
687
ucl_parser_free (parser);
688
689
std::vector<std::string> result;
690
std::move (vars.begin (), vars.end (), std::back_inserter (result));
691
return result;
692
}
693
694
Ucl& operator= (Ucl rhs)
695
{
696
obj.swap (rhs.obj);
697
return *this;
698
}
699
700
bool operator== (const Ucl &rhs) const
701
{
702
return ucl_object_compare (obj.get(), rhs.obj.get ()) == 0;
703
}
704
bool operator< (const Ucl &rhs) const
705
{
706
return ucl_object_compare (obj.get(), rhs.obj.get ()) < 0;
707
}
708
bool operator!= (const Ucl &rhs) const { return !(*this == rhs); }
709
bool operator<= (const Ucl &rhs) const { return !(rhs < *this); }
710
bool operator> (const Ucl &rhs) const { return (rhs < *this); }
711
bool operator>= (const Ucl &rhs) const { return !(*this < rhs); }
712
713
explicit operator bool () const
714
{
715
if (!obj || type() == UCL_NULL) {
716
return false;
717
}
718
719
if (type () == UCL_BOOLEAN) {
720
return bool_value ();
721
}
722
723
return true;
724
}
725
726
const_iterator begin() const
727
{
728
return const_iterator(*this);
729
}
730
const_iterator cbegin() const
731
{
732
return const_iterator(*this);
733
}
734
const_iterator end() const
735
{
736
return const_iterator();
737
}
738
const_iterator cend() const
739
{
740
return const_iterator();
741
}
742
};
743
744
};
745
746