Home | History | Annotate | Line # | Download | only in config
      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.
     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.
     51 config::detail::inner_node::inner_node(const bool dynamic_) :
     52     _dynamic(dynamic_)
     53 {
     54 }
     55 
     56 
     57 /// Destructor.
     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
     71 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*
    101 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*
    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
    194 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.
    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*
    224 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
    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.
    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*
    287 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.
    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*
    305 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
    317 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
    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*
    344 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
    356 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
    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*
    383 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
    395 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
    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*
    422 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
    436 config::strings_set_node::parse_one(const std::string& raw_value) const
    437 {
    438     return raw_value;
    439 }
    440