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