1 // Copyright 2012 Google Inc.
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 /// Finds a node without creating it if not found.
89 /// This recursive algorithm traverses the tree searching for a particular key.
90 /// The returned node is constant, so this can only be used for querying
91 /// purposes. For this reason, this algorithm does not create intermediate
92 /// nodes if they don't exist (as would be necessary to set a new node).
94 /// \param key The key to be queried.
95 /// \param key_pos The current level within the key to be examined.
97 /// \return A reference to the located node, if successful.
99 /// \throw unknown_key_error If the provided key is unknown.
100 const config::detail::base_node
*
101 config::detail::inner_node::lookup_ro(const tree_key
& key
,
102 const tree_key::size_type key_pos
) const
104 PRE(key_pos
< key
.size());
106 const children_map::const_iterator child_iter
= _children
.find(
108 if (child_iter
== _children
.end())
109 throw unknown_key_error(key
);
111 if (key_pos
== key
.size() - 1) {
112 return (*child_iter
).second
;
114 PRE(key_pos
< key
.size() - 1);
116 const inner_node
& child
= dynamic_cast< const inner_node
& >(
117 *(*child_iter
).second
);
118 return child
.lookup_ro(key
, key_pos
+ 1);
119 } catch (const std::bad_cast
& e
) {
120 throw unknown_key_error(
121 key
, "Cannot address incomplete configuration property '%s'");
127 /// Finds a node and creates it if not found.
129 /// This recursive algorithm traverses the tree searching for a particular key,
130 /// creating any intermediate nodes if they do not already exist (for the case
131 /// of dynamic inner nodes). The returned node is non-constant, so this can be
132 /// used by the algorithms that set key values.
134 /// \param key The key to be queried.
135 /// \param key_pos The current level within the key to be examined.
136 /// \param new_node A function that returns a new leaf node of the desired
137 /// type. This is only called if the leaf cannot be found, but it has
138 /// already been defined.
140 /// \return A reference to the located node, if successful.
142 /// \throw unknown_key_error If the provided key is unknown.
143 /// \throw value_error If the resulting node of the search would be an inner
146 config::detail::inner_node::lookup_rw(const tree_key
& key
,
147 const tree_key::size_type key_pos
,
148 new_node_hook new_node
)
150 PRE(key_pos
< key
.size());
152 children_map::const_iterator child_iter
= _children
.find(key
[key_pos
]);
153 if (child_iter
== _children
.end()) {
155 base_node
* const child
= (key_pos
== key
.size() - 1) ?
156 static_cast< base_node
* >(new_node()) :
157 static_cast< base_node
* >(new dynamic_inner_node());
158 _children
.insert(children_map::value_type(key
[key_pos
], child
));
159 child_iter
= _children
.find(key
[key_pos
]);
161 throw unknown_key_error(key
);
165 if (key_pos
== key
.size() - 1) {
167 leaf_node
& child
= dynamic_cast< leaf_node
& >(
168 *(*child_iter
).second
);
170 } catch (const std::bad_cast
& unused_error
) {
171 throw value_error(F("Invalid value for key '%s'") %
175 PRE(key_pos
< key
.size() - 1);
177 inner_node
& child
= dynamic_cast< inner_node
& >(
178 *(*child_iter
).second
);
179 return child
.lookup_rw(key
, key_pos
+ 1, new_node
);
180 } catch (const std::bad_cast
& e
) {
181 throw unknown_key_error(
182 key
, "Cannot address incomplete configuration property '%s'");
188 /// Converts the subtree to a collection of key/value string pairs.
190 /// \param [out] properties The accumulator for the generated properties. The
191 /// contents of the map are only extended.
192 /// \param key The path to the current node.
194 config::detail::inner_node::all_properties(properties_map
& properties
,
195 const tree_key
& key
) const
197 for (children_map::const_iterator iter
= _children
.begin();
198 iter
!= _children
.end(); ++iter
) {
199 tree_key child_key
= key
;
200 child_key
.push_back((*iter
).first
);
202 leaf_node
& child
= dynamic_cast< leaf_node
& >(*(*iter
).second
);
204 properties
[flatten_key(child_key
)] = child
.to_string();
205 } catch (const std::bad_cast
& unused_error
) {
206 inner_node
& child
= dynamic_cast< inner_node
& >(*(*iter
).second
);
207 child
.all_properties(properties
, child_key
);
214 config::detail::static_inner_node::static_inner_node(void) :
222 /// \return A dynamically-allocated node.
223 config::detail::base_node
*
224 config::detail::static_inner_node::deep_copy(void) const
226 std::auto_ptr
< inner_node
> new_node(new static_inner_node());
227 copy_into(new_node
.get());
228 return new_node
.release();
232 /// Registers a key as valid and having a specific type.
234 /// This method does not raise errors on invalid/unknown keys or other
235 /// tree-related issues. The reasons is that define() is a method that does not
236 /// depend on user input: it is intended to pre-populate the tree with a
237 /// specific structure, and that happens once at coding time.
239 /// \param key The key to be registered.
240 /// \param key_pos The current level within the key to be examined.
241 /// \param new_node A function that returns a new leaf node of the desired
244 config::detail::static_inner_node::define(const tree_key
& key
,
245 const tree_key::size_type key_pos
,
246 new_node_hook new_node
)
248 PRE(key_pos
< key
.size());
250 if (key_pos
== key
.size() - 1) {
251 PRE_MSG(_children
.find(key
[key_pos
]) == _children
.end(),
252 "Key already defined");
253 _children
.insert(children_map::value_type(key
[key_pos
], new_node()));
255 PRE(key_pos
< key
.size() - 1);
256 const children_map::const_iterator child_iter
= _children
.find(
259 if (child_iter
== _children
.end()) {
260 static_inner_node
* const child_ptr
= new static_inner_node();
261 _children
.insert(children_map::value_type(key
[key_pos
], child_ptr
));
262 child_ptr
->define(key
, key_pos
+ 1, new_node
);
265 static_inner_node
& child
= dynamic_cast< static_inner_node
& >(
266 *(*child_iter
).second
);
267 child
.define(key
, key_pos
+ 1, new_node
);
268 } catch (const std::bad_cast
& e
) {
277 config::detail::dynamic_inner_node::dynamic_inner_node(void) :
285 /// \return A dynamically-allocated node.
286 config::detail::base_node
*
287 config::detail::dynamic_inner_node::deep_copy(void) const
289 std::auto_ptr
< inner_node
> new_node(new dynamic_inner_node());
290 copy_into(new_node
.get());
291 return new_node
.release();
296 config::leaf_node::~leaf_node(void)
303 /// \return A dynamically-allocated node.
304 config::detail::base_node
*
305 config::bool_node::deep_copy(void) const
307 std::auto_ptr
< bool_node
> new_node(new bool_node());
308 new_node
->_value
= _value
;
309 return new_node
.release();
313 /// Pushes the node's value onto the Lua stack.
315 /// \param state The Lua state onto which to push the value.
317 config::bool_node::push_lua(lutok::state
& state
) const
319 state
.push_boolean(value());
323 /// Sets the value of the node from an entry in the Lua stack.
325 /// \param state The Lua state from which to get the value.
326 /// \param value_index The stack index in which the value resides.
328 /// \throw value_error If the value in state(value_index) cannot be
329 /// processed by this node.
331 config::bool_node::set_lua(lutok::state
& state
, const int value_index
)
333 if (state
.is_boolean(value_index
))
334 set(state
.to_boolean(value_index
));
336 throw value_error("Not a boolean");
342 /// \return A dynamically-allocated node.
343 config::detail::base_node
*
344 config::int_node::deep_copy(void) const
346 std::auto_ptr
< int_node
> new_node(new int_node());
347 new_node
->_value
= _value
;
348 return new_node
.release();
352 /// Pushes the node's value onto the Lua stack.
354 /// \param state The Lua state onto which to push the value.
356 config::int_node::push_lua(lutok::state
& state
) const
358 state
.push_integer(value());
362 /// Sets the value of the node from an entry in the Lua stack.
364 /// \param state The Lua state from which to get the value.
365 /// \param value_index The stack index in which the value resides.
367 /// \throw value_error If the value in state(value_index) cannot be
368 /// processed by this node.
370 config::int_node::set_lua(lutok::state
& state
, const int value_index
)
372 if (state
.is_number(value_index
))
373 set(state
.to_integer(value_index
));
375 throw value_error("Not an integer");
381 /// \return A dynamically-allocated node.
382 config::detail::base_node
*
383 config::string_node::deep_copy(void) const
385 std::auto_ptr
< string_node
> new_node(new string_node());
386 new_node
->_value
= _value
;
387 return new_node
.release();
391 /// Pushes the node's value onto the Lua stack.
393 /// \param state The Lua state onto which to push the value.
395 config::string_node::push_lua(lutok::state
& state
) const
397 state
.push_string(value());
401 /// Sets the value of the node from an entry in the Lua stack.
403 /// \param state The Lua state from which to get the value.
404 /// \param value_index The stack index in which the value resides.
406 /// \throw value_error If the value in state(value_index) cannot be
407 /// processed by this node.
409 config::string_node::set_lua(lutok::state
& state
, const int value_index
)
411 if (state
.is_string(value_index
))
412 set(state
.to_string(value_index
));
414 throw value_error("Not a string");
420 /// \return A dynamically-allocated node.
421 config::detail::base_node
*
422 config::strings_set_node::deep_copy(void) const
424 std::auto_ptr
< strings_set_node
> new_node(new strings_set_node());
425 new_node
->_value
= _value
;
426 return new_node
.release();
430 /// Converts a single word to the native type.
432 /// \param raw_value The value to parse.
434 /// \return The parsed value.
436 config::strings_set_node::parse_one(const std::string
& raw_value
) const