1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
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.
16 //
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.
28
29 #include "utils/config/nodes.ipp"
30
31 #include <memory>
32
33 #include <lutok/state.ipp>
34
35 #include "utils/config/exceptions.hpp"
36 #include "utils/config/keys.hpp"
37 #include "utils/format/macros.hpp"
38
39 namespace config = utils::config;
40
41
42 /// Destructor.
~base_node(void)43 config::detail::base_node::~base_node(void)
44 {
45 }
46
47
48 /// Constructor.
49 ///
50 /// \param dynamic_ Whether the node is dynamic or not.
inner_node(const bool dynamic_)51 config::detail::inner_node::inner_node(const bool dynamic_) :
52 _dynamic(dynamic_)
53 {
54 }
55
56
57 /// Destructor.
~inner_node(void)58 config::detail::inner_node::~inner_node(void)
59 {
60 for (children_map::const_iterator iter = _children.begin();
61 iter != _children.end(); ++iter)
62 delete (*iter).second;
63 }
64
65
66 /// Fills the given node with a copy of this node's data.
67 ///
68 /// \param node The node to fill. Should be the fresh return value of a
69 /// deep_copy() operation.
70 void
copy_into(inner_node * node) const71 config::detail::inner_node::copy_into(inner_node* node) const
72 {
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();
77 try {
78 node->_children[(*iter).first] = new_node;
79 } catch (...) {
80 delete new_node;
81 throw;
82 }
83 }
84 }
85
86
87 /// Finds a node without creating it if not found.
88 ///
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).
93 ///
94 /// \param key The key to be queried.
95 /// \param key_pos The current level within the key to be examined.
96 ///
97 /// \return A reference to the located node, if successful.
98 ///
99 /// \throw unknown_key_error If the provided key is unknown.
100 const config::detail::base_node*
lookup_ro(const tree_key & key,const tree_key::size_type key_pos) const101 config::detail::inner_node::lookup_ro(const tree_key& key,
102 const tree_key::size_type key_pos) const
103 {
104 PRE(key_pos < key.size());
105
106 const children_map::const_iterator child_iter = _children.find(
107 key[key_pos]);
108 if (child_iter == _children.end())
109 throw unknown_key_error(key);
110
111 if (key_pos == key.size() - 1) {
112 return (*child_iter).second;
113 } else {
114 PRE(key_pos < key.size() - 1);
115 try {
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'");
122 }
123 }
124 }
125
126
127 /// Finds a node and creates it if not found.
128 ///
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.
133 ///
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.
139 ///
140 /// \return A reference to the located node, if successful.
141 ///
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
144 /// node.
145 config::leaf_node*
lookup_rw(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_node)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)
149 {
150 PRE(key_pos < key.size());
151
152 children_map::const_iterator child_iter = _children.find(key[key_pos]);
153 if (child_iter == _children.end()) {
154 if (_dynamic) {
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]);
160 } else {
161 throw unknown_key_error(key);
162 }
163 }
164
165 if (key_pos == key.size() - 1) {
166 try {
167 leaf_node& child = dynamic_cast< leaf_node& >(
168 *(*child_iter).second);
169 return &child;
170 } catch (const std::bad_cast& unused_error) {
171 throw value_error(F("Invalid value for key '%s'") %
172 flatten_key(key));
173 }
174 } else {
175 PRE(key_pos < key.size() - 1);
176 try {
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'");
183 }
184 }
185 }
186
187
188 /// Converts the subtree to a collection of key/value string pairs.
189 ///
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.
193 void
all_properties(properties_map & properties,const tree_key & key) const194 config::detail::inner_node::all_properties(properties_map& properties,
195 const tree_key& key) const
196 {
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);
201 try {
202 leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second);
203 if (child.is_set())
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);
208 }
209 }
210 }
211
212
213 /// Constructor.
static_inner_node(void)214 config::detail::static_inner_node::static_inner_node(void) :
215 inner_node(false)
216 {
217 }
218
219
220 /// Copies the node.
221 ///
222 /// \return A dynamically-allocated node.
223 config::detail::base_node*
deep_copy(void) const224 config::detail::static_inner_node::deep_copy(void) const
225 {
226 std::unique_ptr< inner_node > new_node(new static_inner_node());
227 copy_into(new_node.get());
228 return new_node.release();
229 }
230
231
232 /// Registers a key as valid and having a specific type.
233 ///
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.
238 ///
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
242 /// type.
243 void
define(const tree_key & key,const tree_key::size_type key_pos,new_node_hook new_node)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)
247 {
248 PRE(key_pos < key.size());
249
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()));
254 } else {
255 PRE(key_pos < key.size() - 1);
256 const children_map::const_iterator child_iter = _children.find(
257 key[key_pos]);
258
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);
263 } else {
264 try {
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) {
269 UNREACHABLE;
270 }
271 }
272 }
273 }
274
275
276 /// Constructor.
dynamic_inner_node(void)277 config::detail::dynamic_inner_node::dynamic_inner_node(void) :
278 inner_node(true)
279 {
280 }
281
282
283 /// Copies the node.
284 ///
285 /// \return A dynamically-allocated node.
286 config::detail::base_node*
deep_copy(void) const287 config::detail::dynamic_inner_node::deep_copy(void) const
288 {
289 std::unique_ptr< inner_node > new_node(new dynamic_inner_node());
290 copy_into(new_node.get());
291 return new_node.release();
292 }
293
294
295 /// Destructor.
~leaf_node(void)296 config::leaf_node::~leaf_node(void)
297 {
298 }
299
300
301 /// Copies the node.
302 ///
303 /// \return A dynamically-allocated node.
304 config::detail::base_node*
deep_copy(void) const305 config::bool_node::deep_copy(void) const
306 {
307 std::unique_ptr< bool_node > new_node(new bool_node());
308 new_node->_value = _value;
309 return new_node.release();
310 }
311
312
313 /// Pushes the node's value onto the Lua stack.
314 ///
315 /// \param state The Lua state onto which to push the value.
316 void
push_lua(lutok::state & state) const317 config::bool_node::push_lua(lutok::state& state) const
318 {
319 state.push_boolean(value());
320 }
321
322
323 /// Sets the value of the node from an entry in the Lua stack.
324 ///
325 /// \param state The Lua state from which to get the value.
326 /// \param value_index The stack index in which the value resides.
327 ///
328 /// \throw value_error If the value in state(value_index) cannot be
329 /// processed by this node.
330 void
set_lua(lutok::state & state,const int value_index)331 config::bool_node::set_lua(lutok::state& state, const int value_index)
332 {
333 if (state.is_boolean(value_index))
334 set(state.to_boolean(value_index));
335 else
336 throw value_error("Not a boolean");
337 }
338
339
340 /// Copies the node.
341 ///
342 /// \return A dynamically-allocated node.
343 config::detail::base_node*
deep_copy(void) const344 config::int_node::deep_copy(void) const
345 {
346 std::unique_ptr< int_node > new_node(new int_node());
347 new_node->_value = _value;
348 return new_node.release();
349 }
350
351
352 /// Pushes the node's value onto the Lua stack.
353 ///
354 /// \param state The Lua state onto which to push the value.
355 void
push_lua(lutok::state & state) const356 config::int_node::push_lua(lutok::state& state) const
357 {
358 state.push_integer(value());
359 }
360
361
362 /// Sets the value of the node from an entry in the Lua stack.
363 ///
364 /// \param state The Lua state from which to get the value.
365 /// \param value_index The stack index in which the value resides.
366 ///
367 /// \throw value_error If the value in state(value_index) cannot be
368 /// processed by this node.
369 void
set_lua(lutok::state & state,const int value_index)370 config::int_node::set_lua(lutok::state& state, const int value_index)
371 {
372 if (state.is_number(value_index))
373 set(state.to_integer(value_index));
374 else
375 throw value_error("Not an integer");
376 }
377
378
379 /// Copies the node.
380 ///
381 /// \return A dynamically-allocated node.
382 config::detail::base_node*
deep_copy(void) const383 config::string_node::deep_copy(void) const
384 {
385 std::unique_ptr< string_node > new_node(new string_node());
386 new_node->_value = _value;
387 return new_node.release();
388 }
389
390
391 /// Pushes the node's value onto the Lua stack.
392 ///
393 /// \param state The Lua state onto which to push the value.
394 void
push_lua(lutok::state & state) const395 config::string_node::push_lua(lutok::state& state) const
396 {
397 state.push_string(value());
398 }
399
400
401 /// Sets the value of the node from an entry in the Lua stack.
402 ///
403 /// \param state The Lua state from which to get the value.
404 /// \param value_index The stack index in which the value resides.
405 ///
406 /// \throw value_error If the value in state(value_index) cannot be
407 /// processed by this node.
408 void
set_lua(lutok::state & state,const int value_index)409 config::string_node::set_lua(lutok::state& state, const int value_index)
410 {
411 if (state.is_string(value_index))
412 set(state.to_string(value_index));
413 else
414 throw value_error("Not a string");
415 }
416
417
418 /// Copies the node.
419 ///
420 /// \return A dynamically-allocated node.
421 config::detail::base_node*
deep_copy(void) const422 config::strings_set_node::deep_copy(void) const
423 {
424 std::unique_ptr< strings_set_node > new_node(new strings_set_node());
425 new_node->_value = _value;
426 return new_node.release();
427 }
428
429
430 /// Converts a single word to the native type.
431 ///
432 /// \param raw_value The value to parse.
433 ///
434 /// \return The parsed value.
435 std::string
parse_one(const std::string & raw_value) const436 config::strings_set_node::parse_one(const std::string& raw_value) const
437 {
438 return raw_value;
439 }
440