Branch data Line data Source code
1 : : /*
2 : : * Copyright 2006-2009 Savarese Software Research Corporation
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * https://www.savarese.com/software/ApacheLicense-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : /**
18 : : * @file
19 : : * This header defines the Properties class.
20 : : */
21 : :
22 : : #ifndef __SSRC_WSPR_UTILITY_PROPERTIES_H
23 : : #define __SSRC_WSPR_UTILITY_PROPERTIES_H
24 : :
25 : : #include <boost/variant.hpp>
26 : : #include <boost/serialization/variant.hpp>
27 : : #include <boost/serialization/vector.hpp>
28 : : #include <boost/serialization/split_member.hpp>
29 : : #include <boost/ptr_container/serialize_ptr_map.hpp>
30 : : #include <boost/ptr_container/serialize_ptr_vector.hpp>
31 : : #include <cstdint>
32 : : #include <climits>
33 : : #include <string>
34 : : #include <vector>
35 : : #include <utility>
36 : : #include <cstdarg>
37 : :
38 : : #include <ssrc/wispers/utility/properties_ptr.h>
39 : : // <boost/serialization/shared_ptr.hpp> leaks memmory (as of boost 1.41.0)
40 : : // and implements features unrequired by Wispers.
41 : : #include <ssrc/wispers/utility/serialize_shared_ptr.h>
42 : :
43 : : __BEGIN_NS_SSRC_WSPR_UTILITY
44 : :
45 : : template<typename T>
46 : : struct PropTreeValueOps {
47 : : typedef T value_type;
48 : : typedef T storage_type;
49 : :
50 : : storage_type copy(const value_type & t) const {
51 : : return t;
52 : : }
53 : :
54 : : void assign(storage_type & s, const value_type & t) const {
55 : : s = t;
56 : : }
57 : :
58 : : bool equal(const storage_type & a, const storage_type & b) const {
59 : : return (a == b);
60 : : }
61 : :
62 : : void free(const storage_type & t) const { }
63 : :
64 : : const storage_type & initial_value() const {
65 : : return DefaultValue;
66 : : }
67 : :
68 : : private:
69 : : static const value_type DefaultValue;
70 : : };
71 : :
72 : : template<typename T> typename PropTreeValueOps<T>::value_type const
73 : : PropTreeValueOps<T>::DefaultValue = typename PropTreeValueOps<T>::value_type();
74 : :
75 : : template<typename T>
76 : : struct PropTreePointerOps {
77 : : typedef T value_type;
78 : : typedef T* storage_type;
79 : :
80 : 529 : storage_type copy(const value_type & t) const {
81 [ + - ]: 529 : return new value_type(t);
82 : : }
83 : :
84 : 0 : storage_type copy(const storage_type & t) const {
85 [ # # ]: 0 : if(t == 0)
86 : 0 : return 0;
87 : 0 : return copy(*t);
88 : : }
89 : :
90 : 22 : void assign(storage_type & s, const value_type & v) const {
91 [ + + ]: 22 : if(s != 0) {
92 : 2 : *s = v;
93 : : } else {
94 : 20 : s = copy(v);
95 : : }
96 : 22 : }
97 : :
98 : 94 : bool equal(const storage_type a, const storage_type b) const {
99 [ + + + - ]: 94 : if(a != 0 && b != 0)
100 : 33 : return (*a == *b);
101 : 61 : return (a == b);
102 : : }
103 : :
104 : 1009 : void free(storage_type t) const {
105 [ + + ]: 1009 : delete t;
106 : 1009 : }
107 : :
108 : 1 : void assign(storage_type & s, const storage_type & v) const {
109 [ + - ]: 1 : if(s != 0) {
110 [ + - ]: 1 : if(v != 0) {
111 : 1 : *s = *v;
112 : : } else {
113 : 0 : free(s);
114 : 0 : s = 0;
115 : : }
116 : : } else {
117 : 0 : s = copy(v);
118 : : }
119 : 1 : }
120 : :
121 : 478 : storage_type initial_value() const {
122 : 478 : return 0;
123 : : }
124 : : };
125 : :
126 : : template<typename Key, typename Ops, typename TreeType>
127 : : class PropTree {
128 : : public:
129 : : typedef Key key_type;
130 : : typedef TreeType tree_type;
131 : : typedef Ops operations;
132 : : typedef typename operations::value_type value_type;
133 : : typedef typename operations::storage_type storage_type;
134 : :
135 : : typedef boost::ptr_map<key_type, tree_type> child_container;
136 : : typedef typename child_container::iterator child_container_iterator;
137 : : typedef typename child_container::const_iterator child_container_const_iterator;
138 : : typedef typename child_container::size_type size_type;
139 : : typedef std::pair<child_container_iterator, bool> insert_result_type;
140 : :
141 : : protected:
142 : :
143 : : static const operations Value;
144 : :
145 : : storage_type _value;
146 : : child_container _children;
147 : :
148 : : public:
149 : :
150 : 377 : PropTree() : _value(Value.initial_value()) { }
151 : :
152 : 532 : explicit PropTree(const value_type & v) : _value(Value.copy(v)) { }
153 : :
154 : : // PropTree should not be used as a polymorphic base class.
155 : 896 : /*virtual*/ ~PropTree() {
156 [ + - ]: 896 : Value.free(_value);
157 : 896 : }
158 : :
159 : : void clear() {
160 : : _children.clear();
161 : : }
162 : :
163 : 297 : bool is_leaf() const {
164 : 297 : return _children.empty();
165 : : }
166 : :
167 : 244 : const storage_type & value() const {
168 : 244 : return _value;
169 : : }
170 : :
171 : 2 : storage_type & value() {
172 : 2 : return _value;
173 : : }
174 : :
175 : 22 : void set_value(const value_type & v) {
176 : 22 : Value.assign(_value, v);
177 : 22 : }
178 : :
179 : 0 : child_container_const_iterator child_begin() const {
180 : 0 : return _children.begin();
181 : : }
182 : :
183 : 0 : child_container_const_iterator child_end() const {
184 : 0 : return _children.end();
185 : : }
186 : :
187 : 688 : tree_type * find(const key_type & key) {
188 : 688 : child_container_iterator && it = _children.find(key);
189 [ + + ]: 688 : if(it == _children.end())
190 : 665 : return 0;
191 : 23 : return it->second;
192 : : }
193 : :
194 : : template<typename... P>
195 : 11 : tree_type * find(const key_type & key, const P & ...p) {
196 : 11 : child_container_iterator && it = _children.find(key);
197 [ - + + + ]: 11 : if(it == _children.end()) {
198 : 2 : return 0;
199 : : }
200 [ + - + - : 9 : return it->second->find(p...);
+ - + - +
- + - + -
+ - ]
201 : : }
202 : :
203 : 413 : const tree_type * find(const key_type & key) const {
204 : 413 : child_container_const_iterator && it = _children.find(key);
205 [ + + ]: 413 : if(it == _children.end())
206 : 2 : return 0;
207 : 411 : return it->second;
208 : : }
209 : :
210 : : template<typename... P>
211 : 1812 : const tree_type * find(const key_type & key, const P & ...p) const {
212 : 1812 : child_container_const_iterator && it = _children.find(key);
213 [ + + - + : 1812 : if(it == _children.end()) {
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ ]
214 : 1 : return 0;
215 : : }
216 [ + - + - : 1811 : return it->second->find(p...);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
217 : : }
218 : :
219 : 534 : tree_type * set(const value_type & val, const key_type & key) {
220 : 534 : tree_type *tree = find(key);
221 : :
222 [ + + ]: 534 : if(tree != 0) {
223 : 2 : tree->set_value(val);
224 : : } else {
225 : : // const_cast works around ptr_map design without using std::auto_ptr
226 : : //_children.insert(key, std::auto_ptr<tree_type>(new tree_type(val)));
227 [ + - ]: 532 : _children.insert(const_cast<key_type &>(key), (tree = new tree_type(val)));
228 : : }
229 : :
230 : 534 : return tree;
231 : : }
232 : :
233 : : template<typename... P>
234 : : tree_type *
235 : 58 : set(const value_type & val, const key_type & key, const P & ...p) {
236 : 58 : tree_type *tree = find(key);
237 : :
238 [ + + + + ]: 58 : if(tree == 0) {
239 : : // const_cast works around ptr_map design without using std::auto_ptr
240 : : //_children.insert(key, std::auto_ptr<tree_type>(tree = new tree_type));
241 [ + - + - ]: 47 : _children.insert(const_cast<key_type &>(key), (tree = new tree_type));
242 : : }
243 : :
244 : 58 : return tree->set(val, p...);
245 : : }
246 : :
247 : 118 : tree_type * create_node(const key_type & key) {
248 : 118 : tree_type *tree = find(key);
249 : :
250 [ + - ]: 118 : if(tree == 0) {
251 : : // const_cast works around ptr_map design without using std::auto_ptr
252 : : //_children.insert(key, std::auto_ptr<tree_type>(new tree_type));
253 [ + - ]: 118 : _children.insert(const_cast<key_type &>(key), (tree = new tree_type));
254 : : }
255 : :
256 : 118 : return tree;
257 : : }
258 : :
259 : : template<typename... P>
260 : : tree_type *
261 : : create_node(const key_type & key, const P & ...p) {
262 : : tree_type *tree = find(key);
263 : :
264 : : if(tree == 0) {
265 : : // const_cast works around ptr_map design without using std::auto_ptr
266 : : //_children.insert(key, std::auto_ptr<tree_type>(tree = new tree_type));
267 : : _children.insert(const_cast<key_type &>(key), (tree = new tree_type));
268 : : }
269 : :
270 : : return tree->create_node(p...);
271 : : }
272 : :
273 : 2 : size_type erase(const key_type & key) {
274 : 2 : return _children.erase(key);
275 : : }
276 : :
277 : : template<typename... P>
278 : 3 : size_type erase(const key_type & key, const P & ...p) {
279 : 3 : tree_type *tree = find(key);
280 : :
281 [ + + + - ]: 3 : if(tree != 0) {
282 [ + - + - : 2 : return tree->erase(p...);
+ - + - +
- + - ]
283 : : }
284 : :
285 : 1 : return 0;
286 : : }
287 : :
288 : : // Visitor must define enter and leave functions.
289 : : template<typename Visitor>
290 : 4 : void visit(const Visitor & v) {
291 [ + + ]: 17 : for(child_container_iterator && it = _children.begin(),
292 : 4 : && end = _children.end(); it != end;)
293 : : {
294 : 5 : child_container_iterator child = it++;
295 : 5 : tree_type *tree = child->second;
296 : 5 : v.enter(child->first, tree, (it == end));
297 [ + + ]: 5 : if(!tree->is_leaf()) {
298 : 3 : tree->visit(v);
299 : : }
300 : 5 : v.leave(child->first, tree, (it == end));
301 : : }
302 : 4 : }
303 : :
304 : : template<typename Visitor>
305 : 62 : void visit(const Visitor & v) const {
306 [ + + ]: 279 : for(child_container_const_iterator && it = _children.begin(),
307 : 62 : && end = _children.end(); it != end;)
308 : : {
309 : 93 : child_container_const_iterator child = it++;
310 : 93 : const tree_type *tree = child->second;
311 [ + - ]: 93 : v.enter(child->first, tree, (it == end));
312 [ + + ]: 93 : if(!tree->is_leaf()) {
313 : 15 : tree->visit(v);
314 : : }
315 [ + - ]: 93 : v.leave(child->first, tree, (it == end));
316 : : }
317 : 62 : }
318 : :
319 : 81 : bool operator==(const tree_type & p) const {
320 [ - + ]: 81 : if(!Value.equal(_value, p._value))
321 : 0 : return false;
322 : :
323 [ + + ]: 81 : if(_children.size() != p._children.size())
324 : 6 : return false;
325 : :
326 : 75 : child_container_const_iterator && it1 = _children.begin(),
327 : 75 : && it2 = p._children.begin(), && end1 = _children.end();
328 : :
329 [ + + ]: 219 : while(it1 != end1) {
330 [ + - - + : 69 : if(it1->first != it2->first || !(*(it1->second) == *(it2->second)))
- + ]
331 : 0 : return false;
332 : 69 : ++it1;
333 : 69 : ++it2;
334 : : }
335 : :
336 : 75 : return true;
337 : : }
338 : :
339 : : // WARNING! This is a destructive merge with move semantics!
340 : 6 : void merge(tree_type && p) {
341 [ + + ]: 6 : if(!Value.equal(_value, p._value)) {
342 : 1 : Value.free(_value);
343 : 1 : _value = p._value;
344 : 1 : p._value = Value.initial_value();
345 : : }
346 : :
347 : 6 : child_container_iterator && it1 = _children.begin(),
348 : 6 : && it2 = p._children.begin(), && end1 = _children.end(),
349 : 6 : && end2 = p._children.end();
350 : :
351 [ + + ]: 19 : while(it2 != end2) {
352 [ + + ]: 9 : if(it1 == end1) {
353 : 2 : _children.transfer(it2, end2, p._children);
354 : 2 : break;
355 [ + + ]: 7 : } else if(it1->first == it2->first) {
356 : 4 : it1->second->merge(std::move(*it2->second));
357 : 4 : ++it1;
358 : 4 : ++it2;
359 [ + + ]: 3 : } else if(it1->first > it2->first) {
360 : 2 : _children.transfer(it2, p._children);
361 : 2 : ++it2;
362 : : } else {
363 : 1 : ++it1;
364 : : }
365 : : }
366 : 6 : }
367 : :
368 : : // Non-destructive merge.
369 : 7 : void merge(const tree_type & p) {
370 [ + + ]: 7 : if(!Value.equal(_value, p._value)) {
371 : 1 : Value.assign(_value, p._value);
372 : : }
373 : :
374 : 7 : child_container_iterator && it1 = _children.begin(),
375 : 7 : && end1 = _children.end();
376 : 7 : child_container_const_iterator && it2 = p._children.begin(),
377 : 7 : && end2 = p._children.end();
378 : :
379 [ + + ]: 20 : while(it2 != end2) {
380 [ + + ]: 9 : if(it1 == end1) {
381 : 3 : _children.insert(it2, end2);
382 : 3 : break;
383 [ + + ]: 6 : } else if(it1->first == it2->first) {
384 : 4 : it1->second->merge(*it2->second);
385 : 4 : ++it1;
386 : 4 : ++it2;
387 [ + + ]: 2 : } else if(it1->first > it2->first) {
388 : 1 : child_container_const_iterator pos = it2;
389 : 1 : _children.insert(pos, ++it2);
390 : : } else {
391 : 1 : ++it1;
392 : : }
393 : : }
394 : 7 : }
395 : :
396 : : // These functions exist for the benefit of SWIG wrappers. Do not
397 : : // call from C++ code. Use variadic templates instead.
398 : 1 : tree_type * va_set(const value_type & val, const std::va_list & ap) {
399 : : key_type *key;
400 : 1 : tree_type *tree = static_cast<tree_type*>(this);
401 : :
402 [ + - + + ]: 5 : while((key = va_arg(ap, key_type *)) != 0) {
403 : 3 : child_container & children = tree->_children;
404 : 3 : tree = tree->find(*key);
405 : :
406 [ + - ]: 3 : if(tree == 0) {
407 [ + - ]: 3 : children.insert(*key, (tree = new tree_type));
408 : : //children.insert(*key, std::auto_ptr<tree_type>(new tree_type));
409 : : }
410 : : }
411 : :
412 : 1 : tree->set_value(val);
413 : :
414 : 1 : return tree;
415 : : }
416 : :
417 : 2 : tree_type * va_list_find(const key_type *key, const std::va_list & ap) {
418 : 2 : tree_type *tree = static_cast<tree_type*>(this);
419 : :
420 [ - + ]: 2 : do {
421 [ + + ]: 2 : if((tree = tree->find(*key)) == 0) {
422 [ + - ]: 1 : return 0;
423 : : }
424 : : } while((key = va_arg(ap, const key_type *)) != 0);
425 : :
426 : 1 : return tree;
427 : : }
428 : :
429 : 2 : tree_type * va_find(const key_type *key, ...) {
430 : : std::va_list ap;
431 : :
432 : 2 : va_start(ap, key);
433 : :
434 : 2 : tree_type *result = va_list_find(key, ap);
435 : :
436 : 2 : va_end(ap);
437 : :
438 : 2 : return result;
439 : : }
440 : :
441 : : // These functions exist for supporting keys serialized as a sequence
442 : : // of tokens, making it impossible to call a multi-argument function.
443 : : template<typename Iterator>
444 : : tree_type * iterator_set(const value_type & val,
445 : : const Iterator & begin,
446 : : const Iterator & end)
447 : : {
448 : : tree_type *tree = static_cast<tree_type*>(this);
449 : :
450 : : for(Iterator key = begin; key != end; ++key) {
451 : : child_container & children = tree->_children;
452 : : tree = tree->find(*key);
453 : :
454 : : if(tree == 0) {
455 : : children.insert(const_cast<key_type &>(*key), (tree = new tree_type));
456 : : //children.insert(*key, std::auto_ptr<tree_type>(new tree_type));
457 : : }
458 : : }
459 : :
460 : : tree->set_value(val);
461 : :
462 : : return tree;
463 : : }
464 : : template<typename Iterator>
465 : : size_type iterator_erase(const Iterator & begin,
466 : : const Iterator & end)
467 : : {
468 : : tree_type *tree = static_cast<tree_type*>(this);
469 : : tree_type *parent = 0;
470 : : Iterator last_key;
471 : :
472 : : for(Iterator key = begin; key != end; ++key) {
473 : : parent = tree;
474 : : if((tree = tree->find(*key)) == 0) {
475 : : return 0;
476 : : }
477 : : last_key = key;
478 : : }
479 : :
480 : : if(parent) {
481 : : return parent->erase(*last_key);
482 : : }
483 : :
484 : : return 0;
485 : : }
486 : :
487 : : template<typename Iterator>
488 : : tree_type * iterator_find(const Iterator & begin, const Iterator & end) {
489 : : tree_type *tree = static_cast<tree_type*>(this);
490 : :
491 : : for(Iterator key = begin; key != end; ++key) {
492 : : if((tree = tree->find(*key)) == 0) {
493 : : return 0;
494 : : }
495 : : }
496 : :
497 : : return tree;
498 : : }
499 : :
500 : : template<typename Iterator>
501 : : const tree_type *
502 : : iterator_find(const Iterator & begin, const Iterator & end) const {
503 : : const tree_type *tree = static_cast<const tree_type*>(this);
504 : :
505 : : for(Iterator key = begin; key != end; ++key) {
506 : : if((tree = tree->find(*key)) == 0) {
507 : : return 0;
508 : : }
509 : : }
510 : :
511 : : return tree;
512 : : }
513 : :
514 : : // Serialization support.
515 : : template<class Archive>
516 : 100 : void save(Archive & ar, const unsigned int) const {
517 : 100 : ar << _value << _children;
518 : 100 : }
519 : :
520 : : template<class Archive>
521 : 100 : void load(Archive & ar, const unsigned int) {
522 : 100 : Value.free(_value);
523 : 100 : _value = Value.initial_value();
524 : 100 : ar >> _value >> _children;
525 : 100 : }
526 : :
527 : 200 : BOOST_SERIALIZATION_SPLIT_MEMBER()
528 : : };
529 : :
530 : : template<typename K, typename T, typename Tr>
531 : : typename PropTree<K, T, Tr>::operations
532 : : const PropTree<K, T, Tr>::Value = typename PropTree<K, T, Tr>::operations();
533 : :
534 : : enum PropertyType {
535 : : PropertyBool,
536 : : PropertyInt,
537 : : PropertyUInt,
538 : : PropertyInt64,
539 : : PropertyUInt64,
540 : : PropertyDouble,
541 : : PropertyString,
542 : : PropertyPrimitiveArray,
543 : : PropertyArray
544 : : };
545 : :
546 : : typedef
547 : : boost::variant<bool, std::int32_t, std::uint32_t,
548 : : std::int64_t, std::uint64_t, double,
549 : : std::string>
550 : : primitive_property_type;
551 : :
552 : : class Properties;
553 : :
554 : : typedef std::vector<primitive_property_type> primitive_property_vector;
555 : : typedef boost::ptr_vector<Properties> property_vector;
556 : :
557 : : typedef
558 : : boost::variant<bool, std::int32_t, std::uint32_t,
559 : : std::int64_t, std::uint64_t, double,
560 : : std::string, primitive_property_vector, property_vector>
561 : : property_type;
562 : :
563 : : template<typename T>
564 : 446 : class property_type_value_extractor : public boost::static_visitor<void> {
565 : : T* & value;
566 : :
567 : : public:
568 : :
569 : 446 : property_type_value_extractor(T* & value) : value(value) { }
570 : :
571 : 444 : void operator()(T & v) const { value = &v; }
572 : :
573 : : template<typename V>
574 : 2 : void operator()(V & v) const { value = 0; }
575 : : };
576 : :
577 : :
578 : 896 : class Properties : public PropTree<std::string,
579 : : PropTreePointerOps<property_type>,
580 : : Properties>
581 : : {
582 : : public:
583 : : typedef
584 : : PropTree<std::string, PropTreePointerOps<property_type>, Properties> super;
585 : :
586 : 348 : Properties() { }
587 : :
588 : 532 : explicit Properties(const value_type & v) : super(v) { }
589 : :
590 : 22 : Properties(const Properties & p) {
591 : : #ifdef WSPR_DEBUG
592 [ + - ]: 22 : std::cerr << "Properties non-move const copy constructor called\n";
593 : : #endif
594 [ + + ]: 22 : if(p._value != 0) {
595 [ + - ]: 10 : set_value(*p._value);
596 : : } else {
597 [ + - ]: 12 : Value.free(_value);
598 : 12 : _value = 0;
599 : : }
600 [ + - + - : 22 : _children = p._children.clone();
+ - + - ]
601 : 22 : }
602 : :
603 : : Properties & operator=(const Properties & p) {
604 : : #ifdef WSPR_DEBUG
605 : : std::cerr << "Properties non-move assignment operator called\n";
606 : : #endif
607 : : if(p._value != 0) {
608 : : set_value(*p._value);
609 : : } else {
610 : : Value.free(_value);
611 : : _value = 0;
612 : : }
613 : : _children = p._children.clone();
614 : : return *this;
615 : : }
616 : :
617 : : // Begin move semantics.
618 : 7 : explicit Properties(Properties && p) {
619 : 7 : _value = p._value;
620 : 7 : p._value = 0;
621 [ + - + - : 7 : _children = p._children.release();
+ - + - ]
622 : 7 : }
623 : :
624 : : Properties & operator=(Properties && p) {
625 : : Value.free(_value);
626 : : _value = p._value;
627 : : p._value = 0;
628 : : _children = p._children.release();
629 : : return *this;
630 : : }
631 : : // End move semantics.
632 : :
633 : 3 : bool is_null() const {
634 : 3 : return (_value == 0);
635 : : }
636 : :
637 : : // Work around conversion of string literal values to bool by automatic
638 : : // type coercion in choosing variant constructor.
639 : : template<typename... P>
640 : 8 : Properties * set(const char * const val, const P & ...p) {
641 [ + - + - : 8 : return super::set(std::string(val), p...);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + +
+ + ]
642 : : }
643 : :
644 : : // Disambiguate type conversions.
645 : : #if (LONG_MAX == INT_MAX)
646 : : template<typename... P>
647 : : Properties * set(const long val, const P & ...p) {
648 : : return super::set(static_cast<std::int32_t>(val), p...);
649 : : }
650 : :
651 : : template<typename... P>
652 : : Properties * set(const unsigned long val, const P & ...p) {
653 : : return super::set(static_cast<std::uint32_t>(val), p...);
654 : : }
655 : : #endif
656 : :
657 : : template<typename... P>
658 : : Properties * set(const char val, const P & ...p) {
659 : : return super::set(static_cast<std::int32_t>(val), p...);
660 : : }
661 : :
662 : : template<typename... P>
663 : : Properties * set(const signed char val, const P & ...p) {
664 : : return super::set(static_cast<std::int32_t>(val), p...);
665 : : }
666 : :
667 : : template<typename... P>
668 : : Properties * set(const unsigned char val, const P & ...p) {
669 : : return super::set(static_cast<std::uint32_t>(val), p...);
670 : : }
671 : :
672 : : template<typename... P>
673 : 6 : Properties * set(const bool val, const P & ...p) {
674 [ + - + - : 6 : return super::set(val, p...);
+ - + - +
- ]
675 : : }
676 : :
677 : : template<typename... P>
678 : 59 : Properties * set(const std::int32_t val, const P & ...p) {
679 [ + - + - : 59 : return super::set(val, p...);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
680 : : }
681 : :
682 : : template<typename... P>
683 : 36 : Properties * set(const std::uint32_t val, const P & ...p) {
684 [ + - + - : 36 : return super::set(val, p...);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
685 : : }
686 : :
687 : : template<typename... P>
688 : : Properties * set(const std::int16_t val, const P & ...p) {
689 : : return super::set(static_cast<std::int32_t>(val), p...);
690 : : }
691 : :
692 : : template<typename... P>
693 : : Properties * set(const std::uint16_t val, const P & ...p) {
694 : : return super::set(static_cast<std::int32_t>(val), p...);
695 : : }
696 : :
697 : : template<typename... P>
698 : : Properties * set(const std::int64_t val, const P & ...p) {
699 : : return super::set(val, p...);
700 : : }
701 : :
702 : : template<typename... P>
703 : 1 : Properties * set(const std::uint64_t val, const P & ...p) {
704 [ + - + - : 1 : return super::set(val, p...);
+ - + - +
- ]
705 : : }
706 : :
707 : : template<typename... P>
708 : 1 : Properties * set(const float val, const P & ...p) {
709 [ + - + - : 1 : return super::set(static_cast<double>(val), p...);
+ - + - +
- ]
710 : : }
711 : :
712 : : template<typename... P>
713 : 39 : Properties * set(const double val, const P & ...p) {
714 [ + - + - : 39 : return super::set(val, p...);
+ - + - +
- + - + -
+ - + - +
- ]
715 : : }
716 : :
717 : : template<typename... P>
718 : 442 : Properties * set(const value_type & val, const P & ...p) {
719 [ + - + - : 442 : return super::set(val, p...);
+ - + - +
- + - + -
+ - + - ]
720 : : }
721 : :
722 : : // Do same for iterator_set.
723 : : template<typename Iterator>
724 : : Properties * iterator_set(const char * const val,
725 : : const Iterator & begin,
726 : : const Iterator & end)
727 : : {
728 : : return super::iterator_set(std::string(val), begin, end);
729 : : }
730 : :
731 : : #if (LONG_MAX == INT_MAX)
732 : : template<typename Iterator>
733 : : Properties * iterator_set(const long val,
734 : : const Iterator & begin,
735 : : const Iterator & end)
736 : : {
737 : : return super::iterator_set(static_cast<std::int32_t>(val), begin, end);
738 : : }
739 : :
740 : : template<typename Iterator>
741 : : Properties * iterator_set(const unsigned long val,
742 : : const Iterator & begin,
743 : : const Iterator & end)
744 : : {
745 : : return super::iterator_set(static_cast<std::uint32_t>(val), begin, end);
746 : : }
747 : : #endif
748 : :
749 : : template<typename Iterator>
750 : : Properties * iterator_set(const char val,
751 : : const Iterator & begin,
752 : : const Iterator & end)
753 : : {
754 : : return super::iterator_set(static_cast<std::int32_t>(val), begin, end);
755 : : }
756 : :
757 : : template<typename Iterator>
758 : : Properties * iterator_set(const signed char val,
759 : : const Iterator & begin,
760 : : const Iterator & end)
761 : : {
762 : : return super::iterator_set(static_cast<std::int32_t>(val), begin, end);
763 : : }
764 : :
765 : : template<typename Iterator>
766 : : Properties * iterator_set(const unsigned char val,
767 : : const Iterator & begin,
768 : : const Iterator & end)
769 : : {
770 : : return super::iterator_set(static_cast<std::uint32_t>(val), begin, end);
771 : : }
772 : :
773 : : template<typename Iterator>
774 : : Properties * iterator_set(const bool val,
775 : : const Iterator & begin,
776 : : const Iterator & end)
777 : : {
778 : : return super::iterator_set(val, begin, end);
779 : : }
780 : :
781 : : template<typename Iterator>
782 : : Properties * iterator_set(const std::int32_t val,
783 : : const Iterator & begin,
784 : : const Iterator & end)
785 : : {
786 : : return super::iterator_set(val, begin, end);
787 : : }
788 : :
789 : : template<typename Iterator>
790 : : Properties * iterator_set(const std::uint32_t val,
791 : : const Iterator & begin,
792 : : const Iterator & end)
793 : : {
794 : : return super::iterator_set(val, begin, end);
795 : : }
796 : :
797 : : template<typename Iterator>
798 : : Properties * iterator_set(const std::int64_t val,
799 : : const Iterator & begin,
800 : : const Iterator & end)
801 : : {
802 : : return super::iterator_set(val, begin, end);
803 : : }
804 : :
805 : : template<typename Iterator>
806 : : Properties * iterator_set(const std::uint64_t val,
807 : : const Iterator & begin,
808 : : const Iterator & end)
809 : : {
810 : : return super::iterator_set(val, begin, end);
811 : : }
812 : :
813 : : template<typename Iterator>
814 : : Properties * iterator_set(const float val,
815 : : const Iterator & begin,
816 : : const Iterator & end)
817 : : {
818 : : return super::iterator_set(static_cast<double>(val), begin, end);
819 : : }
820 : :
821 : : template<typename Iterator>
822 : : Properties * iterator_set(const double val,
823 : : const Iterator & begin,
824 : : const Iterator & end)
825 : : {
826 : : return super::iterator_set(val, begin, end);
827 : : }
828 : :
829 : : template<typename Iterator>
830 : : Properties * iterator_set(const value_type & val,
831 : : const Iterator & begin,
832 : : const Iterator & end)
833 : : {
834 : : return super::iterator_set(val, begin, end);
835 : : }
836 : :
837 : : template<typename T>
838 : 446 : T* get_ptr() const {
839 : 446 : T* result = 0;
840 : :
841 [ + - + - : 446 : if(_value != 0) {
+ - + - +
- + - ]
842 [ + - + - : 446 : boost::apply_visitor(property_type_value_extractor<T>(result), *_value);
+ - + - +
- + - ]
843 : : }
844 : :
845 : 446 : return result;
846 : : }
847 : :
848 : : template<typename T, typename... P>
849 : 411 : T* get_ptr(const P & ...p) const {
850 [ + - + - : 411 : const Properties *result = find(p...);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
851 : :
852 [ + - + + : 411 : if(result != 0)
+ - + - +
+ + + + -
+ - + - +
- + - + -
+ - + - ]
853 : 408 : return result->get_ptr<T>();
854 : :
855 : 3 : return 0;
856 : : }
857 : :
858 : 15 : property_vector & create_property_vector() {
859 [ + - + - : 15 : set_value(property_vector());
+ - ]
860 : 15 : return *get_ptr<property_vector>();
861 : : }
862 : :
863 : : template<typename... P>
864 : 13 : property_vector & create_property_vector(const P & ...p) {
865 [ + - + - : 13 : return *(set(property_vector(), p...)->get_ptr<property_vector>());
+ - + - +
- + - + -
+ - ]
866 : : }
867 : :
868 : 5 : primitive_property_vector & create_primitive_property_vector() {
869 [ + - + - : 5 : set_value(primitive_property_vector());
+ - ]
870 : 5 : return *get_ptr<primitive_property_vector>();
871 : : }
872 : :
873 : : template<typename... P>
874 : 3 : primitive_property_vector & create_primitive_property_vector(const P & ...p) {
875 [ + - + - : 3 : return *(set(primitive_property_vector(), p...)->get_ptr<primitive_property_vector>());
+ - + - ]
876 : : }
877 : :
878 : : template<typename T>
879 : 11 : const T & get(const T & default_value = T()) const {
880 : 11 : T* result = get_ptr<T>();
881 : :
882 [ + - + - ]: 11 : if(result != 0) {
883 : 11 : return (*result);
884 : : }
885 : :
886 : 0 : return default_value;
887 : : }
888 : :
889 : : template<typename T, typename... P>
890 : 19 : const T & get(const T & default_value, const P & ...p) const {
891 : 19 : T* result = get_ptr<T>(p...);
892 : :
893 [ + - + + : 19 : if(result != 0)
+ - + - -
+ + + # #
# # # # #
# # # # #
# # # # ]
894 : 16 : return (*result);
895 : :
896 : 3 : return default_value;
897 : : }
898 : :
899 : : // These functions exist for the benefit of SWIG wrappers. Do not
900 : : // call from C++ code. Use variadic templates instead.
901 : :
902 : : template<typename T>
903 : 1 : void va_set(const T & val, ...) {
904 : : std::va_list ap;
905 : :
906 : 1 : va_start(ap, val);
907 : :
908 [ + - ]: 1 : super::va_set(val, ap);
909 : :
910 : 1 : va_end(ap);
911 : 1 : }
912 : :
913 : : template<class Archive>
914 : 200 : void serialize(Archive & ar, const unsigned int) {
915 : 200 : ar & boost::serialization::base_object<super>(*this);
916 : 200 : }
917 : : };
918 : :
919 : :
920 : : template<typename T, typename Archive>
921 : 55 : T load_property(Archive & ar) {
922 : 23 : T value;
923 [ + - ]: 55 : ar >> value;
924 : 55 : return value;
925 : : }
926 : :
927 : : template<typename V, typename Archive>
928 : 4 : void load_property_vector(Archive & ar, property_type & p)
929 : : SSRC_DECL_THROW(boost::bad_get)
930 : : {
931 [ + - + - ]: 4 : p = V();
932 : 4 : ar >> boost::get<V>(p);
933 : 4 : }
934 : :
935 : : __END_NS_SSRC_WSPR_UTILITY
936 : :
937 : : // We need to specialize variant load to avoid copy of ptr_vector.
938 : : // We use boost variant save unchanged.
939 : : namespace boost {
940 : : namespace serialization {
941 : : template<class Archive>
942 : 59 : void load(Archive & ar, NS_SSRC_WSPR_UTILITY::property_type & p,
943 : : const unsigned int)
944 : : {
945 : : using namespace NS_SSRC_WSPR_UTILITY;
946 : :
947 : : int which;
948 : 59 : ar >> which;
949 [ + + + - : 59 : switch(which) {
+ + + + +
- ]
950 : 1 : case PropertyBool: p = load_property<bool>(ar); break;
951 : 15 : case PropertyInt: p = load_property<std::int32_t>(ar); break;
952 : 11 : case PropertyUInt: p = load_property<std::uint32_t>(ar); break;
953 : 0 : case PropertyInt64: p = load_property<std::int64_t>(ar); break;
954 : 1 : case PropertyUInt64: p = load_property<std::uint64_t>(ar); break;
955 : 4 : case PropertyDouble: p = load_property<double>(ar); break;
956 [ + - ]: 23 : case PropertyString: p = load_property<std::string>(ar); break;
957 : : case PropertyPrimitiveArray:
958 : 2 : load_property_vector<primitive_property_vector>(ar, p);
959 : 2 : break;
960 : : case PropertyArray:
961 : 2 : load_property_vector<property_vector>(ar, p);
962 : 2 : break;
963 : : default:
964 [ # # ]: 0 : throw boost::archive::archive_exception(boost::archive::archive_exception::unsupported_version);
965 : : break;
966 : : };
967 : 59 : }
968 : : }
969 : : }
970 : :
971 : : BOOST_CLASS_TRACKING(NS_SSRC_WSPR_UTILITY::primitive_property_type, boost::serialization::track_never)
972 : : BOOST_CLASS_TRACKING(NS_SSRC_WSPR_UTILITY::property_type, boost::serialization::track_never)
973 : : BOOST_CLASS_TRACKING(NS_SSRC_WSPR_UTILITY::primitive_property_vector, boost::serialization::track_never)
974 : : BOOST_CLASS_TRACKING(NS_SSRC_WSPR_UTILITY::property_vector, boost::serialization::track_never)
975 : : BOOST_CLASS_TRACKING(NS_SSRC_WSPR_UTILITY::Properties, boost::serialization::track_never)
976 : :
977 : : #endif
|