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::unique_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 tree"); 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 dynamic_cast< base_node* >(new_node()) : 231 dynamic_cast< base_node* >(new dynamic_inner_node()); 232 // The types for `new_node` 233 INV_MSG(child != nullptr, "check the return type for the function called"); 234 _children.insert(children_map::value_type(key[key_pos], child)); 235 child_iter = _children.find(key[key_pos]); 236 } else { 237 throw unknown_key_error(key); 238 } 239 } 240 241 if (key_pos == key.size() - 1) { 242 try { 243 leaf_node& child = dynamic_cast< leaf_node& >( 244 *(*child_iter).second); 245 return &child; 246 } catch (const std::bad_cast& unused_error) { 247 throw invalid_key_value(key, "Type mismatch"); 248 } 249 } else { 250 PRE(key_pos < key.size() - 1); 251 try { 252 inner_node& child = dynamic_cast< inner_node& >( 253 *(*child_iter).second); 254 return child.lookup_rw(key, key_pos + 1, new_node); 255 } catch (const std::bad_cast& e) { 256 throw unknown_key_error( 257 key, "Cannot address incomplete configuration property '%s'"); 258 } 259 } 260 } 261 262 263 /// Converts the subtree to a collection of key/value string pairs. 264 /// 265 /// \param [out] properties The accumulator for the generated properties. The 266 /// contents of the map are only extended. 267 /// \param key The path to the current node. 268 void 269 config::detail::inner_node::all_properties(properties_map& properties, 270 const tree_key& key) const 271 { 272 for (children_map::const_iterator iter = _children.begin(); 273 iter != _children.end(); ++iter) { 274 tree_key child_key = key; 275 child_key.push_back((*iter).first); 276 try { 277 leaf_node& child = dynamic_cast< leaf_node& >(*(*iter).second); 278 if (child.is_set()) 279 properties[flatten_key(child_key)] = child.to_string(); 280 } catch (const std::bad_cast& unused_error) { 281 inner_node& child = dynamic_cast< inner_node& >(*(*iter).second); 282 child.all_properties(properties, child_key); 283 } 284 } 285 } 286 287 288 /// Constructor. 289 config::detail::static_inner_node::static_inner_node(void) : 290 inner_node(false) 291 { 292 } 293 294 295 /// Copies the node. 296 /// 297 /// \return A dynamically-allocated node. 298 config::detail::base_node* 299 config::detail::static_inner_node::deep_copy(void) const 300 { 301 std::unique_ptr< inner_node > new_node(new static_inner_node()); 302 copy_into(new_node.get()); 303 return new_node.release(); 304 } 305 306 307 /// Combines this node with another one. 308 /// 309 /// \param key Key to this node. 310 /// \param other The node to combine with. 311 /// 312 /// \return A new node representing the combination. 313 /// 314 /// \throw bad_combination_error If the two nodes cannot be combined. 315 config::detail::base_node* 316 config::detail::static_inner_node::combine(const tree_key& key, 317 const base_node* other) const 318 { 319 std::unique_ptr< inner_node > new_node(new static_inner_node()); 320 combine_into(key, other, new_node.get()); 321 return new_node.release(); 322 } 323 324 325 /// Registers a key as valid and having a specific type. 326 /// 327 /// This method does not raise errors on invalid/unknown keys or other 328 /// tree-related issues. The reasons is that define() is a method that does not 329 /// depend on user input: it is intended to pre-populate the tree with a 330 /// specific structure, and that happens once at coding time. 331 /// 332 /// \param key The key to be registered. 333 /// \param key_pos The current level within the key to be examined. 334 /// \param new_node A function that returns a new leaf node of the desired 335 /// type. 336 void 337 config::detail::static_inner_node::define(const tree_key& key, 338 const tree_key::size_type key_pos, 339 new_node_hook new_node) 340 { 341 PRE(key_pos < key.size()); 342 343 if (key_pos == key.size() - 1) { 344 PRE_MSG(_children.find(key[key_pos]) == _children.end(), 345 "Key already defined"); 346 _children.insert(children_map::value_type(key[key_pos], new_node())); 347 } else { 348 PRE(key_pos < key.size() - 1); 349 const children_map::const_iterator child_iter = _children.find( 350 key[key_pos]); 351 352 if (child_iter == _children.end()) { 353 static_inner_node* const child_ptr = new static_inner_node(); 354 _children.insert(children_map::value_type(key[key_pos], child_ptr)); 355 child_ptr->define(key, key_pos + 1, new_node); 356 } else { 357 try { 358 static_inner_node& child = dynamic_cast< static_inner_node& >( 359 *(*child_iter).second); 360 child.define(key, key_pos + 1, new_node); 361 } catch (const std::bad_cast& e) { 362 UNREACHABLE; 363 } 364 } 365 } 366 } 367 368 369 /// Constructor. 370 config::detail::dynamic_inner_node::dynamic_inner_node(void) : 371 inner_node(true) 372 { 373 } 374 375 376 /// Copies the node. 377 /// 378 /// \return A dynamically-allocated node. 379 config::detail::base_node* 380 config::detail::dynamic_inner_node::deep_copy(void) const 381 { 382 std::unique_ptr< inner_node > new_node(new dynamic_inner_node()); 383 copy_into(new_node.get()); 384 return new_node.release(); 385 } 386 387 388 /// Combines this node with another one. 389 /// 390 /// \param key Key to this node. 391 /// \param other The node to combine with. 392 /// 393 /// \return A new node representing the combination. 394 /// 395 /// \throw bad_combination_error If the two nodes cannot be combined. 396 config::detail::base_node* 397 config::detail::dynamic_inner_node::combine(const tree_key& key, 398 const base_node* other) const 399 { 400 std::unique_ptr< inner_node > new_node(new dynamic_inner_node()); 401 combine_into(key, other, new_node.get()); 402 return new_node.release(); 403 } 404 405 406 /// Destructor. 407 config::leaf_node::~leaf_node(void) 408 { 409 } 410 411 412 /// Combines this node with another one. 413 /// 414 /// \param key Key to this node. 415 /// \param other_base The node to combine with. 416 /// 417 /// \return A new node representing the combination. 418 /// 419 /// \throw bad_combination_error If the two nodes cannot be combined. 420 config::detail::base_node* 421 config::leaf_node::combine(const detail::tree_key& key, 422 const base_node* other_base) const 423 { 424 try { 425 const leaf_node& other = dynamic_cast< const leaf_node& >(*other_base); 426 427 if (other.is_set()) { 428 return other.deep_copy(); 429 } else { 430 return deep_copy(); 431 } 432 } catch (const std::bad_cast& unused_e) { 433 throw config::bad_combination_error( 434 key, "'%s' is a leaf node in the base tree but an inner node in " 435 "the overrides treee"); 436 } 437 } 438 439 440 /// Copies the node. 441 /// 442 /// \return A dynamically-allocated node. 443 config::detail::base_node* 444 config::bool_node::deep_copy(void) const 445 { 446 std::unique_ptr< bool_node > new_node(new bool_node()); 447 new_node->_value = _value; 448 return new_node.release(); 449 } 450 451 452 /// Pushes the node's value onto the Lua stack. 453 /// 454 /// \param state The Lua state onto which to push the value. 455 void 456 config::bool_node::push_lua(lutok::state& state) const 457 { 458 state.push_boolean(value()); 459 } 460 461 462 /// Sets the value of the node from an entry in the Lua stack. 463 /// 464 /// \param state The Lua state from which to get the value. 465 /// \param value_index The stack index in which the value resides. 466 /// 467 /// \throw value_error If the value in state(value_index) cannot be 468 /// processed by this node. 469 void 470 config::bool_node::set_lua(lutok::state& state, const int value_index) 471 { 472 if (state.is_boolean(value_index)) 473 set(state.to_boolean(value_index)); 474 else 475 throw value_error("Not a boolean"); 476 } 477 478 479 /// Copies the node. 480 /// 481 /// \return A dynamically-allocated node. 482 config::detail::base_node* 483 config::int_node::deep_copy(void) const 484 { 485 std::unique_ptr< int_node > new_node(new int_node()); 486 new_node->_value = _value; 487 return new_node.release(); 488 } 489 490 491 /// Pushes the node's value onto the Lua stack. 492 /// 493 /// \param state The Lua state onto which to push the value. 494 void 495 config::int_node::push_lua(lutok::state& state) const 496 { 497 state.push_integer(value()); 498 } 499 500 501 /// Sets the value of the node from an entry in the Lua stack. 502 /// 503 /// \param state The Lua state from which to get the value. 504 /// \param value_index The stack index in which the value resides. 505 /// 506 /// \throw value_error If the value in state(value_index) cannot be 507 /// processed by this node. 508 void 509 config::int_node::set_lua(lutok::state& state, const int value_index) 510 { 511 if (state.is_number(value_index)) 512 set(state.to_integer(value_index)); 513 else 514 throw value_error("Not an integer"); 515 } 516 517 518 /// Checks a given value for validity. 519 /// 520 /// \param new_value The value to validate. 521 /// 522 /// \throw value_error If the value is not valid. 523 void 524 config::positive_int_node::validate(const value_type& new_value) const 525 { 526 if (new_value <= 0) 527 throw value_error("Must be a positive integer"); 528 } 529 530 531 /// Copies the node. 532 /// 533 /// \return A dynamically-allocated node. 534 config::detail::base_node* 535 config::positive_int_node::deep_copy(void) const 536 { 537 std::unique_ptr< positive_int_node > new_node(new positive_int_node()); 538 new_node->_value = _value; 539 return new_node.release(); 540 } 541 542 543 /// Copies the node. 544 /// 545 /// \return A dynamically-allocated node. 546 config::detail::base_node* 547 config::string_node::deep_copy(void) const 548 { 549 std::unique_ptr< string_node > new_node(new string_node()); 550 new_node->_value = _value; 551 return new_node.release(); 552 } 553 554 555 /// Pushes the node's value onto the Lua stack. 556 /// 557 /// \param state The Lua state onto which to push the value. 558 void 559 config::string_node::push_lua(lutok::state& state) const 560 { 561 state.push_string(value()); 562 } 563 564 565 /// Sets the value of the node from an entry in the Lua stack. 566 /// 567 /// \param state The Lua state from which to get the value. 568 /// \param value_index The stack index in which the value resides. 569 /// 570 /// \throw value_error If the value in state(value_index) cannot be 571 /// processed by this node. 572 void 573 config::string_node::set_lua(lutok::state& state, const int value_index) 574 { 575 if (state.is_string(value_index)) 576 set(state.to_string(value_index)); 577 else 578 throw value_error("Not a string"); 579 } 580 581 582 /// Copies the node. 583 /// 584 /// \return A dynamically-allocated node. 585 config::detail::base_node* 586 config::strings_set_node::deep_copy(void) const 587 { 588 std::unique_ptr< strings_set_node > new_node(new strings_set_node()); 589 new_node->_value = _value; 590 return new_node.release(); 591 } 592 593 594 /// Converts a single word to the native type. 595 /// 596 /// \param raw_value The value to parse. 597 /// 598 /// \return The parsed value. 599 std::string 600 config::strings_set_node::parse_one(const std::string& raw_value) const 601 { 602 return raw_value; 603 } 604