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