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