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