1 // Copyright 2012 The Kyua Authors. 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 /// Combines two children sets, preferring the keys in the first set only. 88 /// 89 /// This operation is not symmetrical on c1 and c2. The caller is responsible 90 /// for invoking this twice so that the two key sets are combined if they happen 91 /// to differ. 92 /// 93 /// \param key Key to this node. 94 /// \param c1 First children set. 95 /// \param c2 First children set. 96 /// \param [in,out] node The node to combine into. 97 /// 98 /// \throw bad_combination_error If the two nodes cannot be combined. 99 void 100 config::detail::inner_node::combine_children_into( 101 const tree_key& key, 102 const children_map& c1, const children_map& c2, 103 inner_node* node) const 104 { 105 for (children_map::const_iterator iter1 = c1.begin(); 106 iter1 != c1.end(); ++iter1) { 107 const std::string& name = (*iter1).first; 108 109 if (node->_children.find(name) != node->_children.end()) { 110 continue; 111 } 112 113 std::auto_ptr< base_node > new_node; 114 115 children_map::const_iterator iter2 = c2.find(name); 116 if (iter2 == c2.end()) { 117 new_node.reset((*iter1).second->deep_copy()); 118 } else { 119 tree_key child_key = key; 120 child_key.push_back(name); 121 new_node.reset((*iter1).second->combine(child_key, 122 (*iter2).second)); 123 } 124 125 node->_children[name] = new_node.release(); 126 } 127 } 128 129 130 /// Combines this inner node with another inner node onto a new node. 131 /// 132 /// The "dynamic" property is inherited by the new node if either of the two 133 /// nodes are dynamic. 134 /// 135 /// \param key Key to this node. 136 /// \param other_base The node to combine with. 137 /// \param [in,out] node The node to combine into. 138 /// 139 /// \throw bad_combination_error If the two nodes cannot be combined. 140 void 141 config::detail::inner_node::combine_into(const tree_key& key, 142 const base_node* other_base, 143 inner_node* node) const 144 { 145 try { 146 const inner_node& other = dynamic_cast< const inner_node& >( 147 *other_base); 148 149 node->_dynamic = _dynamic || other._dynamic; 150 151 combine_children_into(key, _children, other._children, node); 152 combine_children_into(key, other._children, _children, node); 153 } catch (const std::bad_cast& unused_e) { 154 throw config::bad_combination_error( 155 key, "'%s' is an inner node in the base tree but a leaf node in " 156 "the overrides treee"); 157 } 158 } 159 160 161 /// Finds a node without creating it if not found. 162 /// 163 /// This recursive algorithm traverses the tree searching for a particular key. 164 /// The returned node is constant, so this can only be used for querying 165 /// purposes. For this reason, this algorithm does not create intermediate 166 /// nodes if they don't exist (as would be necessary to set a new node). 167 /// 168 /// \param key The key to be queried. 169 /// \param key_pos The current level within the key to be examined. 170 /// 171 /// \return A reference to the located node, if successful. 172 /// 173 /// \throw unknown_key_error If the provided key is unknown. 174 const config::detail::base_node* 175 config::detail::inner_node::lookup_ro(const tree_key& key, 176 const tree_key::size_type key_pos) const 177 { 178 PRE(key_pos < key.size()); 179 180 const children_map::const_iterator child_iter = _children.find( 181 key[key_pos]); 182 if (child_iter == _children.end()) 183 throw unknown_key_error(key); 184 185 if (key_pos == key.size() - 1) { 186 return (*child_iter).second; 187 } else { 188 PRE(key_pos < key.size() - 1); 189 try { 190 const inner_node& child = dynamic_cast< const inner_node& >( 191 *(*child_iter).second); 192 return child.lookup_ro(key, key_pos + 1); 193 } catch (const std::bad_cast& e) { 194 throw unknown_key_error( 195 key, "Cannot address incomplete configuration property '%s'"); 196 } 197 } 198 } 199 200 201 /// Finds a node and creates it if not found. 202 /// 203 /// This recursive algorithm traverses the tree searching for a particular key, 204 /// creating any intermediate nodes if they do not already exist (for the case 205 /// of dynamic inner nodes). The returned node is non-constant, so this can be 206 /// used by the algorithms that set key values. 207 /// 208 /// \param key The key to be queried. 209 /// \param key_pos The current level within the key to be examined. 210 /// \param new_node A function that returns a new leaf node of the desired 211 /// type. This is only called if the leaf cannot be found, but it has 212 /// already been defined. 213 /// 214 /// \return A reference to the located node, if successful. 215 /// 216 /// \throw invalid_key_value If the resulting node of the search would be an 217 /// inner node. 218 /// \throw unknown_key_error If the provided key is unknown. 219 config::leaf_node* 220 config::detail::inner_node::lookup_rw(const tree_key& key, 221 const tree_key::size_type key_pos, 222 new_node_hook new_node) 223 { 224 PRE(key_pos < key.size()); 225 226 children_map::const_iterator child_iter = _children.find(key[key_pos]); 227 if (child_iter == _children.end()) { 228 if (_dynamic) { 229 base_node* const child = (key_pos == key.size() - 1) ? 230 static_cast< base_node* >(new_node()) : 231 static_cast< base_node* >(new dynamic_inner_node()); 232 _children.insert(children_map::value_type(key[key_pos], child)); 233 child_iter = _children.find(key[key_pos]); 234 } else { 235 throw unknown_key_error(key); 236 } 237 } 238 239 if (key_pos == key.size() - 1) { 240 try { 241 leaf_node& child = dynamic_cast< leaf_node& >( 242 *(*child_iter).second); 243 return &child; 244 } catch (const std::bad_cast& unused_error) { 245 throw invalid_key_value(key, "Type mismatch"); 246 } 247 } else { 248 PRE(key_pos < key.size() - 1); 249 try { 250 inner_node& child = dynamic_cast< inner_node& >( 251 *(*child_iter).second); 252 return child.lookup_rw(key, key_pos + 1, new_node); 253 } catch (const std::bad_cast& e) { 254 throw unknown_key_error( 255 key, "Cannot address incomplete configuration property '%s'"); 256 } 257 } 258 } 259 260 261 /// Converts the subtree to a collection of key/value string pairs. 262 /// 263 /// \param [out] properties The accumulator for the generated properties. The 264 /// contents of the map are only extended. 265 /// \param key The path to the current node. 266 void 267 config::detail::inner_node::all_properties(properties_map& properties, 268 const tree_key& key) const 269 { 270 for (children_map::const_iterator iter = _children.begin(); 271 iter != _children.end(); ++iter) { 272 tree_key child_key = key; 273 child_key.push_back((*iter).first); 274 try { 275 leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second); 276 if (child.is_set()) 277 properties[flatten_key(child_key)] = child.to_string(); 278 } catch (const std::bad_cast& unused_error) { 279 inner_node& child = dynamic_cast< inner_node& >(*(*iter).second); 280 child.all_properties(properties, child_key); 281 } 282 } 283 } 284 285 286 /// Constructor. 287 config::detail::static_inner_node::static_inner_node(void) : 288 inner_node(false) 289 { 290 } 291 292 293 /// Copies the node. 294 /// 295 /// \return A dynamically-allocated node. 296 config::detail::base_node* 297 config::detail::static_inner_node::deep_copy(void) const 298 { 299 std::auto_ptr< inner_node > new_node(new static_inner_node()); 300 copy_into(new_node.get()); 301 return new_node.release(); 302 } 303 304 305 /// Combines this node with another one. 306 /// 307 /// \param key Key to this node. 308 /// \param other The node to combine with. 309 /// 310 /// \return A new node representing the combination. 311 /// 312 /// \throw bad_combination_error If the two nodes cannot be combined. 313 config::detail::base_node* 314 config::detail::static_inner_node::combine(const tree_key& key, 315 const base_node* other) const 316 { 317 std::auto_ptr< inner_node > new_node(new static_inner_node()); 318 combine_into(key, other, new_node.get()); 319 return new_node.release(); 320 } 321 322 323 /// Registers a key as valid and having a specific type. 324 /// 325 /// This method does not raise errors on invalid/unknown keys or other 326 /// tree-related issues. The reasons is that define() is a method that does not 327 /// depend on user input: it is intended to pre-populate the tree with a 328 /// specific structure, and that happens once at coding time. 329 /// 330 /// \param key The key to be registered. 331 /// \param key_pos The current level within the key to be examined. 332 /// \param new_node A function that returns a new leaf node of the desired 333 /// type. 334 void 335 config::detail::static_inner_node::define(const tree_key& key, 336 const tree_key::size_type key_pos, 337 new_node_hook new_node) 338 { 339 PRE(key_pos < key.size()); 340 341 if (key_pos == key.size() - 1) { 342 PRE_MSG(_children.find(key[key_pos]) == _children.end(), 343 "Key already defined"); 344 _children.insert(children_map::value_type(key[key_pos], new_node())); 345 } else { 346 PRE(key_pos < key.size() - 1); 347 const children_map::const_iterator child_iter = _children.find( 348 key[key_pos]); 349 350 if (child_iter == _children.end()) { 351 static_inner_node* const child_ptr = new static_inner_node(); 352 _children.insert(children_map::value_type(key[key_pos], child_ptr)); 353 child_ptr->define(key, key_pos + 1, new_node); 354 } else { 355 try { 356 static_inner_node& child = dynamic_cast< static_inner_node& >( 357 *(*child_iter).second); 358 child.define(key, key_pos + 1, new_node); 359 } catch (const std::bad_cast& e) { 360 UNREACHABLE; 361 } 362 } 363 } 364 } 365 366 367 /// Constructor. 368 config::detail::dynamic_inner_node::dynamic_inner_node(void) : 369 inner_node(true) 370 { 371 } 372 373 374 /// Copies the node. 375 /// 376 /// \return A dynamically-allocated node. 377 config::detail::base_node* 378 config::detail::dynamic_inner_node::deep_copy(void) const 379 { 380 std::auto_ptr< inner_node > new_node(new dynamic_inner_node()); 381 copy_into(new_node.get()); 382 return new_node.release(); 383 } 384 385 386 /// Combines this node with another one. 387 /// 388 /// \param key Key to this node. 389 /// \param other The node to combine with. 390 /// 391 /// \return A new node representing the combination. 392 /// 393 /// \throw bad_combination_error If the two nodes cannot be combined. 394 config::detail::base_node* 395 config::detail::dynamic_inner_node::combine(const tree_key& key, 396 const base_node* other) const 397 { 398 std::auto_ptr< inner_node > new_node(new dynamic_inner_node()); 399 combine_into(key, other, new_node.get()); 400 return new_node.release(); 401 } 402 403 404 /// Destructor. 405 config::leaf_node::~leaf_node(void) 406 { 407 } 408 409 410 /// Combines this node with another one. 411 /// 412 /// \param key Key to this node. 413 /// \param other_base The node to combine with. 414 /// 415 /// \return A new node representing the combination. 416 /// 417 /// \throw bad_combination_error If the two nodes cannot be combined. 418 config::detail::base_node* 419 config::leaf_node::combine(const detail::tree_key& key, 420 const base_node* other_base) const 421 { 422 try { 423 const leaf_node& other = dynamic_cast< const leaf_node& >(*other_base); 424 425 if (other.is_set()) { 426 return other.deep_copy(); 427 } else { 428 return deep_copy(); 429 } 430 } catch (const std::bad_cast& unused_e) { 431 throw config::bad_combination_error( 432 key, "'%s' is a leaf node in the base tree but an inner node in " 433 "the overrides treee"); 434 } 435 } 436 437 438 /// Copies the node. 439 /// 440 /// \return A dynamically-allocated node. 441 config::detail::base_node* 442 config::bool_node::deep_copy(void) const 443 { 444 std::auto_ptr< bool_node > new_node(new bool_node()); 445 new_node->_value = _value; 446 return new_node.release(); 447 } 448 449 450 /// Pushes the node's value onto the Lua stack. 451 /// 452 /// \param state The Lua state onto which to push the value. 453 void 454 config::bool_node::push_lua(lutok::state& state) const 455 { 456 state.push_boolean(value()); 457 } 458 459 460 /// Sets the value of the node from an entry in the Lua stack. 461 /// 462 /// \param state The Lua state from which to get the value. 463 /// \param value_index The stack index in which the value resides. 464 /// 465 /// \throw value_error If the value in state(value_index) cannot be 466 /// processed by this node. 467 void 468 config::bool_node::set_lua(lutok::state& state, const int value_index) 469 { 470 if (state.is_boolean(value_index)) 471 set(state.to_boolean(value_index)); 472 else 473 throw value_error("Not a boolean"); 474 } 475 476 477 /// Copies the node. 478 /// 479 /// \return A dynamically-allocated node. 480 config::detail::base_node* 481 config::int_node::deep_copy(void) const 482 { 483 std::auto_ptr< int_node > new_node(new int_node()); 484 new_node->_value = _value; 485 return new_node.release(); 486 } 487 488 489 /// Pushes the node's value onto the Lua stack. 490 /// 491 /// \param state The Lua state onto which to push the value. 492 void 493 config::int_node::push_lua(lutok::state& state) const 494 { 495 state.push_integer(value()); 496 } 497 498 499 /// Sets the value of the node from an entry in the Lua stack. 500 /// 501 /// \param state The Lua state from which to get the value. 502 /// \param value_index The stack index in which the value resides. 503 /// 504 /// \throw value_error If the value in state(value_index) cannot be 505 /// processed by this node. 506 void 507 config::int_node::set_lua(lutok::state& state, const int value_index) 508 { 509 if (state.is_number(value_index)) 510 set(state.to_integer(value_index)); 511 else 512 throw value_error("Not an integer"); 513 } 514 515 516 /// Checks a given value for validity. 517 /// 518 /// \param new_value The value to validate. 519 /// 520 /// \throw value_error If the value is not valid. 521 void 522 config::positive_int_node::validate(const value_type& new_value) const 523 { 524 if (new_value <= 0) 525 throw value_error("Must be a positive integer"); 526 } 527 528 529 /// Copies the node. 530 /// 531 /// \return A dynamically-allocated node. 532 config::detail::base_node* 533 config::string_node::deep_copy(void) const 534 { 535 std::auto_ptr< string_node > new_node(new string_node()); 536 new_node->_value = _value; 537 return new_node.release(); 538 } 539 540 541 /// Pushes the node's value onto the Lua stack. 542 /// 543 /// \param state The Lua state onto which to push the value. 544 void 545 config::string_node::push_lua(lutok::state& state) const 546 { 547 state.push_string(value()); 548 } 549 550 551 /// Sets the value of the node from an entry in the Lua stack. 552 /// 553 /// \param state The Lua state from which to get the value. 554 /// \param value_index The stack index in which the value resides. 555 /// 556 /// \throw value_error If the value in state(value_index) cannot be 557 /// processed by this node. 558 void 559 config::string_node::set_lua(lutok::state& state, const int value_index) 560 { 561 if (state.is_string(value_index)) 562 set(state.to_string(value_index)); 563 else 564 throw value_error("Not a string"); 565 } 566 567 568 /// Copies the node. 569 /// 570 /// \return A dynamically-allocated node. 571 config::detail::base_node* 572 config::strings_set_node::deep_copy(void) const 573 { 574 std::auto_ptr< strings_set_node > new_node(new strings_set_node()); 575 new_node->_value = _value; 576 return new_node.release(); 577 } 578 579 580 /// Converts a single word to the native type. 581 /// 582 /// \param raw_value The value to parse. 583 /// 584 /// \return The parsed value. 585 std::string 586 config::strings_set_node::parse_one(const std::string& raw_value) const 587 { 588 return raw_value; 589 } 590