1 | // ---------------------------------------------------------------------------- |
2 | // Copyright (C) 2002-2006 Marcin Kalicinski |
3 | // Copyright (C) 2009 Sebastian Redl |
4 | // |
5 | // Distributed under the Boost Software License, Version 1.0. |
6 | // (See accompanying file LICENSE_1_0.txt or copy at |
7 | // http://www.boost.org/LICENSE_1_0.txt) |
8 | // |
9 | // For more information, see www.boost.org |
10 | // ---------------------------------------------------------------------------- |
11 | #ifndef BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED |
12 | #define BOOST_PROPERTY_TREE_DETAIL_PTREE_IMPLEMENTATION_HPP_INCLUDED |
13 | |
14 | #include <boost/property_tree/ptree.hpp> |
15 | #include <boost/iterator/iterator_adaptor.hpp> |
16 | #include <boost/iterator/reverse_iterator.hpp> |
17 | #include <boost/assert.hpp> |
18 | #include <boost/core/invoke_swap.hpp> |
19 | #include <boost/core/type_name.hpp> |
20 | #include <memory> |
21 | |
22 | #if (defined(BOOST_MSVC) && \ |
23 | (_MSC_FULL_VER >= 160000000 && _MSC_FULL_VER < 170000000)) || \ |
24 | (defined(BOOST_INTEL_WIN) && \ |
25 | defined(BOOST_DINKUMWARE_STDLIB)) |
26 | #define BOOST_PROPERTY_TREE_PAIR_BUG |
27 | #endif |
28 | |
29 | namespace boost { namespace property_tree |
30 | { |
31 | template <class K, class D, class C> |
32 | struct basic_ptree<K, D, C>::subs |
33 | { |
34 | struct by_name {}; |
35 | // The actual child container. |
36 | #if defined(BOOST_PROPERTY_TREE_PAIR_BUG) |
37 | // MSVC 10 has moved std::pair's members to a base |
38 | // class. Unfortunately this does break the interface. |
39 | BOOST_STATIC_CONSTANT(unsigned, |
40 | first_offset = offsetof(value_type, first)); |
41 | #endif |
42 | typedef multi_index_container<value_type, |
43 | multi_index::indexed_by< |
44 | multi_index::sequenced<>, |
45 | multi_index::ordered_non_unique<multi_index::tag<by_name>, |
46 | #if defined(BOOST_PROPERTY_TREE_PAIR_BUG) |
47 | multi_index::member_offset<value_type, const key_type, |
48 | first_offset>, |
49 | #else |
50 | multi_index::member<value_type, const key_type, |
51 | &value_type::first>, |
52 | #endif |
53 | key_compare |
54 | > |
55 | > |
56 | > base_container; |
57 | |
58 | // The by-name lookup index. |
59 | typedef typename base_container::template index<by_name>::type |
60 | by_name_index; |
61 | |
62 | // Access functions for getting to the children of a tree. |
63 | static base_container& ch(self_type *s) { |
64 | return *static_cast<base_container*>(s->m_children); |
65 | } |
66 | static const base_container& ch(const self_type *s) { |
67 | return *static_cast<const base_container*>(s->m_children); |
68 | } |
69 | static by_name_index& assoc(self_type *s) { |
70 | return ch(s).BOOST_NESTED_TEMPLATE get<by_name>(); |
71 | } |
72 | static const by_name_index& assoc(const self_type *s) { |
73 | return ch(s).BOOST_NESTED_TEMPLATE get<by_name>(); |
74 | } |
75 | }; |
76 | template <class K, class D, class C> |
77 | class basic_ptree<K, D, C>::iterator : public boost::iterator_adaptor< |
78 | iterator, typename subs::base_container::iterator, value_type> |
79 | { |
80 | friend class boost::iterator_core_access; |
81 | typedef boost::iterator_adaptor< |
82 | iterator, typename subs::base_container::iterator, value_type> |
83 | baset; |
84 | public: |
85 | typedef typename baset::reference reference; |
86 | iterator() {} |
87 | explicit iterator(typename iterator::base_type b) |
88 | : iterator::iterator_adaptor_(b) |
89 | {} |
90 | reference dereference() const |
91 | { |
92 | // multi_index doesn't allow modification of its values, because |
93 | // indexes could sort by anything, and modification screws that up. |
94 | // However, we only sort by the key, and it's protected against |
95 | // modification in the value_type, so this const_cast is safe. |
96 | return const_cast<reference>(*this->base_reference()); |
97 | } |
98 | }; |
99 | template <class K, class D, class C> |
100 | class basic_ptree<K, D, C>::const_iterator : public boost::iterator_adaptor< |
101 | const_iterator, typename subs::base_container::const_iterator> |
102 | { |
103 | public: |
104 | const_iterator() {} |
105 | explicit const_iterator(typename const_iterator::base_type b) |
106 | : const_iterator::iterator_adaptor_(b) |
107 | {} |
108 | const_iterator(iterator b) |
109 | : const_iterator::iterator_adaptor_(b.base()) |
110 | {} |
111 | }; |
112 | template <class K, class D, class C> |
113 | class basic_ptree<K, D, C>::reverse_iterator |
114 | : public boost::reverse_iterator<iterator> |
115 | { |
116 | public: |
117 | reverse_iterator() {} |
118 | explicit reverse_iterator(iterator b) |
119 | : boost::reverse_iterator<iterator>(b) |
120 | {} |
121 | }; |
122 | template <class K, class D, class C> |
123 | class basic_ptree<K, D, C>::const_reverse_iterator |
124 | : public boost::reverse_iterator<const_iterator> |
125 | { |
126 | public: |
127 | const_reverse_iterator() {} |
128 | explicit const_reverse_iterator(const_iterator b) |
129 | : boost::reverse_iterator<const_iterator>(b) |
130 | {} |
131 | const_reverse_iterator( |
132 | typename basic_ptree<K, D, C>::reverse_iterator b) |
133 | : boost::reverse_iterator<const_iterator>(b) |
134 | {} |
135 | }; |
136 | template <class K, class D, class C> |
137 | class basic_ptree<K, D, C>::assoc_iterator |
138 | : public boost::iterator_adaptor<assoc_iterator, |
139 | typename subs::by_name_index::iterator, |
140 | value_type> |
141 | { |
142 | friend class boost::iterator_core_access; |
143 | typedef boost::iterator_adaptor<assoc_iterator, |
144 | typename subs::by_name_index::iterator, |
145 | value_type> |
146 | baset; |
147 | public: |
148 | typedef typename baset::reference reference; |
149 | assoc_iterator() {} |
150 | explicit assoc_iterator(typename assoc_iterator::base_type b) |
151 | : assoc_iterator::iterator_adaptor_(b) |
152 | {} |
153 | reference dereference() const |
154 | { |
155 | return const_cast<reference>(*this->base_reference()); |
156 | } |
157 | }; |
158 | template <class K, class D, class C> |
159 | class basic_ptree<K, D, C>::const_assoc_iterator |
160 | : public boost::iterator_adaptor<const_assoc_iterator, |
161 | typename subs::by_name_index::const_iterator> |
162 | { |
163 | public: |
164 | const_assoc_iterator() {} |
165 | explicit const_assoc_iterator( |
166 | typename const_assoc_iterator::base_type b) |
167 | : const_assoc_iterator::iterator_adaptor_(b) |
168 | {} |
169 | const_assoc_iterator(assoc_iterator b) |
170 | : const_assoc_iterator::iterator_adaptor_(b.base()) |
171 | {} |
172 | }; |
173 | |
174 | |
175 | // Big five |
176 | |
177 | // Perhaps the children collection could be created on-demand only, to |
178 | // reduce heap traffic. But that's a lot more work to implement. |
179 | |
180 | template<class K, class D, class C> inline |
181 | basic_ptree<K, D, C>::basic_ptree() |
182 | : m_children(new typename subs::base_container) |
183 | { |
184 | } |
185 | |
186 | template<class K, class D, class C> inline |
187 | basic_ptree<K, D, C>::basic_ptree(const data_type &d) |
188 | : m_data(d), m_children(new typename subs::base_container) |
189 | { |
190 | } |
191 | |
192 | template<class K, class D, class C> inline |
193 | basic_ptree<K, D, C>::basic_ptree(const basic_ptree<K, D, C> &rhs) |
194 | : m_data(rhs.m_data), |
195 | m_children(new typename subs::base_container(subs::ch(&rhs))) |
196 | { |
197 | } |
198 | |
199 | template<class K, class D, class C> |
200 | basic_ptree<K, D, C> & |
201 | basic_ptree<K, D, C>::operator =(const basic_ptree<K, D, C> &rhs) |
202 | { |
203 | self_type(rhs).swap(*this); |
204 | return *this; |
205 | } |
206 | |
207 | template<class K, class D, class C> |
208 | basic_ptree<K, D, C>::~basic_ptree() |
209 | { |
210 | delete &subs::ch(this); |
211 | } |
212 | |
213 | template<class K, class D, class C> inline |
214 | void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs) |
215 | { |
216 | boost::core::invoke_swap(m_data, rhs.m_data); |
217 | // Void pointers, no ADL necessary |
218 | std::swap(m_children, rhs.m_children); |
219 | } |
220 | |
221 | // Container view |
222 | |
223 | template<class K, class D, class C> inline |
224 | typename basic_ptree<K, D, C>::size_type |
225 | basic_ptree<K, D, C>::size() const |
226 | { |
227 | return subs::ch(this).size(); |
228 | } |
229 | |
230 | template<class K, class D, class C> inline |
231 | typename basic_ptree<K, D, C>::size_type |
232 | basic_ptree<K, D, C>::max_size() const |
233 | { |
234 | return subs::ch(this).max_size(); |
235 | } |
236 | |
237 | template<class K, class D, class C> inline |
238 | bool basic_ptree<K, D, C>::empty() const |
239 | { |
240 | return subs::ch(this).empty(); |
241 | } |
242 | |
243 | template<class K, class D, class C> inline |
244 | typename basic_ptree<K, D, C>::iterator |
245 | basic_ptree<K, D, C>::begin() |
246 | { |
247 | return iterator(subs::ch(this).begin()); |
248 | } |
249 | |
250 | template<class K, class D, class C> inline |
251 | typename basic_ptree<K, D, C>::const_iterator |
252 | basic_ptree<K, D, C>::begin() const |
253 | { |
254 | return const_iterator(subs::ch(this).begin()); |
255 | } |
256 | |
257 | template<class K, class D, class C> inline |
258 | typename basic_ptree<K, D, C>::iterator |
259 | basic_ptree<K, D, C>::end() |
260 | { |
261 | return iterator(subs::ch(this).end()); |
262 | } |
263 | |
264 | template<class K, class D, class C> inline |
265 | typename basic_ptree<K, D, C>::const_iterator |
266 | basic_ptree<K, D, C>::end() const |
267 | { |
268 | return const_iterator(subs::ch(this).end()); |
269 | } |
270 | |
271 | template<class K, class D, class C> inline |
272 | typename basic_ptree<K, D, C>::reverse_iterator |
273 | basic_ptree<K, D, C>::rbegin() |
274 | { |
275 | return reverse_iterator(this->end()); |
276 | } |
277 | |
278 | template<class K, class D, class C> inline |
279 | typename basic_ptree<K, D, C>::const_reverse_iterator |
280 | basic_ptree<K, D, C>::rbegin() const |
281 | { |
282 | return const_reverse_iterator(this->end()); |
283 | } |
284 | |
285 | template<class K, class D, class C> inline |
286 | typename basic_ptree<K, D, C>::reverse_iterator |
287 | basic_ptree<K, D, C>::rend() |
288 | { |
289 | return reverse_iterator(this->begin()); |
290 | } |
291 | |
292 | template<class K, class D, class C> inline |
293 | typename basic_ptree<K, D, C>::const_reverse_iterator |
294 | basic_ptree<K, D, C>::rend() const |
295 | { |
296 | return const_reverse_iterator(this->begin()); |
297 | } |
298 | |
299 | template<class K, class D, class C> inline |
300 | typename basic_ptree<K, D, C>::value_type & |
301 | basic_ptree<K, D, C>::front() |
302 | { |
303 | return const_cast<value_type&>(subs::ch(this).front()); |
304 | } |
305 | |
306 | template<class K, class D, class C> inline |
307 | const typename basic_ptree<K, D, C>::value_type & |
308 | basic_ptree<K, D, C>::front() const |
309 | { |
310 | return subs::ch(this).front(); |
311 | } |
312 | |
313 | template<class K, class D, class C> inline |
314 | typename basic_ptree<K, D, C>::value_type & |
315 | basic_ptree<K, D, C>::back() |
316 | { |
317 | return const_cast<value_type&>(subs::ch(this).back()); |
318 | } |
319 | |
320 | template<class K, class D, class C> inline |
321 | const typename basic_ptree<K, D, C>::value_type & |
322 | basic_ptree<K, D, C>::back() const |
323 | { |
324 | return subs::ch(this).back(); |
325 | } |
326 | |
327 | template<class K, class D, class C> inline |
328 | typename basic_ptree<K, D, C>::iterator |
329 | basic_ptree<K, D, C>::insert(iterator where, const value_type &value) |
330 | { |
331 | return iterator(subs::ch(this).insert(where.base(), value).first); |
332 | } |
333 | |
334 | template<class K, class D, class C> |
335 | template<class It> inline |
336 | void basic_ptree<K, D, C>::insert(iterator where, It first, It last) |
337 | { |
338 | subs::ch(this).insert(where.base(), first, last); |
339 | } |
340 | |
341 | template<class K, class D, class C> inline |
342 | typename basic_ptree<K, D, C>::iterator |
343 | basic_ptree<K, D, C>::erase(iterator where) |
344 | { |
345 | return iterator(subs::ch(this).erase(where.base())); |
346 | } |
347 | |
348 | template<class K, class D, class C> inline |
349 | typename basic_ptree<K, D, C>::iterator |
350 | basic_ptree<K, D, C>::erase(iterator first, iterator last) |
351 | { |
352 | return iterator(subs::ch(this).erase(first.base(), last.base())); |
353 | } |
354 | |
355 | template<class K, class D, class C> inline |
356 | typename basic_ptree<K, D, C>::iterator |
357 | basic_ptree<K, D, C>::push_front(const value_type &value) |
358 | { |
359 | return iterator(subs::ch(this).push_front(value).first); |
360 | } |
361 | |
362 | template<class K, class D, class C> inline |
363 | typename basic_ptree<K, D, C>::iterator |
364 | basic_ptree<K, D, C>::push_back(const value_type &value) |
365 | { |
366 | return iterator(subs::ch(this).push_back(value).first); |
367 | } |
368 | |
369 | template<class K, class D, class C> inline |
370 | void basic_ptree<K, D, C>::pop_front() |
371 | { |
372 | subs::ch(this).pop_front(); |
373 | } |
374 | |
375 | template<class K, class D, class C> inline |
376 | void basic_ptree<K, D, C>::pop_back() |
377 | { |
378 | subs::ch(this).pop_back(); |
379 | } |
380 | |
381 | template<class K, class D, class C> inline |
382 | void basic_ptree<K, D, C>::reverse() |
383 | { |
384 | subs::ch(this).reverse(); |
385 | } |
386 | |
387 | namespace impl |
388 | { |
389 | struct by_first |
390 | { |
391 | template <typename P> |
392 | bool operator ()(const P& lhs, const P& rhs) const { |
393 | return lhs.first < rhs.first; |
394 | } |
395 | }; |
396 | |
397 | template <typename C> |
398 | struct equal_pred |
399 | { |
400 | template <typename P> |
401 | bool operator ()(const P& lhs, const P& rhs) const { |
402 | C c; |
403 | return !c(lhs.first, rhs.first) && |
404 | !c(rhs.first, lhs.first) && |
405 | lhs.second == rhs.second; |
406 | } |
407 | }; |
408 | |
409 | template <typename C, typename MI> |
410 | bool equal_children(const MI& ch1, const MI& ch2) { |
411 | // Assumes ch1.size() == ch2.size() |
412 | return std::equal(ch1.begin(), ch1.end(), |
413 | ch2.begin(), equal_pred<C>()); |
414 | } |
415 | } |
416 | |
417 | template<class K, class D, class C> inline |
418 | void basic_ptree<K, D, C>::sort() |
419 | { |
420 | sort(impl::by_first()); |
421 | } |
422 | |
423 | template<class K, class D, class C> |
424 | template<class Compare> inline |
425 | void basic_ptree<K, D, C>::sort(Compare comp) |
426 | { |
427 | subs::ch(this).sort(comp); |
428 | } |
429 | |
430 | // Equality |
431 | |
432 | template<class K, class D, class C> inline |
433 | bool basic_ptree<K, D, C>::operator ==( |
434 | const basic_ptree<K, D, C> &rhs) const |
435 | { |
436 | // The size test is cheap, so add it as an optimization |
437 | return size() == rhs.size() && data() == rhs.data() && |
438 | impl::equal_children<C>(subs::ch(this), subs::ch(&rhs)); |
439 | } |
440 | |
441 | template<class K, class D, class C> inline |
442 | bool basic_ptree<K, D, C>::operator !=( |
443 | const basic_ptree<K, D, C> &rhs) const |
444 | { |
445 | return !(*this == rhs); |
446 | } |
447 | |
448 | // Associative view |
449 | |
450 | template<class K, class D, class C> inline |
451 | typename basic_ptree<K, D, C>::assoc_iterator |
452 | basic_ptree<K, D, C>::ordered_begin() |
453 | { |
454 | return assoc_iterator(subs::assoc(this).begin()); |
455 | } |
456 | |
457 | template<class K, class D, class C> inline |
458 | typename basic_ptree<K, D, C>::const_assoc_iterator |
459 | basic_ptree<K, D, C>::ordered_begin() const |
460 | { |
461 | return const_assoc_iterator(subs::assoc(this).begin()); |
462 | } |
463 | |
464 | template<class K, class D, class C> inline |
465 | typename basic_ptree<K, D, C>::assoc_iterator |
466 | basic_ptree<K, D, C>::not_found() |
467 | { |
468 | return assoc_iterator(subs::assoc(this).end()); |
469 | } |
470 | |
471 | template<class K, class D, class C> inline |
472 | typename basic_ptree<K, D, C>::const_assoc_iterator |
473 | basic_ptree<K, D, C>::not_found() const |
474 | { |
475 | return const_assoc_iterator(subs::assoc(this).end()); |
476 | } |
477 | |
478 | template<class K, class D, class C> inline |
479 | typename basic_ptree<K, D, C>::assoc_iterator |
480 | basic_ptree<K, D, C>::find(const key_type &key) |
481 | { |
482 | return assoc_iterator(subs::assoc(this).find(key)); |
483 | } |
484 | |
485 | template<class K, class D, class C> inline |
486 | typename basic_ptree<K, D, C>::const_assoc_iterator |
487 | basic_ptree<K, D, C>::find(const key_type &key) const |
488 | { |
489 | return const_assoc_iterator(subs::assoc(this).find(key)); |
490 | } |
491 | |
492 | template<class K, class D, class C> inline |
493 | std::pair< |
494 | typename basic_ptree<K, D, C>::assoc_iterator, |
495 | typename basic_ptree<K, D, C>::assoc_iterator |
496 | > basic_ptree<K, D, C>::equal_range(const key_type &key) |
497 | { |
498 | std::pair<typename subs::by_name_index::iterator, |
499 | typename subs::by_name_index::iterator> r( |
500 | subs::assoc(this).equal_range(key)); |
501 | return std::pair<assoc_iterator, assoc_iterator>( |
502 | assoc_iterator(r.first), assoc_iterator(r.second)); |
503 | } |
504 | |
505 | template<class K, class D, class C> inline |
506 | std::pair< |
507 | typename basic_ptree<K, D, C>::const_assoc_iterator, |
508 | typename basic_ptree<K, D, C>::const_assoc_iterator |
509 | > basic_ptree<K, D, C>::equal_range(const key_type &key) const |
510 | { |
511 | std::pair<typename subs::by_name_index::const_iterator, |
512 | typename subs::by_name_index::const_iterator> r( |
513 | subs::assoc(this).equal_range(key)); |
514 | return std::pair<const_assoc_iterator, const_assoc_iterator>( |
515 | const_assoc_iterator(r.first), const_assoc_iterator(r.second)); |
516 | } |
517 | |
518 | template<class K, class D, class C> inline |
519 | typename basic_ptree<K, D, C>::size_type |
520 | basic_ptree<K, D, C>::count(const key_type &key) const |
521 | { |
522 | return subs::assoc(this).count(key); |
523 | } |
524 | |
525 | template<class K, class D, class C> inline |
526 | typename basic_ptree<K, D, C>::size_type |
527 | basic_ptree<K, D, C>::erase(const key_type &key) |
528 | { |
529 | return subs::assoc(this).erase(key); |
530 | } |
531 | |
532 | template<class K, class D, class C> inline |
533 | typename basic_ptree<K, D, C>::iterator |
534 | basic_ptree<K, D, C>::to_iterator(assoc_iterator ai) |
535 | { |
536 | return iterator(subs::ch(this). |
537 | BOOST_NESTED_TEMPLATE project<0>(ai.base())); |
538 | } |
539 | |
540 | template<class K, class D, class C> inline |
541 | typename basic_ptree<K, D, C>::const_iterator |
542 | basic_ptree<K, D, C>::to_iterator(const_assoc_iterator ai) const |
543 | { |
544 | return const_iterator(subs::ch(this). |
545 | BOOST_NESTED_TEMPLATE project<0>(ai.base())); |
546 | } |
547 | |
548 | // Property tree view |
549 | |
550 | template<class K, class D, class C> inline |
551 | typename basic_ptree<K, D, C>::data_type & |
552 | basic_ptree<K, D, C>::data() |
553 | { |
554 | return m_data; |
555 | } |
556 | |
557 | template<class K, class D, class C> inline |
558 | const typename basic_ptree<K, D, C>::data_type & |
559 | basic_ptree<K, D, C>::data() const |
560 | { |
561 | return m_data; |
562 | } |
563 | |
564 | template<class K, class D, class C> inline |
565 | void basic_ptree<K, D, C>::clear() |
566 | { |
567 | m_data = data_type(); |
568 | subs::ch(this).clear(); |
569 | } |
570 | |
571 | template<class K, class D, class C> |
572 | basic_ptree<K, D, C> & |
573 | basic_ptree<K, D, C>::get_child(const path_type &path) |
574 | { |
575 | path_type p(path); |
576 | self_type *n = walk_path(p); |
577 | if (!n) { |
578 | BOOST_PROPERTY_TREE_THROW(ptree_bad_path("No such node" , path)); |
579 | } |
580 | return *n; |
581 | } |
582 | |
583 | template<class K, class D, class C> inline |
584 | const basic_ptree<K, D, C> & |
585 | basic_ptree<K, D, C>::get_child(const path_type &path) const |
586 | { |
587 | return const_cast<self_type*>(this)->get_child(path); |
588 | } |
589 | |
590 | template<class K, class D, class C> inline |
591 | basic_ptree<K, D, C> & |
592 | basic_ptree<K, D, C>::get_child(const path_type &path, |
593 | self_type &default_value) |
594 | { |
595 | path_type p(path); |
596 | self_type *n = walk_path(p); |
597 | return n ? *n : default_value; |
598 | } |
599 | |
600 | template<class K, class D, class C> inline |
601 | const basic_ptree<K, D, C> & |
602 | basic_ptree<K, D, C>::get_child(const path_type &path, |
603 | const self_type &default_value) const |
604 | { |
605 | return const_cast<self_type*>(this)->get_child(path, |
606 | const_cast<self_type&>(default_value)); |
607 | } |
608 | |
609 | |
610 | template<class K, class D, class C> |
611 | optional<basic_ptree<K, D, C> &> |
612 | basic_ptree<K, D, C>::get_child_optional(const path_type &path) |
613 | { |
614 | path_type p(path); |
615 | self_type *n = walk_path(p); |
616 | if (!n) { |
617 | return optional<self_type&>(); |
618 | } |
619 | return *n; |
620 | } |
621 | |
622 | template<class K, class D, class C> |
623 | optional<const basic_ptree<K, D, C> &> |
624 | basic_ptree<K, D, C>::get_child_optional(const path_type &path) const |
625 | { |
626 | path_type p(path); |
627 | self_type *n = walk_path(p); |
628 | if (!n) { |
629 | return optional<const self_type&>(); |
630 | } |
631 | return *n; |
632 | } |
633 | |
634 | template<class K, class D, class C> |
635 | basic_ptree<K, D, C> & |
636 | basic_ptree<K, D, C>::put_child(const path_type &path, |
637 | const self_type &value) |
638 | { |
639 | path_type p(path); |
640 | self_type &parent = force_path(p); |
641 | // Got the parent. Now get the correct child. |
642 | key_type fragment = p.reduce(); |
643 | assoc_iterator el = parent.find(fragment); |
644 | // If the new child exists, replace it. |
645 | if(el != parent.not_found()) { |
646 | return el->second = value; |
647 | } else { |
648 | return parent.push_back(value_type(fragment, value))->second; |
649 | } |
650 | } |
651 | |
652 | template<class K, class D, class C> |
653 | basic_ptree<K, D, C> & |
654 | basic_ptree<K, D, C>::add_child(const path_type &path, |
655 | const self_type &value) |
656 | { |
657 | path_type p(path); |
658 | self_type &parent = force_path(p); |
659 | // Got the parent. |
660 | key_type fragment = p.reduce(); |
661 | return parent.push_back(value_type(fragment, value))->second; |
662 | } |
663 | |
664 | template<class K, class D, class C> |
665 | template<class Type, class Translator> |
666 | typename boost::enable_if<detail::is_translator<Translator>, Type>::type |
667 | basic_ptree<K, D, C>::get_value(Translator tr) const |
668 | { |
669 | if(boost::optional<Type> o = get_value_optional<Type>(tr)) { |
670 | return *o; |
671 | } |
672 | BOOST_PROPERTY_TREE_THROW(ptree_bad_data( |
673 | std::string("conversion of data to type \"" ) + |
674 | boost::core::type_name<Type>() + "\" failed" , data())); |
675 | } |
676 | |
677 | template<class K, class D, class C> |
678 | template<class Type> inline |
679 | Type basic_ptree<K, D, C>::get_value() const |
680 | { |
681 | return get_value<Type>( |
682 | typename translator_between<data_type, Type>::type()); |
683 | } |
684 | |
685 | template<class K, class D, class C> |
686 | template<class Type, class Translator> inline |
687 | Type basic_ptree<K, D, C>::get_value(const Type &default_value, |
688 | Translator tr) const |
689 | { |
690 | return get_value_optional<Type>(tr).get_value_or(default_value); |
691 | } |
692 | |
693 | template<class K, class D, class C> |
694 | template <class Ch, class Translator> |
695 | typename boost::enable_if< |
696 | detail::is_character<Ch>, |
697 | std::basic_string<Ch> |
698 | >::type |
699 | basic_ptree<K, D, C>::get_value(const Ch *default_value, Translator tr)const |
700 | { |
701 | return get_value<std::basic_string<Ch>, Translator>(default_value, tr); |
702 | } |
703 | |
704 | template<class K, class D, class C> |
705 | template<class Type> inline |
706 | typename boost::disable_if<detail::is_translator<Type>, Type>::type |
707 | basic_ptree<K, D, C>::get_value(const Type &default_value) const |
708 | { |
709 | return get_value(default_value, |
710 | typename translator_between<data_type, Type>::type()); |
711 | } |
712 | |
713 | template<class K, class D, class C> |
714 | template <class Ch> |
715 | typename boost::enable_if< |
716 | detail::is_character<Ch>, |
717 | std::basic_string<Ch> |
718 | >::type |
719 | basic_ptree<K, D, C>::get_value(const Ch *default_value) const |
720 | { |
721 | return get_value< std::basic_string<Ch> >(default_value); |
722 | } |
723 | |
724 | template<class K, class D, class C> |
725 | template<class Type, class Translator> inline |
726 | optional<Type> basic_ptree<K, D, C>::get_value_optional( |
727 | Translator tr) const |
728 | { |
729 | return tr.get_value(data()); |
730 | } |
731 | |
732 | template<class K, class D, class C> |
733 | template<class Type> inline |
734 | optional<Type> basic_ptree<K, D, C>::get_value_optional() const |
735 | { |
736 | return get_value_optional<Type>( |
737 | typename translator_between<data_type, Type>::type()); |
738 | } |
739 | |
740 | template<class K, class D, class C> |
741 | template<class Type, class Translator> inline |
742 | typename boost::enable_if<detail::is_translator<Translator>, Type>::type |
743 | basic_ptree<K, D, C>::get(const path_type &path, |
744 | Translator tr) const |
745 | { |
746 | return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>(tr); |
747 | } |
748 | |
749 | template<class K, class D, class C> |
750 | template<class Type> inline |
751 | Type basic_ptree<K, D, C>::get(const path_type &path) const |
752 | { |
753 | return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>(); |
754 | } |
755 | |
756 | template<class K, class D, class C> |
757 | template<class Type, class Translator> inline |
758 | Type basic_ptree<K, D, C>::get(const path_type &path, |
759 | const Type &default_value, |
760 | Translator tr) const |
761 | { |
762 | return get_optional<Type>(path, tr).get_value_or(default_value); |
763 | } |
764 | |
765 | template<class K, class D, class C> |
766 | template <class Ch, class Translator> |
767 | typename boost::enable_if< |
768 | detail::is_character<Ch>, |
769 | std::basic_string<Ch> |
770 | >::type |
771 | basic_ptree<K, D, C>::get( |
772 | const path_type &path, const Ch *default_value, Translator tr) const |
773 | { |
774 | return get<std::basic_string<Ch>, Translator>(path, default_value, tr); |
775 | } |
776 | |
777 | template<class K, class D, class C> |
778 | template<class Type> inline |
779 | typename boost::disable_if<detail::is_translator<Type>, Type>::type |
780 | basic_ptree<K, D, C>::get(const path_type &path, |
781 | const Type &default_value) const |
782 | { |
783 | return get_optional<Type>(path).get_value_or(default_value); |
784 | } |
785 | |
786 | template<class K, class D, class C> |
787 | template <class Ch> |
788 | typename boost::enable_if< |
789 | detail::is_character<Ch>, |
790 | std::basic_string<Ch> |
791 | >::type |
792 | basic_ptree<K, D, C>::get( |
793 | const path_type &path, const Ch *default_value) const |
794 | { |
795 | return get< std::basic_string<Ch> >(path, default_value); |
796 | } |
797 | |
798 | template<class K, class D, class C> |
799 | template<class Type, class Translator> |
800 | optional<Type> basic_ptree<K, D, C>::get_optional(const path_type &path, |
801 | Translator tr) const |
802 | { |
803 | if (optional<const self_type&> child = get_child_optional(path)) |
804 | return child.get(). |
805 | BOOST_NESTED_TEMPLATE get_value_optional<Type>(tr); |
806 | else |
807 | return optional<Type>(); |
808 | } |
809 | |
810 | template<class K, class D, class C> |
811 | template<class Type> |
812 | optional<Type> basic_ptree<K, D, C>::get_optional( |
813 | const path_type &path) const |
814 | { |
815 | if (optional<const self_type&> child = get_child_optional(path)) |
816 | return child.get().BOOST_NESTED_TEMPLATE get_value_optional<Type>(); |
817 | else |
818 | return optional<Type>(); |
819 | } |
820 | |
821 | template<class K, class D, class C> |
822 | template<class Type, class Translator> |
823 | void basic_ptree<K, D, C>::put_value(const Type &value, Translator tr) |
824 | { |
825 | if(optional<data_type> o = tr.put_value(value)) { |
826 | data() = *o; |
827 | } else { |
828 | BOOST_PROPERTY_TREE_THROW(ptree_bad_data( |
829 | std::string("conversion of type \"" ) + boost::core::type_name<Type>() + |
830 | "\" to data failed" , boost::any())); |
831 | } |
832 | } |
833 | |
834 | template<class K, class D, class C> |
835 | template<class Type> inline |
836 | void basic_ptree<K, D, C>::put_value(const Type &value) |
837 | { |
838 | put_value(value, typename translator_between<data_type, Type>::type()); |
839 | } |
840 | |
841 | template<class K, class D, class C> |
842 | template<class Type, typename Translator> |
843 | basic_ptree<K, D, C> & basic_ptree<K, D, C>::put( |
844 | const path_type &path, const Type &value, Translator tr) |
845 | { |
846 | if(optional<self_type &> child = get_child_optional(path)) { |
847 | child.get().put_value(value, tr); |
848 | return *child; |
849 | } else { |
850 | self_type &child2 = put_child(path, value: self_type()); |
851 | child2.put_value(value, tr); |
852 | return child2; |
853 | } |
854 | } |
855 | |
856 | template<class K, class D, class C> |
857 | template<class Type> inline |
858 | basic_ptree<K, D, C> & basic_ptree<K, D, C>::put( |
859 | const path_type &path, const Type &value) |
860 | { |
861 | return put(path, value, |
862 | typename translator_between<data_type, Type>::type()); |
863 | } |
864 | |
865 | template<class K, class D, class C> |
866 | template<class Type, typename Translator> inline |
867 | basic_ptree<K, D, C> & basic_ptree<K, D, C>::add( |
868 | const path_type &path, const Type &value, Translator tr) |
869 | { |
870 | self_type &child = add_child(path, value: self_type()); |
871 | child.put_value(value, tr); |
872 | return child; |
873 | } |
874 | |
875 | template<class K, class D, class C> |
876 | template<class Type> inline |
877 | basic_ptree<K, D, C> & basic_ptree<K, D, C>::add( |
878 | const path_type &path, const Type &value) |
879 | { |
880 | return add(path, value, |
881 | typename translator_between<data_type, Type>::type()); |
882 | } |
883 | |
884 | |
885 | template<class K, class D, class C> |
886 | basic_ptree<K, D, C> * |
887 | basic_ptree<K, D, C>::walk_path(path_type &p) const |
888 | { |
889 | if(p.empty()) { |
890 | // I'm the child we're looking for. |
891 | return const_cast<basic_ptree*>(this); |
892 | } |
893 | // Recurse down the tree to find the path. |
894 | key_type fragment = p.reduce(); |
895 | const_assoc_iterator el = find(fragment); |
896 | if(el == not_found()) { |
897 | // No such child. |
898 | return 0; |
899 | } |
900 | // Not done yet, recurse. |
901 | return el->second.walk_path(p); |
902 | } |
903 | |
904 | template<class K, class D, class C> |
905 | basic_ptree<K, D, C> & basic_ptree<K, D, C>::force_path(path_type &p) |
906 | { |
907 | BOOST_ASSERT(!p.empty() && "Empty path not allowed for put_child." ); |
908 | if(p.single()) { |
909 | // I'm the parent we're looking for. |
910 | return *this; |
911 | } |
912 | key_type fragment = p.reduce(); |
913 | assoc_iterator el = find(fragment); |
914 | // If we've found an existing child, go down that path. Else |
915 | // create a new one. |
916 | self_type& child = el == not_found() ? |
917 | push_back(value: value_type(fragment, self_type()))->second : el->second; |
918 | return child.force_path(p); |
919 | } |
920 | |
921 | // Free functions |
922 | |
923 | template<class K, class D, class C> |
924 | inline void swap(basic_ptree<K, D, C> &pt1, basic_ptree<K, D, C> &pt2) |
925 | { |
926 | pt1.swap(pt2); |
927 | } |
928 | |
929 | } } |
930 | |
931 | #if defined(BOOST_PROPERTY_TREE_PAIR_BUG) |
932 | #undef BOOST_PROPERTY_TREE_PAIR_BUG |
933 | #endif |
934 | |
935 | #endif |
936 | |