1 // Copyright 2012 The Kyua Authors.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "utils/config/nodes.ipp"
33 #include <lutok/state.ipp>
35 #include "utils/config/exceptions.hpp"
36 #include "utils/config/keys.hpp"
37 #include "utils/format/macros.hpp"
39 namespace config = utils::config;
43 config::detail::base_node::~base_node(void)
50 /// \param dynamic_ Whether the node is dynamic or not.
51 config::detail::inner_node::inner_node(const bool dynamic_) :
58 config::detail::inner_node::~inner_node(void)
60 for (children_map::const_iterator iter = _children.begin();
61 iter != _children.end(); ++iter)
62 delete (*iter).second;
66 /// Fills the given node with a copy of this node's data.
68 /// \param node The node to fill. Should be the fresh return value of a
69 /// deep_copy() operation.
71 config::detail::inner_node::copy_into(inner_node* node) const
73 node->_dynamic = _dynamic;
74 for (children_map::const_iterator iter = _children.begin();
75 iter != _children.end(); ++iter) {
76 base_node* new_node = (*iter).second->deep_copy();
78 node->_children[(*iter).first] = new_node;
87 /// Combines two children sets, preferring the keys in the first set only.
89 /// This operation is not symmetrical on c1 and c2. The caller is responsible
90 /// for invoking this twice so that the two key sets are combined if they happen
93 /// \param key Key to this node.
94 /// \param c1 First children set.
95 /// \param c2 First children set.
96 /// \param [in,out] node The node to combine into.
98 /// \throw bad_combination_error If the two nodes cannot be combined.
100 config::detail::inner_node::combine_children_into(
102 const children_map& c1, const children_map& c2,
103 inner_node* node) const
105 for (children_map::const_iterator iter1 = c1.begin();
106 iter1 != c1.end(); ++iter1) {
107 const std::string& name = (*iter1).first;
109 if (node->_children.find(name) != node->_children.end()) {
113 std::auto_ptr< base_node > new_node;
115 children_map::const_iterator iter2 = c2.find(name);
116 if (iter2 == c2.end()) {
117 new_node.reset((*iter1).second->deep_copy());
119 tree_key child_key = key;
120 child_key.push_back(name);
121 new_node.reset((*iter1).second->combine(child_key,
125 node->_children[name] = new_node.release();
130 /// Combines this inner node with another inner node onto a new node.
132 /// The "dynamic" property is inherited by the new node if either of the two
133 /// nodes are dynamic.
135 /// \param key Key to this node.
136 /// \param other_base The node to combine with.
137 /// \param [in,out] node The node to combine into.
139 /// \throw bad_combination_error If the two nodes cannot be combined.
141 config::detail::inner_node::combine_into(const tree_key& key,
142 const base_node* other_base,
143 inner_node* node) const
146 const inner_node& other = dynamic_cast< const inner_node& >(
149 node->_dynamic = _dynamic || other._dynamic;
151 combine_children_into(key, _children, other._children, node);
152 combine_children_into(key, other._children, _children, node);
153 } catch (const std::bad_cast& unused_e) {
154 throw config::bad_combination_error(
155 key, "'%s' is an inner node in the base tree but a leaf node in "
156 "the overrides treee");
161 /// Finds a node without creating it if not found.
163 /// This recursive algorithm traverses the tree searching for a particular key.
164 /// The returned node is constant, so this can only be used for querying
165 /// purposes. For this reason, this algorithm does not create intermediate
166 /// nodes if they don't exist (as would be necessary to set a new node).
168 /// \param key The key to be queried.
169 /// \param key_pos The current level within the key to be examined.
171 /// \return A reference to the located node, if successful.
173 /// \throw unknown_key_error If the provided key is unknown.
174 const config::detail::base_node*
175 config::detail::inner_node::lookup_ro(const tree_key& key,
176 const tree_key::size_type key_pos) const
178 PRE(key_pos < key.size());
180 const children_map::const_iterator child_iter = _children.find(
182 if (child_iter == _children.end())
183 throw unknown_key_error(key);
185 if (key_pos == key.size() - 1) {
186 return (*child_iter).second;
188 PRE(key_pos < key.size() - 1);
190 const inner_node& child = dynamic_cast< const inner_node& >(
191 *(*child_iter).second);
192 return child.lookup_ro(key, key_pos + 1);
193 } catch (const std::bad_cast& e) {
194 throw unknown_key_error(
195 key, "Cannot address incomplete configuration property '%s'");
201 /// Finds a node and creates it if not found.
203 /// This recursive algorithm traverses the tree searching for a particular key,
204 /// creating any intermediate nodes if they do not already exist (for the case
205 /// of dynamic inner nodes). The returned node is non-constant, so this can be
206 /// used by the algorithms that set key values.
208 /// \param key The key to be queried.
209 /// \param key_pos The current level within the key to be examined.
210 /// \param new_node A function that returns a new leaf node of the desired
211 /// type. This is only called if the leaf cannot be found, but it has
212 /// already been defined.
214 /// \return A reference to the located node, if successful.
216 /// \throw invalid_key_value If the resulting node of the search would be an
218 /// \throw unknown_key_error If the provided key is unknown.
220 config::detail::inner_node::lookup_rw(const tree_key& key,
221 const tree_key::size_type key_pos,
222 new_node_hook new_node)
224 PRE(key_pos < key.size());
226 children_map::const_iterator child_iter = _children.find(key[key_pos]);
227 if (child_iter == _children.end()) {
229 base_node* const child = (key_pos == key.size() - 1) ?
230 static_cast< base_node* >(new_node()) :
231 static_cast< base_node* >(new dynamic_inner_node());
232 _children.insert(children_map::value_type(key[key_pos], child));
233 child_iter = _children.find(key[key_pos]);
235 throw unknown_key_error(key);
239 if (key_pos == key.size() - 1) {
241 leaf_node& child = dynamic_cast< leaf_node& >(
242 *(*child_iter).second);
244 } catch (const std::bad_cast& unused_error) {
245 throw invalid_key_value(key, "Type mismatch");
248 PRE(key_pos < key.size() - 1);
250 inner_node& child = dynamic_cast< inner_node& >(
251 *(*child_iter).second);
252 return child.lookup_rw(key, key_pos + 1, new_node);
253 } catch (const std::bad_cast& e) {
254 throw unknown_key_error(
255 key, "Cannot address incomplete configuration property '%s'");
261 /// Converts the subtree to a collection of key/value string pairs.
263 /// \param [out] properties The accumulator for the generated properties. The
264 /// contents of the map are only extended.
265 /// \param key The path to the current node.
267 config::detail::inner_node::all_properties(properties_map& properties,
268 const tree_key& key) const
270 for (children_map::const_iterator iter = _children.begin();
271 iter != _children.end(); ++iter) {
272 tree_key child_key = key;
273 child_key.push_back((*iter).first);
275 leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second);
277 properties[flatten_key(child_key)] = child.to_string();
278 } catch (const std::bad_cast& unused_error) {
279 inner_node& child = dynamic_cast< inner_node& >(*(*iter).second);
280 child.all_properties(properties, child_key);
287 config::detail::static_inner_node::static_inner_node(void) :
295 /// \return A dynamically-allocated node.
296 config::detail::base_node*
297 config::detail::static_inner_node::deep_copy(void) const
299 std::auto_ptr< inner_node > new_node(new static_inner_node());
300 copy_into(new_node.get());
301 return new_node.release();
305 /// Combines this node with another one.
307 /// \param key Key to this node.
308 /// \param other The node to combine with.
310 /// \return A new node representing the combination.
312 /// \throw bad_combination_error If the two nodes cannot be combined.
313 config::detail::base_node*
314 config::detail::static_inner_node::combine(const tree_key& key,
315 const base_node* other) const
317 std::auto_ptr< inner_node > new_node(new static_inner_node());
318 combine_into(key, other, new_node.get());
319 return new_node.release();
323 /// Registers a key as valid and having a specific type.
325 /// This method does not raise errors on invalid/unknown keys or other
326 /// tree-related issues. The reasons is that define() is a method that does not
327 /// depend on user input: it is intended to pre-populate the tree with a
328 /// specific structure, and that happens once at coding time.
330 /// \param key The key to be registered.
331 /// \param key_pos The current level within the key to be examined.
332 /// \param new_node A function that returns a new leaf node of the desired
335 config::detail::static_inner_node::define(const tree_key& key,
336 const tree_key::size_type key_pos,
337 new_node_hook new_node)
339 PRE(key_pos < key.size());
341 if (key_pos == key.size() - 1) {
342 PRE_MSG(_children.find(key[key_pos]) == _children.end(),
343 "Key already defined");
344 _children.insert(children_map::value_type(key[key_pos], new_node()));
346 PRE(key_pos < key.size() - 1);
347 const children_map::const_iterator child_iter = _children.find(
350 if (child_iter == _children.end()) {
351 static_inner_node* const child_ptr = new static_inner_node();
352 _children.insert(children_map::value_type(key[key_pos], child_ptr));
353 child_ptr->define(key, key_pos + 1, new_node);
356 static_inner_node& child = dynamic_cast< static_inner_node& >(
357 *(*child_iter).second);
358 child.define(key, key_pos + 1, new_node);
359 } catch (const std::bad_cast& e) {
368 config::detail::dynamic_inner_node::dynamic_inner_node(void) :
376 /// \return A dynamically-allocated node.
377 config::detail::base_node*
378 config::detail::dynamic_inner_node::deep_copy(void) const
380 std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
381 copy_into(new_node.get());
382 return new_node.release();
386 /// Combines this node with another one.
388 /// \param key Key to this node.
389 /// \param other The node to combine with.
391 /// \return A new node representing the combination.
393 /// \throw bad_combination_error If the two nodes cannot be combined.
394 config::detail::base_node*
395 config::detail::dynamic_inner_node::combine(const tree_key& key,
396 const base_node* other) const
398 std::auto_ptr< inner_node > new_node(new dynamic_inner_node());
399 combine_into(key, other, new_node.get());
400 return new_node.release();
405 config::leaf_node::~leaf_node(void)
410 /// Combines this node with another one.
412 /// \param key Key to this node.
413 /// \param other_base The node to combine with.
415 /// \return A new node representing the combination.
417 /// \throw bad_combination_error If the two nodes cannot be combined.
418 config::detail::base_node*
419 config::leaf_node::combine(const detail::tree_key& key,
420 const base_node* other_base) const
423 const leaf_node& other = dynamic_cast< const leaf_node& >(*other_base);
425 if (other.is_set()) {
426 return other.deep_copy();
430 } catch (const std::bad_cast& unused_e) {
431 throw config::bad_combination_error(
432 key, "'%s' is a leaf node in the base tree but an inner node in "
433 "the overrides treee");
440 /// \return A dynamically-allocated node.
441 config::detail::base_node*
442 config::bool_node::deep_copy(void) const
444 std::auto_ptr< bool_node > new_node(new bool_node());
445 new_node->_value = _value;
446 return new_node.release();
450 /// Pushes the node's value onto the Lua stack.
452 /// \param state The Lua state onto which to push the value.
454 config::bool_node::push_lua(lutok::state& state) const
456 state.push_boolean(value());
460 /// Sets the value of the node from an entry in the Lua stack.
462 /// \param state The Lua state from which to get the value.
463 /// \param value_index The stack index in which the value resides.
465 /// \throw value_error If the value in state(value_index) cannot be
466 /// processed by this node.
468 config::bool_node::set_lua(lutok::state& state, const int value_index)
470 if (state.is_boolean(value_index))
471 set(state.to_boolean(value_index));
473 throw value_error("Not a boolean");
479 /// \return A dynamically-allocated node.
480 config::detail::base_node*
481 config::int_node::deep_copy(void) const
483 std::auto_ptr< int_node > new_node(new int_node());
484 new_node->_value = _value;
485 return new_node.release();
489 /// Pushes the node's value onto the Lua stack.
491 /// \param state The Lua state onto which to push the value.
493 config::int_node::push_lua(lutok::state& state) const
495 state.push_integer(value());
499 /// Sets the value of the node from an entry in the Lua stack.
501 /// \param state The Lua state from which to get the value.
502 /// \param value_index The stack index in which the value resides.
504 /// \throw value_error If the value in state(value_index) cannot be
505 /// processed by this node.
507 config::int_node::set_lua(lutok::state& state, const int value_index)
509 if (state.is_number(value_index))
510 set(state.to_integer(value_index));
512 throw value_error("Not an integer");
516 /// Checks a given value for validity.
518 /// \param new_value The value to validate.
520 /// \throw value_error If the value is not valid.
522 config::positive_int_node::validate(const value_type& new_value) const
525 throw value_error("Must be a positive integer");
531 /// \return A dynamically-allocated node.
532 config::detail::base_node*
533 config::string_node::deep_copy(void) const
535 std::auto_ptr< string_node > new_node(new string_node());
536 new_node->_value = _value;
537 return new_node.release();
541 /// Pushes the node's value onto the Lua stack.
543 /// \param state The Lua state onto which to push the value.
545 config::string_node::push_lua(lutok::state& state) const
547 state.push_string(value());
551 /// Sets the value of the node from an entry in the Lua stack.
553 /// \param state The Lua state from which to get the value.
554 /// \param value_index The stack index in which the value resides.
556 /// \throw value_error If the value in state(value_index) cannot be
557 /// processed by this node.
559 config::string_node::set_lua(lutok::state& state, const int value_index)
561 if (state.is_string(value_index))
562 set(state.to_string(value_index));
564 throw value_error("Not a string");
570 /// \return A dynamically-allocated node.
571 config::detail::base_node*
572 config::strings_set_node::deep_copy(void) const
574 std::auto_ptr< strings_set_node > new_node(new strings_set_node());
575 new_node->_value = _value;
576 return new_node.release();
580 /// Converts a single word to the native type.
582 /// \param raw_value The value to parse.
584 /// \return The parsed value.
586 config::strings_set_node::parse_one(const std::string& raw_value) const