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/iterator/iterator_adaptor.hpp>
15 #include <boost/iterator/reverse_iterator.hpp>
16 #include <boost/assert.hpp>
17 #include <memory>
18 
19 #if defined(BOOST_MSVC) && \
20     (_MSC_FULL_VER >= 160000000 && _MSC_FULL_VER < 170000000)
21 #define BOOST_PROPERTY_TREE_PAIR_BUG
22 #endif
23 
24 namespace boost { namespace property_tree
25 {
26     template <class K, class D, class C>
27     struct basic_ptree<K, D, C>::subs
28     {
29         struct by_name {};
30         // The actual child container.
31 #if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
32         // MSVC 10 has moved std::pair's members to a base
33         // class. Unfortunately this does break the interface.
34         BOOST_STATIC_CONSTANT(unsigned,
35             first_offset = offsetof(value_type, first));
36         typedef multi_index_container<value_type,
37             multi_index::indexed_by<
38                 multi_index::sequenced<>,
39                 multi_index::ordered_non_unique<multi_index::tag<by_name>,
40                     multi_index::member_offset<value_type, const key_type,
41                                         first_offset>,
42                     key_compare
43                 >
44             >
45         > base_container;
46 #else
47         typedef multi_index_container<value_type,
48             multi_index::indexed_by<
49                 multi_index::sequenced<>,
50                 multi_index::ordered_non_unique<multi_index::tag<by_name>,
51                     multi_index::member<value_type, const key_type,
52                                         &value_type::first>,
53                     key_compare
54                 >
55             >
56         > base_container;
57 #endif
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.
chboost::property_tree::basic_ptree::subs63         static base_container& ch(self_type *s) {
64             return *static_cast<base_container*>(s->m_children);
65         }
chboost::property_tree::basic_ptree::subs66         static const base_container& ch(const self_type *s) {
67             return *static_cast<const base_container*>(s->m_children);
68         }
assocboost::property_tree::basic_ptree::subs69         static by_name_index& assoc(self_type *s) {
70             return ch(s).BOOST_NESTED_TEMPLATE get<by_name>();
71         }
assocboost::property_tree::basic_ptree::subs72         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;
iterator()86         iterator() {}
iterator(typename iterator::base_type b)87         explicit iterator(typename iterator::base_type b)
88             : iterator::iterator_adaptor_(b)
89         {}
dereference() const90         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:
const_iterator()104         const_iterator() {}
const_iterator(typename const_iterator::base_type b)105         explicit const_iterator(typename const_iterator::base_type b)
106             : const_iterator::iterator_adaptor_(b)
107         {}
const_iterator(iterator b)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:
reverse_iterator()117         reverse_iterator() {}
reverse_iterator(iterator b)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:
const_reverse_iterator()127         const_reverse_iterator() {}
const_reverse_iterator(const_iterator b)128         explicit const_reverse_iterator(const_iterator b)
129             : boost::reverse_iterator<const_iterator>(b)
130         {}
const_reverse_iterator(typename basic_ptree<K,D,C>::reverse_iterator b)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;
assoc_iterator()149         assoc_iterator() {}
assoc_iterator(typename assoc_iterator::base_type b)150         explicit assoc_iterator(typename assoc_iterator::base_type b)
151             : assoc_iterator::iterator_adaptor_(b)
152         {}
dereference() const153         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:
const_assoc_iterator()164         const_assoc_iterator() {}
const_assoc_iterator(typename const_assoc_iterator::base_type b)165         explicit const_assoc_iterator(
166             typename const_assoc_iterator::base_type b)
167             : const_assoc_iterator::iterator_adaptor_(b)
168         {}
const_assoc_iterator(assoc_iterator b)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
basic_ptree()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
basic_ptree(const data_type & d)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
basic_ptree(const basic_ptree<K,D,C> & rhs)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> &
operator =(const basic_ptree<K,D,C> & rhs)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>
~basic_ptree()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
swap(basic_ptree<K,D,C> & rhs)214     void basic_ptree<K, D, C>::swap(basic_ptree<K, D, C> &rhs)
215     {
216         m_data.swap(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
size() const225         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
max_size() const232         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
empty() const238     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
begin()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
begin() const252         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
end()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
end() const266         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
rbegin()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
rbegin() const280         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
rend()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
rend() const294         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 &
front()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 &
front() const308         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 &
back()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 &
back() const322         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
insert(iterator where,const value_type & value)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
insert(iterator where,It first,It last)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
erase(iterator where)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
erase(iterator first,iterator last)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
push_front(const value_type & value)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
push_back(const value_type & value)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
pop_front()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
pop_back()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
reverse()382     void basic_ptree<K, D, C>::reverse()
383     {
384         subs::ch(this).reverse();
385     }
386 
387     template<class K, class D, class C> inline
sort()388     void basic_ptree<K, D, C>::sort()
389     {
390         subs::ch(this).sort();
391     }
392 
393     template<class K, class D, class C>
394     template<class Compare> inline
sort(Compare comp)395     void basic_ptree<K, D, C>::sort(Compare comp)
396     {
397         subs::ch(this).sort(comp);
398     }
399 
400     // Equality
401 
402     template<class K, class D, class C> inline
operator ==(const basic_ptree<K,D,C> & rhs) const403     bool basic_ptree<K, D, C>::operator ==(
404                                   const basic_ptree<K, D, C> &rhs) const
405     {
406         // The size test is cheap, so add it as an optimization
407         return size() == rhs.size() && data() == rhs.data() &&
408             subs::ch(this) == subs::ch(&rhs);
409     }
410 
411     template<class K, class D, class C> inline
operator !=(const basic_ptree<K,D,C> & rhs) const412     bool basic_ptree<K, D, C>::operator !=(
413                                   const basic_ptree<K, D, C> &rhs) const
414     {
415         return !(*this == rhs);
416     }
417 
418     // Associative view
419 
420     template<class K, class D, class C> inline
421     typename basic_ptree<K, D, C>::assoc_iterator
ordered_begin()422         basic_ptree<K, D, C>::ordered_begin()
423     {
424         return assoc_iterator(subs::assoc(this).begin());
425     }
426 
427     template<class K, class D, class C> inline
428     typename basic_ptree<K, D, C>::const_assoc_iterator
ordered_begin() const429         basic_ptree<K, D, C>::ordered_begin() const
430     {
431         return const_assoc_iterator(subs::assoc(this).begin());
432     }
433 
434     template<class K, class D, class C> inline
435     typename basic_ptree<K, D, C>::assoc_iterator
not_found()436         basic_ptree<K, D, C>::not_found()
437     {
438         return assoc_iterator(subs::assoc(this).end());
439     }
440 
441     template<class K, class D, class C> inline
442     typename basic_ptree<K, D, C>::const_assoc_iterator
not_found() const443         basic_ptree<K, D, C>::not_found() const
444     {
445         return const_assoc_iterator(subs::assoc(this).end());
446     }
447 
448     template<class K, class D, class C> inline
449     typename basic_ptree<K, D, C>::assoc_iterator
find(const key_type & key)450         basic_ptree<K, D, C>::find(const key_type &key)
451     {
452         return assoc_iterator(subs::assoc(this).find(key));
453     }
454 
455     template<class K, class D, class C> inline
456     typename basic_ptree<K, D, C>::const_assoc_iterator
find(const key_type & key) const457         basic_ptree<K, D, C>::find(const key_type &key) const
458     {
459         return const_assoc_iterator(subs::assoc(this).find(key));
460     }
461 
462     template<class K, class D, class C> inline
463     std::pair<
464         typename basic_ptree<K, D, C>::assoc_iterator,
465         typename basic_ptree<K, D, C>::assoc_iterator
equal_range(const key_type & key)466     > basic_ptree<K, D, C>::equal_range(const key_type &key)
467     {
468         std::pair<typename subs::by_name_index::iterator,
469                   typename subs::by_name_index::iterator> r(
470             subs::assoc(this).equal_range(key));
471         return std::pair<assoc_iterator, assoc_iterator>(
472           assoc_iterator(r.first), assoc_iterator(r.second));
473     }
474 
475     template<class K, class D, class C> inline
476     std::pair<
477         typename basic_ptree<K, D, C>::const_assoc_iterator,
478         typename basic_ptree<K, D, C>::const_assoc_iterator
equal_range(const key_type & key) const479     > basic_ptree<K, D, C>::equal_range(const key_type &key) const
480     {
481         std::pair<typename subs::by_name_index::const_iterator,
482                   typename subs::by_name_index::const_iterator> r(
483             subs::assoc(this).equal_range(key));
484         return std::pair<const_assoc_iterator, const_assoc_iterator>(
485             const_assoc_iterator(r.first), const_assoc_iterator(r.second));
486     }
487 
488     template<class K, class D, class C> inline
489     typename basic_ptree<K, D, C>::size_type
count(const key_type & key) const490         basic_ptree<K, D, C>::count(const key_type &key) const
491     {
492         return subs::assoc(this).count(key);
493     }
494 
495     template<class K, class D, class C> inline
496     typename basic_ptree<K, D, C>::size_type
erase(const key_type & key)497         basic_ptree<K, D, C>::erase(const key_type &key)
498     {
499         return subs::assoc(this).erase(key);
500     }
501 
502     template<class K, class D, class C> inline
503     typename basic_ptree<K, D, C>::iterator
to_iterator(assoc_iterator ai)504         basic_ptree<K, D, C>::to_iterator(assoc_iterator ai)
505     {
506         return iterator(subs::ch(this).
507             BOOST_NESTED_TEMPLATE project<0>(ai.base()));
508     }
509 
510     template<class K, class D, class C> inline
511     typename basic_ptree<K, D, C>::const_iterator
to_iterator(const_assoc_iterator ai) const512         basic_ptree<K, D, C>::to_iterator(const_assoc_iterator ai) const
513     {
514         return const_iterator(subs::ch(this).
515             BOOST_NESTED_TEMPLATE project<0>(ai.base()));
516     }
517 
518     // Property tree view
519 
520     template<class K, class D, class C> inline
521     typename basic_ptree<K, D, C>::data_type &
data()522         basic_ptree<K, D, C>::data()
523     {
524         return m_data;
525     }
526 
527     template<class K, class D, class C> inline
528     const typename basic_ptree<K, D, C>::data_type &
data() const529         basic_ptree<K, D, C>::data() const
530     {
531         return m_data;
532     }
533 
534     template<class K, class D, class C> inline
clear()535     void basic_ptree<K, D, C>::clear()
536     {
537         m_data = data_type();
538         subs::ch(this).clear();
539     }
540 
541     template<class K, class D, class C>
542     basic_ptree<K, D, C> &
get_child(const path_type & path)543         basic_ptree<K, D, C>::get_child(const path_type &path)
544     {
545         path_type p(path);
546         self_type *n = walk_path(p);
547         if (!n) {
548             BOOST_PROPERTY_TREE_THROW(ptree_bad_path("No such node", path));
549         }
550         return *n;
551     }
552 
553     template<class K, class D, class C> inline
554     const basic_ptree<K, D, C> &
get_child(const path_type & path) const555         basic_ptree<K, D, C>::get_child(const path_type &path) const
556     {
557         return const_cast<self_type*>(this)->get_child(path);
558     }
559 
560     template<class K, class D, class C> inline
561     basic_ptree<K, D, C> &
get_child(const path_type & path,self_type & default_value)562         basic_ptree<K, D, C>::get_child(const path_type &path,
563                                         self_type &default_value)
564     {
565         path_type p(path);
566         self_type *n = walk_path(p);
567         return n ? *n : default_value;
568     }
569 
570     template<class K, class D, class C> inline
571     const basic_ptree<K, D, C> &
get_child(const path_type & path,const self_type & default_value) const572         basic_ptree<K, D, C>::get_child(const path_type &path,
573                                         const self_type &default_value) const
574     {
575         return const_cast<self_type*>(this)->get_child(path,
576             const_cast<self_type&>(default_value));
577     }
578 
579 
580     template<class K, class D, class C>
581     optional<basic_ptree<K, D, C> &>
get_child_optional(const path_type & path)582         basic_ptree<K, D, C>::get_child_optional(const path_type &path)
583     {
584         path_type p(path);
585         self_type *n = walk_path(p);
586         if (!n) {
587             return optional<self_type&>();
588         }
589         return *n;
590     }
591 
592     template<class K, class D, class C>
593     optional<const basic_ptree<K, D, C> &>
get_child_optional(const path_type & path) const594         basic_ptree<K, D, C>::get_child_optional(const path_type &path) const
595     {
596         path_type p(path);
597         self_type *n = walk_path(p);
598         if (!n) {
599             return optional<const self_type&>();
600         }
601         return *n;
602     }
603 
604     template<class K, class D, class C>
605     basic_ptree<K, D, C> &
put_child(const path_type & path,const self_type & value)606         basic_ptree<K, D, C>::put_child(const path_type &path,
607                                         const self_type &value)
608     {
609         path_type p(path);
610         self_type &parent = force_path(p);
611         // Got the parent. Now get the correct child.
612         key_type fragment = p.reduce();
613         assoc_iterator el = parent.find(fragment);
614         // If the new child exists, replace it.
615         if(el != parent.not_found()) {
616             return el->second = value;
617         } else {
618             return parent.push_back(value_type(fragment, value))->second;
619         }
620     }
621 
622     template<class K, class D, class C>
623     basic_ptree<K, D, C> &
add_child(const path_type & path,const self_type & value)624         basic_ptree<K, D, C>::add_child(const path_type &path,
625                                         const self_type &value)
626     {
627         path_type p(path);
628         self_type &parent = force_path(p);
629         // Got the parent.
630         key_type fragment = p.reduce();
631         return parent.push_back(value_type(fragment, value))->second;
632     }
633 
634     template<class K, class D, class C>
635     template<class Type, class Translator>
636     typename boost::enable_if<detail::is_translator<Translator>, Type>::type
get_value(Translator tr) const637     basic_ptree<K, D, C>::get_value(Translator tr) const
638     {
639         if(boost::optional<Type> o = get_value_optional<Type>(tr)) {
640             return *o;
641         }
642         BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
643             std::string("conversion of data to type \"") +
644             typeid(Type).name() + "\" failed", data()));
645     }
646 
647     template<class K, class D, class C>
648     template<class Type> inline
get_value() const649     Type basic_ptree<K, D, C>::get_value() const
650     {
651         return get_value<Type>(
652             typename translator_between<data_type, Type>::type());
653     }
654 
655     template<class K, class D, class C>
656     template<class Type, class Translator> inline
get_value(const Type & default_value,Translator tr) const657     Type basic_ptree<K, D, C>::get_value(const Type &default_value,
658                                          Translator tr) const
659     {
660         return get_value_optional<Type>(tr).get_value_or(default_value);
661     }
662 
663     template<class K, class D, class C>
664     template <class Ch, class Translator>
665     typename boost::enable_if<
666         detail::is_character<Ch>,
667         std::basic_string<Ch>
668     >::type
get_value(const Ch * default_value,Translator tr) const669     basic_ptree<K, D, C>::get_value(const Ch *default_value, Translator tr)const
670     {
671         return get_value<std::basic_string<Ch>, Translator>(default_value, tr);
672     }
673 
674     template<class K, class D, class C>
675     template<class Type> inline
676     typename boost::disable_if<detail::is_translator<Type>, Type>::type
get_value(const Type & default_value) const677     basic_ptree<K, D, C>::get_value(const Type &default_value) const
678     {
679         return get_value(default_value,
680                          typename translator_between<data_type, Type>::type());
681     }
682 
683     template<class K, class D, class C>
684     template <class Ch>
685     typename boost::enable_if<
686         detail::is_character<Ch>,
687         std::basic_string<Ch>
688     >::type
get_value(const Ch * default_value) const689     basic_ptree<K, D, C>::get_value(const Ch *default_value) const
690     {
691         return get_value< std::basic_string<Ch> >(default_value);
692     }
693 
694     template<class K, class D, class C>
695     template<class Type, class Translator> inline
get_value_optional(Translator tr) const696     optional<Type> basic_ptree<K, D, C>::get_value_optional(
697                                                 Translator tr) const
698     {
699         return tr.get_value(data());
700     }
701 
702     template<class K, class D, class C>
703     template<class Type> inline
get_value_optional() const704     optional<Type> basic_ptree<K, D, C>::get_value_optional() const
705     {
706         return get_value_optional<Type>(
707             typename translator_between<data_type, Type>::type());
708     }
709 
710     template<class K, class D, class C>
711     template<class Type, class Translator> inline
712     typename boost::enable_if<detail::is_translator<Translator>, Type>::type
get(const path_type & path,Translator tr) const713     basic_ptree<K, D, C>::get(const path_type &path,
714                               Translator tr) const
715     {
716         return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>(tr);
717     }
718 
719     template<class K, class D, class C>
720     template<class Type> inline
get(const path_type & path) const721     Type basic_ptree<K, D, C>::get(const path_type &path) const
722     {
723         return get_child(path).BOOST_NESTED_TEMPLATE get_value<Type>();
724     }
725 
726     template<class K, class D, class C>
727     template<class Type, class Translator> inline
get(const path_type & path,const Type & default_value,Translator tr) const728     Type basic_ptree<K, D, C>::get(const path_type &path,
729                                    const Type &default_value,
730                                    Translator tr) const
731     {
732         return get_optional<Type>(path, tr).get_value_or(default_value);
733     }
734 
735     template<class K, class D, class C>
736     template <class Ch, class Translator>
737     typename boost::enable_if<
738         detail::is_character<Ch>,
739         std::basic_string<Ch>
740     >::type
get(const path_type & path,const Ch * default_value,Translator tr) const741     basic_ptree<K, D, C>::get(
742         const path_type &path, const Ch *default_value, Translator tr) const
743     {
744         return get<std::basic_string<Ch>, Translator>(path, default_value, tr);
745     }
746 
747     template<class K, class D, class C>
748     template<class Type> inline
749     typename boost::disable_if<detail::is_translator<Type>, Type>::type
get(const path_type & path,const Type & default_value) const750     basic_ptree<K, D, C>::get(const path_type &path,
751                               const Type &default_value) const
752     {
753         return get_optional<Type>(path).get_value_or(default_value);
754     }
755 
756     template<class K, class D, class C>
757     template <class Ch>
758     typename boost::enable_if<
759         detail::is_character<Ch>,
760         std::basic_string<Ch>
761     >::type
get(const path_type & path,const Ch * default_value) const762     basic_ptree<K, D, C>::get(
763         const path_type &path, const Ch *default_value) const
764     {
765         return get< std::basic_string<Ch> >(path, default_value);
766     }
767 
768     template<class K, class D, class C>
769     template<class Type, class Translator>
get_optional(const path_type & path,Translator tr) const770     optional<Type> basic_ptree<K, D, C>::get_optional(const path_type &path,
771                                                          Translator tr) const
772     {
773         if (optional<const self_type&> child = get_child_optional(path))
774             return child.get().
775                 BOOST_NESTED_TEMPLATE get_value_optional<Type>(tr);
776         else
777             return optional<Type>();
778     }
779 
780     template<class K, class D, class C>
781     template<class Type>
get_optional(const path_type & path) const782     optional<Type> basic_ptree<K, D, C>::get_optional(
783                                                 const path_type &path) const
784     {
785         if (optional<const self_type&> child = get_child_optional(path))
786             return child.get().BOOST_NESTED_TEMPLATE get_value_optional<Type>();
787         else
788             return optional<Type>();
789     }
790 
791     template<class K, class D, class C>
792     template<class Type, class Translator>
put_value(const Type & value,Translator tr)793     void basic_ptree<K, D, C>::put_value(const Type &value, Translator tr)
794     {
795         if(optional<data_type> o = tr.put_value(value)) {
796             data() = *o;
797         } else {
798             BOOST_PROPERTY_TREE_THROW(ptree_bad_data(
799                 std::string("conversion of type \"") + typeid(Type).name() +
800                 "\" to data failed", boost::any()));
801         }
802     }
803 
804     template<class K, class D, class C>
805     template<class Type> inline
put_value(const Type & value)806     void basic_ptree<K, D, C>::put_value(const Type &value)
807     {
808         put_value(value, typename translator_between<data_type, Type>::type());
809     }
810 
811     template<class K, class D, class C>
812     template<class Type, typename Translator>
put(const path_type & path,const Type & value,Translator tr)813     basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
814         const path_type &path, const Type &value, Translator tr)
815     {
816         if(optional<self_type &> child = get_child_optional(path)) {
817             child.get().put_value(value, tr);
818             return *child;
819         } else {
820             self_type &child2 = put_child(path, self_type());
821             child2.put_value(value, tr);
822             return child2;
823         }
824     }
825 
826     template<class K, class D, class C>
827     template<class Type> inline
put(const path_type & path,const Type & value)828     basic_ptree<K, D, C> & basic_ptree<K, D, C>::put(
829         const path_type &path, const Type &value)
830     {
831         return put(path, value,
832                    typename translator_between<data_type, Type>::type());
833     }
834 
835     template<class K, class D, class C>
836     template<class Type, typename Translator> inline
add(const path_type & path,const Type & value,Translator tr)837     basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
838         const path_type &path, const Type &value, Translator tr)
839     {
840         self_type &child = add_child(path, self_type());
841         child.put_value(value, tr);
842         return child;
843     }
844 
845     template<class K, class D, class C>
846     template<class Type> inline
add(const path_type & path,const Type & value)847     basic_ptree<K, D, C> & basic_ptree<K, D, C>::add(
848         const path_type &path, const Type &value)
849     {
850         return add(path, value,
851                    typename translator_between<data_type, Type>::type());
852     }
853 
854 
855     template<class K, class D, class C>
856     basic_ptree<K, D, C> *
walk_path(path_type & p) const857     basic_ptree<K, D, C>::walk_path(path_type &p) const
858     {
859         if(p.empty()) {
860             // I'm the child we're looking for.
861             return const_cast<basic_ptree*>(this);
862         }
863         // Recurse down the tree to find the path.
864         key_type fragment = p.reduce();
865         const_assoc_iterator el = find(fragment);
866         if(el == not_found()) {
867             // No such child.
868             return 0;
869         }
870         // Not done yet, recurse.
871         return el->second.walk_path(p);
872     }
873 
874     template<class K, class D, class C>
force_path(path_type & p)875     basic_ptree<K, D, C> & basic_ptree<K, D, C>::force_path(path_type &p)
876     {
877         BOOST_ASSERT(!p.empty() && "Empty path not allowed for put_child.");
878         if(p.single()) {
879             // I'm the parent we're looking for.
880             return *this;
881         }
882         key_type fragment = p.reduce();
883         assoc_iterator el = find(fragment);
884         // If we've found an existing child, go down that path. Else
885         // create a new one.
886         self_type& child = el == not_found() ?
887             push_back(value_type(fragment, self_type()))->second : el->second;
888         return child.force_path(p);
889     }
890 
891     // Free functions
892 
893     template<class K, class D, class C>
swap(basic_ptree<K,D,C> & pt1,basic_ptree<K,D,C> & pt2)894     inline void swap(basic_ptree<K, D, C> &pt1, basic_ptree<K, D, C> &pt2)
895     {
896         pt1.swap(pt2);
897     }
898 
899 } }
900 
901 #if defined(BOOST_PROPERTY_TREE_PAIR_BUG)
902 #undef BOOST_PROPERTY_TREE_PAIR_BUG
903 #endif
904 
905 #endif
906