Home | History | Annotate | Line # | Download | only in config
tree.cpp revision 1.1.1.1.12.2
      1  1.1.1.1.12.2  yamt // Copyright 2012 Google Inc.
      2  1.1.1.1.12.2  yamt // All rights reserved.
      3  1.1.1.1.12.2  yamt //
      4  1.1.1.1.12.2  yamt // Redistribution and use in source and binary forms, with or without
      5  1.1.1.1.12.2  yamt // modification, are permitted provided that the following conditions are
      6  1.1.1.1.12.2  yamt // met:
      7  1.1.1.1.12.2  yamt //
      8  1.1.1.1.12.2  yamt // * Redistributions of source code must retain the above copyright
      9  1.1.1.1.12.2  yamt //   notice, this list of conditions and the following disclaimer.
     10  1.1.1.1.12.2  yamt // * Redistributions in binary form must reproduce the above copyright
     11  1.1.1.1.12.2  yamt //   notice, this list of conditions and the following disclaimer in the
     12  1.1.1.1.12.2  yamt //   documentation and/or other materials provided with the distribution.
     13  1.1.1.1.12.2  yamt // * Neither the name of Google Inc. nor the names of its contributors
     14  1.1.1.1.12.2  yamt //   may be used to endorse or promote products derived from this software
     15  1.1.1.1.12.2  yamt //   without specific prior written permission.
     16  1.1.1.1.12.2  yamt //
     17  1.1.1.1.12.2  yamt // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18  1.1.1.1.12.2  yamt // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19  1.1.1.1.12.2  yamt // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20  1.1.1.1.12.2  yamt // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21  1.1.1.1.12.2  yamt // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22  1.1.1.1.12.2  yamt // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23  1.1.1.1.12.2  yamt // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  1.1.1.1.12.2  yamt // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  1.1.1.1.12.2  yamt // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  1.1.1.1.12.2  yamt // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27  1.1.1.1.12.2  yamt // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  1.1.1.1.12.2  yamt 
     29  1.1.1.1.12.2  yamt #include "utils/config/tree.ipp"
     30  1.1.1.1.12.2  yamt 
     31  1.1.1.1.12.2  yamt #include "utils/config/exceptions.hpp"
     32  1.1.1.1.12.2  yamt #include "utils/config/keys.hpp"
     33  1.1.1.1.12.2  yamt #include "utils/config/nodes.ipp"
     34  1.1.1.1.12.2  yamt #include "utils/format/macros.hpp"
     35  1.1.1.1.12.2  yamt 
     36  1.1.1.1.12.2  yamt namespace config = utils::config;
     37  1.1.1.1.12.2  yamt 
     38  1.1.1.1.12.2  yamt 
     39  1.1.1.1.12.2  yamt /// Constructor.
     40  1.1.1.1.12.2  yamt config::tree::tree(void) :
     41  1.1.1.1.12.2  yamt     _root(new detail::static_inner_node())
     42  1.1.1.1.12.2  yamt {
     43  1.1.1.1.12.2  yamt }
     44  1.1.1.1.12.2  yamt 
     45  1.1.1.1.12.2  yamt 
     46  1.1.1.1.12.2  yamt /// Constructor with a non-empty root.
     47  1.1.1.1.12.2  yamt ///
     48  1.1.1.1.12.2  yamt /// \param root The root to the tree to be owned by this instance.
     49  1.1.1.1.12.2  yamt config::tree::tree(detail::static_inner_node* root) :
     50  1.1.1.1.12.2  yamt     _root(root)
     51  1.1.1.1.12.2  yamt {
     52  1.1.1.1.12.2  yamt }
     53  1.1.1.1.12.2  yamt 
     54  1.1.1.1.12.2  yamt 
     55  1.1.1.1.12.2  yamt /// Destructor.
     56  1.1.1.1.12.2  yamt config::tree::~tree(void)
     57  1.1.1.1.12.2  yamt {
     58  1.1.1.1.12.2  yamt }
     59  1.1.1.1.12.2  yamt 
     60  1.1.1.1.12.2  yamt 
     61  1.1.1.1.12.2  yamt /// Generates a deep copy of the input tree.
     62  1.1.1.1.12.2  yamt ///
     63  1.1.1.1.12.2  yamt /// \return A new tree that is an exact copy of this tree.
     64  1.1.1.1.12.2  yamt config::tree
     65  1.1.1.1.12.2  yamt config::tree::deep_copy(void) const
     66  1.1.1.1.12.2  yamt {
     67  1.1.1.1.12.2  yamt     detail::static_inner_node* new_root =
     68  1.1.1.1.12.2  yamt         dynamic_cast< detail::static_inner_node* >(_root->deep_copy());
     69  1.1.1.1.12.2  yamt     return config::tree(new_root);
     70  1.1.1.1.12.2  yamt }
     71  1.1.1.1.12.2  yamt 
     72  1.1.1.1.12.2  yamt 
     73  1.1.1.1.12.2  yamt /// Registers a node as being dynamic.
     74  1.1.1.1.12.2  yamt ///
     75  1.1.1.1.12.2  yamt /// This operation creates the given key as an inner node.  Further set
     76  1.1.1.1.12.2  yamt /// operations that trespass this node will automatically create any missing
     77  1.1.1.1.12.2  yamt /// keys.
     78  1.1.1.1.12.2  yamt ///
     79  1.1.1.1.12.2  yamt /// This method does not raise errors on invalid/unknown keys or other
     80  1.1.1.1.12.2  yamt /// tree-related issues.  The reasons is that define() is a method that does not
     81  1.1.1.1.12.2  yamt /// depend on user input: it is intended to pre-populate the tree with a
     82  1.1.1.1.12.2  yamt /// specific structure, and that happens once at coding time.
     83  1.1.1.1.12.2  yamt ///
     84  1.1.1.1.12.2  yamt /// \param dotted_key The key to be registered in dotted representation.
     85  1.1.1.1.12.2  yamt void
     86  1.1.1.1.12.2  yamt config::tree::define_dynamic(const std::string& dotted_key)
     87  1.1.1.1.12.2  yamt {
     88  1.1.1.1.12.2  yamt     try {
     89  1.1.1.1.12.2  yamt         const detail::tree_key key = detail::parse_key(dotted_key);
     90  1.1.1.1.12.2  yamt         _root->define(key, 0, detail::new_node< detail::dynamic_inner_node >);
     91  1.1.1.1.12.2  yamt     } catch (const error& e) {
     92  1.1.1.1.12.2  yamt         UNREACHABLE_MSG("define() failing due to key errors is a programming "
     93  1.1.1.1.12.2  yamt                         "mistake: " + std::string(e.what()));
     94  1.1.1.1.12.2  yamt     }
     95  1.1.1.1.12.2  yamt }
     96  1.1.1.1.12.2  yamt 
     97  1.1.1.1.12.2  yamt 
     98  1.1.1.1.12.2  yamt /// Checks if a given node is set.
     99  1.1.1.1.12.2  yamt ///
    100  1.1.1.1.12.2  yamt /// \param dotted_key The key to be checked.
    101  1.1.1.1.12.2  yamt ///
    102  1.1.1.1.12.2  yamt /// \return True if the key is set to a specific value (not just defined).
    103  1.1.1.1.12.2  yamt /// False if the key is not set or if the key does not exist.
    104  1.1.1.1.12.2  yamt ///
    105  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    106  1.1.1.1.12.2  yamt bool
    107  1.1.1.1.12.2  yamt config::tree::is_set(const std::string& dotted_key) const
    108  1.1.1.1.12.2  yamt {
    109  1.1.1.1.12.2  yamt     const detail::tree_key key = detail::parse_key(dotted_key);
    110  1.1.1.1.12.2  yamt     try {
    111  1.1.1.1.12.2  yamt         const detail::base_node* raw_node = _root->lookup_ro(key, 0);
    112  1.1.1.1.12.2  yamt         try {
    113  1.1.1.1.12.2  yamt             const leaf_node& child = dynamic_cast< const leaf_node& >(
    114  1.1.1.1.12.2  yamt                 *raw_node);
    115  1.1.1.1.12.2  yamt             return child.is_set();
    116  1.1.1.1.12.2  yamt         } catch (const std::bad_cast& unused_error) {
    117  1.1.1.1.12.2  yamt             return false;
    118  1.1.1.1.12.2  yamt         }
    119  1.1.1.1.12.2  yamt     } catch (const unknown_key_error& unused_error) {
    120  1.1.1.1.12.2  yamt         return false;
    121  1.1.1.1.12.2  yamt     }
    122  1.1.1.1.12.2  yamt }
    123  1.1.1.1.12.2  yamt 
    124  1.1.1.1.12.2  yamt 
    125  1.1.1.1.12.2  yamt /// Pushes a leaf node's value onto the Lua stack.
    126  1.1.1.1.12.2  yamt ///
    127  1.1.1.1.12.2  yamt /// \param dotted_key The key to be pushed.
    128  1.1.1.1.12.2  yamt /// \param state The Lua state into which to push the key's value.
    129  1.1.1.1.12.2  yamt ///
    130  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    131  1.1.1.1.12.2  yamt /// \throw unknown_key_error If the provided key is unknown.
    132  1.1.1.1.12.2  yamt void
    133  1.1.1.1.12.2  yamt config::tree::push_lua(const std::string& dotted_key, lutok::state& state) const
    134  1.1.1.1.12.2  yamt {
    135  1.1.1.1.12.2  yamt     const detail::tree_key key = detail::parse_key(dotted_key);
    136  1.1.1.1.12.2  yamt     const detail::base_node* raw_node = _root->lookup_ro(key, 0);
    137  1.1.1.1.12.2  yamt     try {
    138  1.1.1.1.12.2  yamt         const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
    139  1.1.1.1.12.2  yamt         child.push_lua(state);
    140  1.1.1.1.12.2  yamt     } catch (const std::bad_cast& unused_error) {
    141  1.1.1.1.12.2  yamt         throw unknown_key_error(key);
    142  1.1.1.1.12.2  yamt     }
    143  1.1.1.1.12.2  yamt }
    144  1.1.1.1.12.2  yamt 
    145  1.1.1.1.12.2  yamt 
    146  1.1.1.1.12.2  yamt /// Sets a leaf node's value from a value in the Lua stack.
    147  1.1.1.1.12.2  yamt ///
    148  1.1.1.1.12.2  yamt /// \param dotted_key The key to be set.
    149  1.1.1.1.12.2  yamt /// \param state The Lua state from which to retrieve the value.
    150  1.1.1.1.12.2  yamt /// \param value_index The position in the Lua stack holding the value.
    151  1.1.1.1.12.2  yamt ///
    152  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    153  1.1.1.1.12.2  yamt /// \throw unknown_key_error If the provided key is unknown.
    154  1.1.1.1.12.2  yamt /// \throw value_error If the value mismatches the node type.
    155  1.1.1.1.12.2  yamt void
    156  1.1.1.1.12.2  yamt config::tree::set_lua(const std::string& dotted_key, lutok::state& state,
    157  1.1.1.1.12.2  yamt                       const int value_index)
    158  1.1.1.1.12.2  yamt {
    159  1.1.1.1.12.2  yamt     const detail::tree_key key = detail::parse_key(dotted_key);
    160  1.1.1.1.12.2  yamt     detail::base_node* raw_node = _root->lookup_rw(
    161  1.1.1.1.12.2  yamt         key, 0, detail::new_node< string_node >);
    162  1.1.1.1.12.2  yamt     try {
    163  1.1.1.1.12.2  yamt         leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
    164  1.1.1.1.12.2  yamt         child.set_lua(state, value_index);
    165  1.1.1.1.12.2  yamt     } catch (const std::bad_cast& unused_error) {
    166  1.1.1.1.12.2  yamt         throw value_error(F("Invalid value for key '%s'") %
    167  1.1.1.1.12.2  yamt                           detail::flatten_key(key));
    168  1.1.1.1.12.2  yamt     }
    169  1.1.1.1.12.2  yamt }
    170  1.1.1.1.12.2  yamt 
    171  1.1.1.1.12.2  yamt 
    172  1.1.1.1.12.2  yamt /// Gets the value of a node as a plain string.
    173  1.1.1.1.12.2  yamt ///
    174  1.1.1.1.12.2  yamt /// \param dotted_key The key to be looked up.
    175  1.1.1.1.12.2  yamt ///
    176  1.1.1.1.12.2  yamt /// \return The value of the located node as a string.
    177  1.1.1.1.12.2  yamt ///
    178  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    179  1.1.1.1.12.2  yamt /// \throw unknown_key_error If the provided key is unknown.
    180  1.1.1.1.12.2  yamt std::string
    181  1.1.1.1.12.2  yamt config::tree::lookup_string(const std::string& dotted_key) const
    182  1.1.1.1.12.2  yamt {
    183  1.1.1.1.12.2  yamt     const detail::tree_key key = detail::parse_key(dotted_key);
    184  1.1.1.1.12.2  yamt     const detail::base_node* raw_node = _root->lookup_ro(key, 0);
    185  1.1.1.1.12.2  yamt     try {
    186  1.1.1.1.12.2  yamt         const leaf_node& child = dynamic_cast< const leaf_node& >(*raw_node);
    187  1.1.1.1.12.2  yamt         return child.to_string();
    188  1.1.1.1.12.2  yamt     } catch (const std::bad_cast& unused_error) {
    189  1.1.1.1.12.2  yamt         throw unknown_key_error(key);
    190  1.1.1.1.12.2  yamt     }
    191  1.1.1.1.12.2  yamt }
    192  1.1.1.1.12.2  yamt 
    193  1.1.1.1.12.2  yamt 
    194  1.1.1.1.12.2  yamt /// Sets the value of a leaf addressed by its key from a string value.
    195  1.1.1.1.12.2  yamt ///
    196  1.1.1.1.12.2  yamt /// This respects the native types of all the nodes that have been predefined.
    197  1.1.1.1.12.2  yamt /// For new nodes under a dynamic subtree, this has no mechanism of determining
    198  1.1.1.1.12.2  yamt /// what type they need to have, so they are created as plain string nodes.
    199  1.1.1.1.12.2  yamt ///
    200  1.1.1.1.12.2  yamt /// \param dotted_key The key to be registered in dotted representation.
    201  1.1.1.1.12.2  yamt /// \param raw_value The string representation of the value to set the node to.
    202  1.1.1.1.12.2  yamt ///
    203  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    204  1.1.1.1.12.2  yamt /// \throw unknown_key_error If the provided key is unknown.
    205  1.1.1.1.12.2  yamt /// \throw value_error If the value mismatches the node type.
    206  1.1.1.1.12.2  yamt void
    207  1.1.1.1.12.2  yamt config::tree::set_string(const std::string& dotted_key,
    208  1.1.1.1.12.2  yamt                          const std::string& raw_value)
    209  1.1.1.1.12.2  yamt {
    210  1.1.1.1.12.2  yamt     const detail::tree_key key = detail::parse_key(dotted_key);
    211  1.1.1.1.12.2  yamt     detail::base_node* raw_node = _root->lookup_rw(
    212  1.1.1.1.12.2  yamt         key, 0, detail::new_node< string_node >);
    213  1.1.1.1.12.2  yamt     try {
    214  1.1.1.1.12.2  yamt         leaf_node& child = dynamic_cast< leaf_node& >(*raw_node);
    215  1.1.1.1.12.2  yamt         child.set_string(raw_value);
    216  1.1.1.1.12.2  yamt     } catch (const std::bad_cast& unused_error) {
    217  1.1.1.1.12.2  yamt         throw value_error(F("Invalid value for key '%s'") %
    218  1.1.1.1.12.2  yamt                           detail::flatten_key(key));
    219  1.1.1.1.12.2  yamt     }
    220  1.1.1.1.12.2  yamt }
    221  1.1.1.1.12.2  yamt 
    222  1.1.1.1.12.2  yamt 
    223  1.1.1.1.12.2  yamt /// Converts the tree to a collection of key/value string pairs.
    224  1.1.1.1.12.2  yamt ///
    225  1.1.1.1.12.2  yamt /// \param dotted_key Subtree from which to start the export.
    226  1.1.1.1.12.2  yamt /// \param strip_key If true, remove the dotted_key prefix from the resulting
    227  1.1.1.1.12.2  yamt ///     properties.
    228  1.1.1.1.12.2  yamt ///
    229  1.1.1.1.12.2  yamt /// \return A map of keys to values in their textual representation.
    230  1.1.1.1.12.2  yamt ///
    231  1.1.1.1.12.2  yamt /// \throw invalid_key_error If the provided key has an invalid format.
    232  1.1.1.1.12.2  yamt /// \throw unknown_key_error If the provided key is unknown.
    233  1.1.1.1.12.2  yamt /// \throw value_error If the provided key points to a leaf.
    234  1.1.1.1.12.2  yamt config::properties_map
    235  1.1.1.1.12.2  yamt config::tree::all_properties(const std::string& dotted_key,
    236  1.1.1.1.12.2  yamt                              const bool strip_key) const
    237  1.1.1.1.12.2  yamt {
    238  1.1.1.1.12.2  yamt     PRE(!strip_key || !dotted_key.empty());
    239  1.1.1.1.12.2  yamt 
    240  1.1.1.1.12.2  yamt     properties_map properties;
    241  1.1.1.1.12.2  yamt 
    242  1.1.1.1.12.2  yamt     detail::tree_key key;
    243  1.1.1.1.12.2  yamt     const detail::base_node* raw_node;
    244  1.1.1.1.12.2  yamt     if (dotted_key.empty()) {
    245  1.1.1.1.12.2  yamt         raw_node = _root.get();
    246  1.1.1.1.12.2  yamt     } else {
    247  1.1.1.1.12.2  yamt         key = detail::parse_key(dotted_key);
    248  1.1.1.1.12.2  yamt         raw_node = _root->lookup_ro(key, 0);
    249  1.1.1.1.12.2  yamt     }
    250  1.1.1.1.12.2  yamt     try {
    251  1.1.1.1.12.2  yamt         const detail::inner_node& child =
    252  1.1.1.1.12.2  yamt             dynamic_cast< const detail::inner_node& >(*raw_node);
    253  1.1.1.1.12.2  yamt         child.all_properties(properties, key);
    254  1.1.1.1.12.2  yamt     } catch (const std::bad_cast& unused_error) {
    255  1.1.1.1.12.2  yamt         INV(!dotted_key.empty());
    256  1.1.1.1.12.2  yamt         throw value_error(F("Cannot export properties from a leaf node; "
    257  1.1.1.1.12.2  yamt                             "'%s' given") % dotted_key);
    258  1.1.1.1.12.2  yamt     }
    259  1.1.1.1.12.2  yamt 
    260  1.1.1.1.12.2  yamt     if (strip_key) {
    261  1.1.1.1.12.2  yamt         properties_map stripped;
    262  1.1.1.1.12.2  yamt         for (properties_map::const_iterator iter = properties.begin();
    263  1.1.1.1.12.2  yamt              iter != properties.end(); ++iter) {
    264  1.1.1.1.12.2  yamt             stripped[(*iter).first.substr(dotted_key.length() + 1)] =
    265  1.1.1.1.12.2  yamt                 (*iter).second;
    266  1.1.1.1.12.2  yamt         }
    267  1.1.1.1.12.2  yamt         properties = stripped;
    268  1.1.1.1.12.2  yamt     }
    269  1.1.1.1.12.2  yamt 
    270  1.1.1.1.12.2  yamt     return properties;
    271  1.1.1.1.12.2  yamt }
    272  1.1.1.1.12.2  yamt 
    273  1.1.1.1.12.2  yamt 
    274  1.1.1.1.12.2  yamt /// Equality comparator.
    275  1.1.1.1.12.2  yamt ///
    276  1.1.1.1.12.2  yamt /// \param other The other object to compare this one to.
    277  1.1.1.1.12.2  yamt ///
    278  1.1.1.1.12.2  yamt /// \return True if this object and other are equal; false otherwise.
    279  1.1.1.1.12.2  yamt bool
    280  1.1.1.1.12.2  yamt config::tree::operator==(const tree& other) const
    281  1.1.1.1.12.2  yamt {
    282  1.1.1.1.12.2  yamt     // TODO(jmmv): Would be nicer to perform the comparison directly on the
    283  1.1.1.1.12.2  yamt     // nodes, instead of exporting the values to strings first.
    284  1.1.1.1.12.2  yamt     return _root == other._root || all_properties() == other.all_properties();
    285  1.1.1.1.12.2  yamt }
    286  1.1.1.1.12.2  yamt 
    287  1.1.1.1.12.2  yamt 
    288  1.1.1.1.12.2  yamt /// Inequality comparator.
    289  1.1.1.1.12.2  yamt ///
    290  1.1.1.1.12.2  yamt /// \param other The other object to compare this one to.
    291  1.1.1.1.12.2  yamt ///
    292  1.1.1.1.12.2  yamt /// \return True if this object and other are different; false otherwise.
    293  1.1.1.1.12.2  yamt bool
    294  1.1.1.1.12.2  yamt config::tree::operator!=(const tree& other) const
    295  1.1.1.1.12.2  yamt {
    296  1.1.1.1.12.2  yamt     return !(*this == other);
    297  1.1.1.1.12.2  yamt }
    298