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
39namespace config = utils::config;
40
41
42/// Destructor.
43config::detail::base_node::~base_node(void)
44{
45}
46
47
48/// Constructor.
49///
50/// \param dynamic_ Whether the node is dynamic or not.
51config::detail::inner_node::inner_node(const bool dynamic_) :
52    _dynamic(dynamic_)
53{
54}
55
56
57/// Destructor.
58config::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.
70void
71config::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.
100const config::detail::base_node*
101config::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.
145config::leaf_node*
146config::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.
193void
194config::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.
214config::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.
223config::detail::base_node*
224config::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.
243void
244config::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.
277config::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.
286config::detail::base_node*
287config::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.
296config::leaf_node::~leaf_node(void)
297{
298}
299
300
301/// Copies the node.
302///
303/// \return A dynamically-allocated node.
304config::detail::base_node*
305config::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.
316void
317config::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.
330void
331config::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.
343config::detail::base_node*
344config::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.
355void
356config::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.
369void
370config::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.
382config::detail::base_node*
383config::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.
394void
395config::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.
408void
409config::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.
421config::detail::base_node*
422config::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.
435std::string
436config::strings_set_node::parse_one(const std::string& raw_value) const
437{
438    return raw_value;
439}
440