xref: /freebsd/contrib/kyua/utils/config/nodes.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davis // Copyright 2012 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/config/nodes.ipp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis #include <memory>
32*b0d29bc4SBrooks Davis 
33*b0d29bc4SBrooks Davis #include <lutok/state.ipp>
34*b0d29bc4SBrooks Davis 
35*b0d29bc4SBrooks Davis #include "utils/config/exceptions.hpp"
36*b0d29bc4SBrooks Davis #include "utils/config/keys.hpp"
37*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
38*b0d29bc4SBrooks Davis 
39*b0d29bc4SBrooks Davis namespace config = utils::config;
40*b0d29bc4SBrooks Davis 
41*b0d29bc4SBrooks Davis 
42*b0d29bc4SBrooks Davis /// Destructor.
~base_node(void)43*b0d29bc4SBrooks Davis config::detail::base_node::~base_node(void)
44*b0d29bc4SBrooks Davis {
45*b0d29bc4SBrooks Davis }
46*b0d29bc4SBrooks Davis 
47*b0d29bc4SBrooks Davis 
48*b0d29bc4SBrooks Davis /// Constructor.
49*b0d29bc4SBrooks Davis ///
50*b0d29bc4SBrooks Davis /// \param dynamic_ Whether the node is dynamic or not.
inner_node(const bool dynamic_)51*b0d29bc4SBrooks Davis config::detail::inner_node::inner_node(const bool dynamic_) :
52*b0d29bc4SBrooks Davis     _dynamic(dynamic_)
53*b0d29bc4SBrooks Davis {
54*b0d29bc4SBrooks Davis }
55*b0d29bc4SBrooks Davis 
56*b0d29bc4SBrooks Davis 
57*b0d29bc4SBrooks Davis /// Destructor.
~inner_node(void)58*b0d29bc4SBrooks Davis config::detail::inner_node::~inner_node(void)
59*b0d29bc4SBrooks Davis {
60*b0d29bc4SBrooks Davis     for (children_map::const_iterator iter = _children.begin();
61*b0d29bc4SBrooks Davis          iter != _children.end(); ++iter)
62*b0d29bc4SBrooks Davis         delete (*iter).second;
63*b0d29bc4SBrooks Davis }
64*b0d29bc4SBrooks Davis 
65*b0d29bc4SBrooks Davis 
66*b0d29bc4SBrooks Davis /// Fills the given node with a copy of this node's data.
67*b0d29bc4SBrooks Davis ///
68*b0d29bc4SBrooks Davis /// \param node The node to fill.  Should be the fresh return value of a
69*b0d29bc4SBrooks Davis ///     deep_copy() operation.
70*b0d29bc4SBrooks Davis void
copy_into(inner_node * node) const71*b0d29bc4SBrooks Davis config::detail::inner_node::copy_into(inner_node* node) const
72*b0d29bc4SBrooks Davis {
73*b0d29bc4SBrooks Davis     node->_dynamic = _dynamic;
74*b0d29bc4SBrooks Davis     for (children_map::const_iterator iter = _children.begin();
75*b0d29bc4SBrooks Davis          iter != _children.end(); ++iter) {
76*b0d29bc4SBrooks Davis         base_node* new_node = (*iter).second->deep_copy();
77*b0d29bc4SBrooks Davis         try {
78*b0d29bc4SBrooks Davis             node->_children[(*iter).first] = new_node;
79*b0d29bc4SBrooks Davis         } catch (...) {
80*b0d29bc4SBrooks Davis             delete new_node;
81*b0d29bc4SBrooks Davis             throw;
82*b0d29bc4SBrooks Davis         }
83*b0d29bc4SBrooks Davis     }
84*b0d29bc4SBrooks Davis }
85*b0d29bc4SBrooks Davis 
86*b0d29bc4SBrooks Davis 
87*b0d29bc4SBrooks Davis /// Combines two children sets, preferring the keys in the first set only.
88*b0d29bc4SBrooks Davis ///
89*b0d29bc4SBrooks Davis /// This operation is not symmetrical on c1 and c2.  The caller is responsible
90*b0d29bc4SBrooks Davis /// for invoking this twice so that the two key sets are combined if they happen
91*b0d29bc4SBrooks Davis /// to differ.
92*b0d29bc4SBrooks Davis ///
93*b0d29bc4SBrooks Davis /// \param key Key to this node.
94*b0d29bc4SBrooks Davis /// \param c1 First children set.
95*b0d29bc4SBrooks Davis /// \param c2 First children set.
96*b0d29bc4SBrooks Davis /// \param [in,out] node The node to combine into.
97*b0d29bc4SBrooks Davis ///
98*b0d29bc4SBrooks Davis /// \throw bad_combination_error If the two nodes cannot be combined.
99*b0d29bc4SBrooks Davis void
combine_children_into(const tree_key & key,const children_map & c1,const children_map & c2,inner_node * node) const100*b0d29bc4SBrooks Davis config::detail::inner_node::combine_children_into(
101*b0d29bc4SBrooks Davis     const tree_key& key,
102*b0d29bc4SBrooks Davis     const children_map& c1, const children_map& c2,
103*b0d29bc4SBrooks Davis     inner_node* node) const
104*b0d29bc4SBrooks Davis {
105*b0d29bc4SBrooks Davis     for (children_map::const_iterator iter1 = c1.begin();
106*b0d29bc4SBrooks Davis          iter1 != c1.end(); ++iter1) {
107*b0d29bc4SBrooks Davis         const std::string& name = (*iter1).first;
108*b0d29bc4SBrooks Davis 
109*b0d29bc4SBrooks Davis         if (node->_children.find(name) != node->_children.end()) {
110*b0d29bc4SBrooks Davis             continue;
111*b0d29bc4SBrooks Davis         }
112*b0d29bc4SBrooks Davis 
113*b0d29bc4SBrooks Davis         std::auto_ptr< base_node > new_node;
114*b0d29bc4SBrooks Davis 
115*b0d29bc4SBrooks Davis         children_map::const_iterator iter2 = c2.find(name);
116*b0d29bc4SBrooks Davis         if (iter2 == c2.end()) {
117*b0d29bc4SBrooks Davis             new_node.reset((*iter1).second->deep_copy());
118*b0d29bc4SBrooks Davis         } else {
119*b0d29bc4SBrooks Davis             tree_key child_key = key;
120*b0d29bc4SBrooks Davis             child_key.push_back(name);
121*b0d29bc4SBrooks Davis             new_node.reset((*iter1).second->combine(child_key,
122*b0d29bc4SBrooks Davis                                                     (*iter2).second));
123*b0d29bc4SBrooks Davis         }
124*b0d29bc4SBrooks Davis 
125*b0d29bc4SBrooks Davis         node->_children[name] = new_node.release();
126*b0d29bc4SBrooks Davis     }
127*b0d29bc4SBrooks Davis }
128*b0d29bc4SBrooks Davis 
129*b0d29bc4SBrooks Davis 
130*b0d29bc4SBrooks Davis /// Combines this inner node with another inner node onto a new node.
131*b0d29bc4SBrooks Davis ///
132*b0d29bc4SBrooks Davis /// The "dynamic" property is inherited by the new node if either of the two
133*b0d29bc4SBrooks Davis /// nodes are dynamic.
134*b0d29bc4SBrooks Davis ///
135*b0d29bc4SBrooks Davis /// \param key Key to this node.
136*b0d29bc4SBrooks Davis /// \param other_base The node to combine with.
137*b0d29bc4SBrooks Davis /// \param [in,out] node The node to combine into.
138*b0d29bc4SBrooks Davis ///
139*b0d29bc4SBrooks Davis /// \throw bad_combination_error If the two nodes cannot be combined.
140*b0d29bc4SBrooks Davis void
combine_into(const tree_key & key,const base_node * other_base,inner_node * node) const141*b0d29bc4SBrooks Davis config::detail::inner_node::combine_into(const tree_key& key,
142*b0d29bc4SBrooks Davis                                          const base_node* other_base,
143*b0d29bc4SBrooks Davis                                          inner_node* node) const
144*b0d29bc4SBrooks Davis {
145*b0d29bc4SBrooks Davis     try {
146*b0d29bc4SBrooks Davis         const inner_node& other = dynamic_cast< const inner_node& >(
147*b0d29bc4SBrooks Davis             *other_base);
148*b0d29bc4SBrooks Davis 
149*b0d29bc4SBrooks Davis         node->_dynamic = _dynamic || other._dynamic;
150*b0d29bc4SBrooks Davis 
151*b0d29bc4SBrooks Davis         combine_children_into(key, _children, other._children, node);
152*b0d29bc4SBrooks Davis         combine_children_into(key, other._children, _children, node);
153*b0d29bc4SBrooks Davis     } catch (const std::bad_cast& unused_e) {
154*b0d29bc4SBrooks Davis         throw config::bad_combination_error(
155*b0d29bc4SBrooks Davis             key, "'%s' is an inner node in the base tree but a leaf node in "
156*b0d29bc4SBrooks Davis             "the overrides treee");
157*b0d29bc4SBrooks Davis     }
158*b0d29bc4SBrooks Davis }
159*b0d29bc4SBrooks Davis 
160*b0d29bc4SBrooks Davis 
161*b0d29bc4SBrooks Davis /// Finds a node without creating it if not found.
162*b0d29bc4SBrooks Davis ///
163*b0d29bc4SBrooks Davis /// This recursive algorithm traverses the tree searching for a particular key.
164*b0d29bc4SBrooks Davis /// The returned node is constant, so this can only be used for querying
165*b0d29bc4SBrooks Davis /// purposes.  For this reason, this algorithm does not create intermediate
166*b0d29bc4SBrooks Davis /// nodes if they don't exist (as would be necessary to set a new node).
167*b0d29bc4SBrooks Davis ///
168*b0d29bc4SBrooks Davis /// \param key The key to be queried.
169*b0d29bc4SBrooks Davis /// \param key_pos The current level within the key to be examined.
170*b0d29bc4SBrooks Davis ///
171*b0d29bc4SBrooks Davis /// \return A reference to the located node, if successful.
172*b0d29bc4SBrooks Davis ///
173*b0d29bc4SBrooks Davis /// \throw unknown_key_error If the provided key is unknown.
174*b0d29bc4SBrooks Davis const config::detail::base_node*
lookup_ro(const tree_key & key,const tree_key::size_type key_pos) const175*b0d29bc4SBrooks Davis config::detail::inner_node::lookup_ro(const tree_key& key,
176*b0d29bc4SBrooks Davis                                       const tree_key::size_type key_pos) const
177*b0d29bc4SBrooks Davis {
178*b0d29bc4SBrooks Davis     PRE(key_pos < key.size());
179*b0d29bc4SBrooks Davis 
180*b0d29bc4SBrooks Davis     const children_map::const_iterator child_iter = _children.find(
181*b0d29bc4SBrooks Davis         key[key_pos]);
182*b0d29bc4SBrooks Davis     if (child_iter == _children.end())
183*b0d29bc4SBrooks Davis         throw unknown_key_error(key);
184*b0d29bc4SBrooks Davis 
185*b0d29bc4SBrooks Davis     if (key_pos == key.size() - 1) {
186*b0d29bc4SBrooks Davis         return (*child_iter).second;
187*b0d29bc4SBrooks Davis     } else {
188*b0d29bc4SBrooks Davis         PRE(key_pos < key.size() - 1);
189*b0d29bc4SBrooks Davis         try {
190*b0d29bc4SBrooks Davis             const inner_node& child = dynamic_cast< const inner_node& >(
191*b0d29bc4SBrooks Davis                 *(*child_iter).second);
192*b0d29bc4SBrooks Davis             return child.lookup_ro(key, key_pos + 1);
193*b0d29bc4SBrooks Davis         } catch (const std::bad_cast& e) {
194*b0d29bc4SBrooks Davis             throw unknown_key_error(
195*b0d29bc4SBrooks Davis                 key, "Cannot address incomplete configuration property '%s'");
196*b0d29bc4SBrooks Davis         }
197*b0d29bc4SBrooks Davis     }
198*b0d29bc4SBrooks Davis }
199*b0d29bc4SBrooks Davis 
200*b0d29bc4SBrooks Davis 
201*b0d29bc4SBrooks Davis /// Finds a node and creates it if not found.
202*b0d29bc4SBrooks Davis ///
203*b0d29bc4SBrooks Davis /// This recursive algorithm traverses the tree searching for a particular key,
204*b0d29bc4SBrooks Davis /// creating any intermediate nodes if they do not already exist (for the case
205*b0d29bc4SBrooks Davis /// of dynamic inner nodes).  The returned node is non-constant, so this can be
206*b0d29bc4SBrooks Davis /// used by the algorithms that set key values.
207*b0d29bc4SBrooks Davis ///
208*b0d29bc4SBrooks Davis /// \param key The key to be queried.
209*b0d29bc4SBrooks Davis /// \param key_pos The current level within the key to be examined.
210*b0d29bc4SBrooks Davis /// \param new_node A function that returns a new leaf node of the desired
211*b0d29bc4SBrooks Davis ///     type.  This is only called if the leaf cannot be found, but it has
212*b0d29bc4SBrooks Davis ///     already been defined.
213*b0d29bc4SBrooks Davis ///
214*b0d29bc4SBrooks Davis /// \return A reference to the located node, if successful.
215*b0d29bc4SBrooks Davis ///
216*b0d29bc4SBrooks Davis /// \throw invalid_key_value If the resulting node of the search would be an
217*b0d29bc4SBrooks Davis ///     inner node.
218*b0d29bc4SBrooks Davis /// \throw unknown_key_error If the provided key is unknown.
219*b0d29bc4SBrooks Davis config::leaf_node*
lookup_rw(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_node)220*b0d29bc4SBrooks Davis config::detail::inner_node::lookup_rw(const tree_key& key,
221*b0d29bc4SBrooks Davis                                       const tree_key::size_type key_pos,
222*b0d29bc4SBrooks Davis                                       new_node_hook new_node)
223*b0d29bc4SBrooks Davis {
224*b0d29bc4SBrooks Davis     PRE(key_pos < key.size());
225*b0d29bc4SBrooks Davis 
226*b0d29bc4SBrooks Davis     children_map::const_iterator child_iter = _children.find(key[key_pos]);
227*b0d29bc4SBrooks Davis     if (child_iter == _children.end()) {
228*b0d29bc4SBrooks Davis         if (_dynamic) {
229*b0d29bc4SBrooks Davis             base_node* const child = (key_pos == key.size() - 1) ?
230*b0d29bc4SBrooks Davis                 static_cast< base_node* >(new_node()) :
231*b0d29bc4SBrooks Davis                 static_cast< base_node* >(new dynamic_inner_node());
232*b0d29bc4SBrooks Davis             _children.insert(children_map::value_type(key[key_pos], child));
233*b0d29bc4SBrooks Davis             child_iter = _children.find(key[key_pos]);
234*b0d29bc4SBrooks Davis         } else {
235*b0d29bc4SBrooks Davis             throw unknown_key_error(key);
236*b0d29bc4SBrooks Davis         }
237*b0d29bc4SBrooks Davis     }
238*b0d29bc4SBrooks Davis 
239*b0d29bc4SBrooks Davis     if (key_pos == key.size() - 1) {
240*b0d29bc4SBrooks Davis         try {
241*b0d29bc4SBrooks Davis             leaf_node& child = dynamic_cast< leaf_node& >(
242*b0d29bc4SBrooks Davis                 *(*child_iter).second);
243*b0d29bc4SBrooks Davis             return &child;
244*b0d29bc4SBrooks Davis         } catch (const std::bad_cast& unused_error) {
245*b0d29bc4SBrooks Davis             throw invalid_key_value(key, "Type mismatch");
246*b0d29bc4SBrooks Davis         }
247*b0d29bc4SBrooks Davis     } else {
248*b0d29bc4SBrooks Davis         PRE(key_pos < key.size() - 1);
249*b0d29bc4SBrooks Davis         try {
250*b0d29bc4SBrooks Davis             inner_node& child = dynamic_cast< inner_node& >(
251*b0d29bc4SBrooks Davis                 *(*child_iter).second);
252*b0d29bc4SBrooks Davis             return child.lookup_rw(key, key_pos + 1, new_node);
253*b0d29bc4SBrooks Davis         } catch (const std::bad_cast& e) {
254*b0d29bc4SBrooks Davis             throw unknown_key_error(
255*b0d29bc4SBrooks Davis                 key, "Cannot address incomplete configuration property '%s'");
256*b0d29bc4SBrooks Davis         }
257*b0d29bc4SBrooks Davis     }
258*b0d29bc4SBrooks Davis }
259*b0d29bc4SBrooks Davis 
260*b0d29bc4SBrooks Davis 
261*b0d29bc4SBrooks Davis /// Converts the subtree to a collection of key/value string pairs.
262*b0d29bc4SBrooks Davis ///
263*b0d29bc4SBrooks Davis /// \param [out] properties The accumulator for the generated properties.  The
264*b0d29bc4SBrooks Davis ///     contents of the map are only extended.
265*b0d29bc4SBrooks Davis /// \param key The path to the current node.
266*b0d29bc4SBrooks Davis void
all_properties(properties_map & properties,const tree_key & key) const267*b0d29bc4SBrooks Davis config::detail::inner_node::all_properties(properties_map& properties,
268*b0d29bc4SBrooks Davis                                            const tree_key& key) const
269*b0d29bc4SBrooks Davis {
270*b0d29bc4SBrooks Davis     for (children_map::const_iterator iter = _children.begin();
271*b0d29bc4SBrooks Davis          iter != _children.end(); ++iter) {
272*b0d29bc4SBrooks Davis         tree_key child_key = key;
273*b0d29bc4SBrooks Davis         child_key.push_back((*iter).first);
274*b0d29bc4SBrooks Davis         try {
275*b0d29bc4SBrooks Davis             leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second);
276*b0d29bc4SBrooks Davis             if (child.is_set())
277*b0d29bc4SBrooks Davis                 properties[flatten_key(child_key)] = child.to_string();
278*b0d29bc4SBrooks Davis         } catch (const std::bad_cast& unused_error) {
279*b0d29bc4SBrooks Davis             inner_node& child = dynamic_cast< inner_node& >(*(*iter).second);
280*b0d29bc4SBrooks Davis             child.all_properties(properties, child_key);
281*b0d29bc4SBrooks Davis         }
282*b0d29bc4SBrooks Davis     }
283*b0d29bc4SBrooks Davis }
284*b0d29bc4SBrooks Davis 
285*b0d29bc4SBrooks Davis 
286*b0d29bc4SBrooks Davis /// Constructor.
static_inner_node(void)287*b0d29bc4SBrooks Davis config::detail::static_inner_node::static_inner_node(void) :
288*b0d29bc4SBrooks Davis     inner_node(false)
289*b0d29bc4SBrooks Davis {
290*b0d29bc4SBrooks Davis }
291*b0d29bc4SBrooks Davis 
292*b0d29bc4SBrooks Davis 
293*b0d29bc4SBrooks Davis /// Copies the node.
294*b0d29bc4SBrooks Davis ///
295*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
296*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const297*b0d29bc4SBrooks Davis config::detail::static_inner_node::deep_copy(void) const
298*b0d29bc4SBrooks Davis {
299*b0d29bc4SBrooks Davis     std::auto_ptr< inner_node > new_node(new static_inner_node());
300*b0d29bc4SBrooks Davis     copy_into(new_node.get());
301*b0d29bc4SBrooks Davis     return new_node.release();
302*b0d29bc4SBrooks Davis }
303*b0d29bc4SBrooks Davis 
304*b0d29bc4SBrooks Davis 
305*b0d29bc4SBrooks Davis /// Combines this node with another one.
306*b0d29bc4SBrooks Davis ///
307*b0d29bc4SBrooks Davis /// \param key Key to this node.
308*b0d29bc4SBrooks Davis /// \param other The node to combine with.
309*b0d29bc4SBrooks Davis ///
310*b0d29bc4SBrooks Davis /// \return A new node representing the combination.
311*b0d29bc4SBrooks Davis ///
312*b0d29bc4SBrooks Davis /// \throw bad_combination_error If the two nodes cannot be combined.
313*b0d29bc4SBrooks Davis config::detail::base_node*
combine(const tree_key & key,const base_node * other) const314*b0d29bc4SBrooks Davis config::detail::static_inner_node::combine(const tree_key& key,
315*b0d29bc4SBrooks Davis                                            const base_node* other) const
316*b0d29bc4SBrooks Davis {
317*b0d29bc4SBrooks Davis     std::auto_ptr< inner_node > new_node(new static_inner_node());
318*b0d29bc4SBrooks Davis     combine_into(key, other, new_node.get());
319*b0d29bc4SBrooks Davis     return new_node.release();
320*b0d29bc4SBrooks Davis }
321*b0d29bc4SBrooks Davis 
322*b0d29bc4SBrooks Davis 
323*b0d29bc4SBrooks Davis /// Registers a key as valid and having a specific type.
324*b0d29bc4SBrooks Davis ///
325*b0d29bc4SBrooks Davis /// This method does not raise errors on invalid/unknown keys or other
326*b0d29bc4SBrooks Davis /// tree-related issues.  The reasons is that define() is a method that does not
327*b0d29bc4SBrooks Davis /// depend on user input: it is intended to pre-populate the tree with a
328*b0d29bc4SBrooks Davis /// specific structure, and that happens once at coding time.
329*b0d29bc4SBrooks Davis ///
330*b0d29bc4SBrooks Davis /// \param key The key to be registered.
331*b0d29bc4SBrooks Davis /// \param key_pos The current level within the key to be examined.
332*b0d29bc4SBrooks Davis /// \param new_node A function that returns a new leaf node of the desired
333*b0d29bc4SBrooks Davis ///     type.
334*b0d29bc4SBrooks Davis void
define(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_node)335*b0d29bc4SBrooks Davis config::detail::static_inner_node::define(const tree_key& key,
336*b0d29bc4SBrooks Davis                                           const tree_key::size_type key_pos,
337*b0d29bc4SBrooks Davis                                           new_node_hook new_node)
338*b0d29bc4SBrooks Davis {
339*b0d29bc4SBrooks Davis     PRE(key_pos < key.size());
340*b0d29bc4SBrooks Davis 
341*b0d29bc4SBrooks Davis     if (key_pos == key.size() - 1) {
342*b0d29bc4SBrooks Davis         PRE_MSG(_children.find(key[key_pos]) == _children.end(),
343*b0d29bc4SBrooks Davis                 "Key already defined");
344*b0d29bc4SBrooks Davis         _children.insert(children_map::value_type(key[key_pos], new_node()));
345*b0d29bc4SBrooks Davis     } else {
346*b0d29bc4SBrooks Davis         PRE(key_pos < key.size() - 1);
347*b0d29bc4SBrooks Davis         const children_map::const_iterator child_iter = _children.find(
348*b0d29bc4SBrooks Davis             key[key_pos]);
349*b0d29bc4SBrooks Davis 
350*b0d29bc4SBrooks Davis         if (child_iter == _children.end()) {
351*b0d29bc4SBrooks Davis             static_inner_node* const child_ptr = new static_inner_node();
352*b0d29bc4SBrooks Davis             _children.insert(children_map::value_type(key[key_pos], child_ptr));
353*b0d29bc4SBrooks Davis             child_ptr->define(key, key_pos + 1, new_node);
354*b0d29bc4SBrooks Davis         } else {
355*b0d29bc4SBrooks Davis             try {
356*b0d29bc4SBrooks Davis                 static_inner_node& child = dynamic_cast< static_inner_node& >(
357*b0d29bc4SBrooks Davis                     *(*child_iter).second);
358*b0d29bc4SBrooks Davis                 child.define(key, key_pos + 1, new_node);
359*b0d29bc4SBrooks Davis             } catch (const std::bad_cast& e) {
360*b0d29bc4SBrooks Davis                 UNREACHABLE;
361*b0d29bc4SBrooks Davis             }
362*b0d29bc4SBrooks Davis         }
363*b0d29bc4SBrooks Davis     }
364*b0d29bc4SBrooks Davis }
365*b0d29bc4SBrooks Davis 
366*b0d29bc4SBrooks Davis 
367*b0d29bc4SBrooks Davis /// Constructor.
dynamic_inner_node(void)368*b0d29bc4SBrooks Davis config::detail::dynamic_inner_node::dynamic_inner_node(void) :
369*b0d29bc4SBrooks Davis     inner_node(true)
370*b0d29bc4SBrooks Davis {
371*b0d29bc4SBrooks Davis }
372*b0d29bc4SBrooks Davis 
373*b0d29bc4SBrooks Davis 
374*b0d29bc4SBrooks Davis /// Copies the node.
375*b0d29bc4SBrooks Davis ///
376*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
377*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const378*b0d29bc4SBrooks Davis config::detail::dynamic_inner_node::deep_copy(void) const
379*b0d29bc4SBrooks Davis {
380*b0d29bc4SBrooks Davis     std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
381*b0d29bc4SBrooks Davis     copy_into(new_node.get());
382*b0d29bc4SBrooks Davis     return new_node.release();
383*b0d29bc4SBrooks Davis }
384*b0d29bc4SBrooks Davis 
385*b0d29bc4SBrooks Davis 
386*b0d29bc4SBrooks Davis /// Combines this node with another one.
387*b0d29bc4SBrooks Davis ///
388*b0d29bc4SBrooks Davis /// \param key Key to this node.
389*b0d29bc4SBrooks Davis /// \param other The node to combine with.
390*b0d29bc4SBrooks Davis ///
391*b0d29bc4SBrooks Davis /// \return A new node representing the combination.
392*b0d29bc4SBrooks Davis ///
393*b0d29bc4SBrooks Davis /// \throw bad_combination_error If the two nodes cannot be combined.
394*b0d29bc4SBrooks Davis config::detail::base_node*
combine(const tree_key & key,const base_node * other) const395*b0d29bc4SBrooks Davis config::detail::dynamic_inner_node::combine(const tree_key& key,
396*b0d29bc4SBrooks Davis                                             const base_node* other) const
397*b0d29bc4SBrooks Davis {
398*b0d29bc4SBrooks Davis     std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
399*b0d29bc4SBrooks Davis     combine_into(key, other, new_node.get());
400*b0d29bc4SBrooks Davis     return new_node.release();
401*b0d29bc4SBrooks Davis }
402*b0d29bc4SBrooks Davis 
403*b0d29bc4SBrooks Davis 
404*b0d29bc4SBrooks Davis /// Destructor.
~leaf_node(void)405*b0d29bc4SBrooks Davis config::leaf_node::~leaf_node(void)
406*b0d29bc4SBrooks Davis {
407*b0d29bc4SBrooks Davis }
408*b0d29bc4SBrooks Davis 
409*b0d29bc4SBrooks Davis 
410*b0d29bc4SBrooks Davis /// Combines this node with another one.
411*b0d29bc4SBrooks Davis ///
412*b0d29bc4SBrooks Davis /// \param key Key to this node.
413*b0d29bc4SBrooks Davis /// \param other_base The node to combine with.
414*b0d29bc4SBrooks Davis ///
415*b0d29bc4SBrooks Davis /// \return A new node representing the combination.
416*b0d29bc4SBrooks Davis ///
417*b0d29bc4SBrooks Davis /// \throw bad_combination_error If the two nodes cannot be combined.
418*b0d29bc4SBrooks Davis config::detail::base_node*
combine(const detail::tree_key & key,const base_node * other_base) const419*b0d29bc4SBrooks Davis config::leaf_node::combine(const detail::tree_key& key,
420*b0d29bc4SBrooks Davis                            const base_node* other_base) const
421*b0d29bc4SBrooks Davis {
422*b0d29bc4SBrooks Davis     try {
423*b0d29bc4SBrooks Davis         const leaf_node& other = dynamic_cast< const leaf_node& >(*other_base);
424*b0d29bc4SBrooks Davis 
425*b0d29bc4SBrooks Davis         if (other.is_set()) {
426*b0d29bc4SBrooks Davis             return other.deep_copy();
427*b0d29bc4SBrooks Davis         } else {
428*b0d29bc4SBrooks Davis             return deep_copy();
429*b0d29bc4SBrooks Davis         }
430*b0d29bc4SBrooks Davis     } catch (const std::bad_cast& unused_e) {
431*b0d29bc4SBrooks Davis         throw config::bad_combination_error(
432*b0d29bc4SBrooks Davis             key, "'%s' is a leaf node in the base tree but an inner node in "
433*b0d29bc4SBrooks Davis             "the overrides treee");
434*b0d29bc4SBrooks Davis     }
435*b0d29bc4SBrooks Davis }
436*b0d29bc4SBrooks Davis 
437*b0d29bc4SBrooks Davis 
438*b0d29bc4SBrooks Davis /// Copies the node.
439*b0d29bc4SBrooks Davis ///
440*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
441*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const442*b0d29bc4SBrooks Davis config::bool_node::deep_copy(void) const
443*b0d29bc4SBrooks Davis {
444*b0d29bc4SBrooks Davis     std::auto_ptr< bool_node > new_node(new bool_node());
445*b0d29bc4SBrooks Davis     new_node->_value = _value;
446*b0d29bc4SBrooks Davis     return new_node.release();
447*b0d29bc4SBrooks Davis }
448*b0d29bc4SBrooks Davis 
449*b0d29bc4SBrooks Davis 
450*b0d29bc4SBrooks Davis /// Pushes the node's value onto the Lua stack.
451*b0d29bc4SBrooks Davis ///
452*b0d29bc4SBrooks Davis /// \param state The Lua state onto which to push the value.
453*b0d29bc4SBrooks Davis void
push_lua(lutok::state & state) const454*b0d29bc4SBrooks Davis config::bool_node::push_lua(lutok::state& state) const
455*b0d29bc4SBrooks Davis {
456*b0d29bc4SBrooks Davis     state.push_boolean(value());
457*b0d29bc4SBrooks Davis }
458*b0d29bc4SBrooks Davis 
459*b0d29bc4SBrooks Davis 
460*b0d29bc4SBrooks Davis /// Sets the value of the node from an entry in the Lua stack.
461*b0d29bc4SBrooks Davis ///
462*b0d29bc4SBrooks Davis /// \param state The Lua state from which to get the value.
463*b0d29bc4SBrooks Davis /// \param value_index The stack index in which the value resides.
464*b0d29bc4SBrooks Davis ///
465*b0d29bc4SBrooks Davis /// \throw value_error If the value in state(value_index) cannot be
466*b0d29bc4SBrooks Davis ///     processed by this node.
467*b0d29bc4SBrooks Davis void
set_lua(lutok::state & state,const int value_index)468*b0d29bc4SBrooks Davis config::bool_node::set_lua(lutok::state& state, const int value_index)
469*b0d29bc4SBrooks Davis {
470*b0d29bc4SBrooks Davis     if (state.is_boolean(value_index))
471*b0d29bc4SBrooks Davis         set(state.to_boolean(value_index));
472*b0d29bc4SBrooks Davis     else
473*b0d29bc4SBrooks Davis         throw value_error("Not a boolean");
474*b0d29bc4SBrooks Davis }
475*b0d29bc4SBrooks Davis 
476*b0d29bc4SBrooks Davis 
477*b0d29bc4SBrooks Davis /// Copies the node.
478*b0d29bc4SBrooks Davis ///
479*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
480*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const481*b0d29bc4SBrooks Davis config::int_node::deep_copy(void) const
482*b0d29bc4SBrooks Davis {
483*b0d29bc4SBrooks Davis     std::auto_ptr< int_node > new_node(new int_node());
484*b0d29bc4SBrooks Davis     new_node->_value = _value;
485*b0d29bc4SBrooks Davis     return new_node.release();
486*b0d29bc4SBrooks Davis }
487*b0d29bc4SBrooks Davis 
488*b0d29bc4SBrooks Davis 
489*b0d29bc4SBrooks Davis /// Pushes the node's value onto the Lua stack.
490*b0d29bc4SBrooks Davis ///
491*b0d29bc4SBrooks Davis /// \param state The Lua state onto which to push the value.
492*b0d29bc4SBrooks Davis void
push_lua(lutok::state & state) const493*b0d29bc4SBrooks Davis config::int_node::push_lua(lutok::state& state) const
494*b0d29bc4SBrooks Davis {
495*b0d29bc4SBrooks Davis     state.push_integer(value());
496*b0d29bc4SBrooks Davis }
497*b0d29bc4SBrooks Davis 
498*b0d29bc4SBrooks Davis 
499*b0d29bc4SBrooks Davis /// Sets the value of the node from an entry in the Lua stack.
500*b0d29bc4SBrooks Davis ///
501*b0d29bc4SBrooks Davis /// \param state The Lua state from which to get the value.
502*b0d29bc4SBrooks Davis /// \param value_index The stack index in which the value resides.
503*b0d29bc4SBrooks Davis ///
504*b0d29bc4SBrooks Davis /// \throw value_error If the value in state(value_index) cannot be
505*b0d29bc4SBrooks Davis ///     processed by this node.
506*b0d29bc4SBrooks Davis void
set_lua(lutok::state & state,const int value_index)507*b0d29bc4SBrooks Davis config::int_node::set_lua(lutok::state& state, const int value_index)
508*b0d29bc4SBrooks Davis {
509*b0d29bc4SBrooks Davis     if (state.is_number(value_index))
510*b0d29bc4SBrooks Davis         set(state.to_integer(value_index));
511*b0d29bc4SBrooks Davis     else
512*b0d29bc4SBrooks Davis         throw value_error("Not an integer");
513*b0d29bc4SBrooks Davis }
514*b0d29bc4SBrooks Davis 
515*b0d29bc4SBrooks Davis 
516*b0d29bc4SBrooks Davis /// Checks a given value for validity.
517*b0d29bc4SBrooks Davis ///
518*b0d29bc4SBrooks Davis /// \param new_value The value to validate.
519*b0d29bc4SBrooks Davis ///
520*b0d29bc4SBrooks Davis /// \throw value_error If the value is not valid.
521*b0d29bc4SBrooks Davis void
validate(const value_type & new_value) const522*b0d29bc4SBrooks Davis config::positive_int_node::validate(const value_type& new_value) const
523*b0d29bc4SBrooks Davis {
524*b0d29bc4SBrooks Davis     if (new_value <= 0)
525*b0d29bc4SBrooks Davis         throw value_error("Must be a positive integer");
526*b0d29bc4SBrooks Davis }
527*b0d29bc4SBrooks Davis 
528*b0d29bc4SBrooks Davis 
529*b0d29bc4SBrooks Davis /// Copies the node.
530*b0d29bc4SBrooks Davis ///
531*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
532*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const533*b0d29bc4SBrooks Davis config::string_node::deep_copy(void) const
534*b0d29bc4SBrooks Davis {
535*b0d29bc4SBrooks Davis     std::auto_ptr< string_node > new_node(new string_node());
536*b0d29bc4SBrooks Davis     new_node->_value = _value;
537*b0d29bc4SBrooks Davis     return new_node.release();
538*b0d29bc4SBrooks Davis }
539*b0d29bc4SBrooks Davis 
540*b0d29bc4SBrooks Davis 
541*b0d29bc4SBrooks Davis /// Pushes the node's value onto the Lua stack.
542*b0d29bc4SBrooks Davis ///
543*b0d29bc4SBrooks Davis /// \param state The Lua state onto which to push the value.
544*b0d29bc4SBrooks Davis void
push_lua(lutok::state & state) const545*b0d29bc4SBrooks Davis config::string_node::push_lua(lutok::state& state) const
546*b0d29bc4SBrooks Davis {
547*b0d29bc4SBrooks Davis     state.push_string(value());
548*b0d29bc4SBrooks Davis }
549*b0d29bc4SBrooks Davis 
550*b0d29bc4SBrooks Davis 
551*b0d29bc4SBrooks Davis /// Sets the value of the node from an entry in the Lua stack.
552*b0d29bc4SBrooks Davis ///
553*b0d29bc4SBrooks Davis /// \param state The Lua state from which to get the value.
554*b0d29bc4SBrooks Davis /// \param value_index The stack index in which the value resides.
555*b0d29bc4SBrooks Davis ///
556*b0d29bc4SBrooks Davis /// \throw value_error If the value in state(value_index) cannot be
557*b0d29bc4SBrooks Davis ///     processed by this node.
558*b0d29bc4SBrooks Davis void
set_lua(lutok::state & state,const int value_index)559*b0d29bc4SBrooks Davis config::string_node::set_lua(lutok::state& state, const int value_index)
560*b0d29bc4SBrooks Davis {
561*b0d29bc4SBrooks Davis     if (state.is_string(value_index))
562*b0d29bc4SBrooks Davis         set(state.to_string(value_index));
563*b0d29bc4SBrooks Davis     else
564*b0d29bc4SBrooks Davis         throw value_error("Not a string");
565*b0d29bc4SBrooks Davis }
566*b0d29bc4SBrooks Davis 
567*b0d29bc4SBrooks Davis 
568*b0d29bc4SBrooks Davis /// Copies the node.
569*b0d29bc4SBrooks Davis ///
570*b0d29bc4SBrooks Davis /// \return A dynamically-allocated node.
571*b0d29bc4SBrooks Davis config::detail::base_node*
deep_copy(void) const572*b0d29bc4SBrooks Davis config::strings_set_node::deep_copy(void) const
573*b0d29bc4SBrooks Davis {
574*b0d29bc4SBrooks Davis     std::auto_ptr< strings_set_node > new_node(new strings_set_node());
575*b0d29bc4SBrooks Davis     new_node->_value = _value;
576*b0d29bc4SBrooks Davis     return new_node.release();
577*b0d29bc4SBrooks Davis }
578*b0d29bc4SBrooks Davis 
579*b0d29bc4SBrooks Davis 
580*b0d29bc4SBrooks Davis /// Converts a single word to the native type.
581*b0d29bc4SBrooks Davis ///
582*b0d29bc4SBrooks Davis /// \param raw_value The value to parse.
583*b0d29bc4SBrooks Davis ///
584*b0d29bc4SBrooks Davis /// \return The parsed value.
585*b0d29bc4SBrooks Davis std::string
parse_one(const std::string & raw_value) const586*b0d29bc4SBrooks Davis config::strings_set_node::parse_one(const std::string& raw_value) const
587*b0d29bc4SBrooks Davis {
588*b0d29bc4SBrooks Davis     return raw_value;
589*b0d29bc4SBrooks Davis }
590