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