1*6a6c8299Sjmmv// Copyright 2012 Google Inc. 2*6a6c8299Sjmmv// All rights reserved. 3*6a6c8299Sjmmv// 4*6a6c8299Sjmmv// Redistribution and use in source and binary forms, with or without 5*6a6c8299Sjmmv// modification, are permitted provided that the following conditions are 6*6a6c8299Sjmmv// met: 7*6a6c8299Sjmmv// 8*6a6c8299Sjmmv// * Redistributions of source code must retain the above copyright 9*6a6c8299Sjmmv// notice, this list of conditions and the following disclaimer. 10*6a6c8299Sjmmv// * Redistributions in binary form must reproduce the above copyright 11*6a6c8299Sjmmv// notice, this list of conditions and the following disclaimer in the 12*6a6c8299Sjmmv// documentation and/or other materials provided with the distribution. 13*6a6c8299Sjmmv// * Neither the name of Google Inc. nor the names of its contributors 14*6a6c8299Sjmmv// may be used to endorse or promote products derived from this software 15*6a6c8299Sjmmv// without specific prior written permission. 16*6a6c8299Sjmmv// 17*6a6c8299Sjmmv// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18*6a6c8299Sjmmv// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*6a6c8299Sjmmv// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20*6a6c8299Sjmmv// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21*6a6c8299Sjmmv// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22*6a6c8299Sjmmv// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23*6a6c8299Sjmmv// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24*6a6c8299Sjmmv// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25*6a6c8299Sjmmv// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26*6a6c8299Sjmmv// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27*6a6c8299Sjmmv// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28*6a6c8299Sjmmv 29*6a6c8299Sjmmv#include "utils/config/nodes.hpp" 30*6a6c8299Sjmmv 31*6a6c8299Sjmmv#if !defined(UTILS_CONFIG_NODES_IPP) 32*6a6c8299Sjmmv#define UTILS_CONFIG_NODES_IPP 33*6a6c8299Sjmmv 34*6a6c8299Sjmmv#include <memory> 35*6a6c8299Sjmmv#include <typeinfo> 36*6a6c8299Sjmmv 37*6a6c8299Sjmmv#include "utils/config/exceptions.hpp" 38*6a6c8299Sjmmv#include "utils/defs.hpp" 39*6a6c8299Sjmmv#include "utils/format/macros.hpp" 40*6a6c8299Sjmmv#include "utils/optional.ipp" 41*6a6c8299Sjmmv#include "utils/text/exceptions.hpp" 42*6a6c8299Sjmmv#include "utils/text/operations.ipp" 43*6a6c8299Sjmmv#include "utils/sanity.hpp" 44*6a6c8299Sjmmv 45*6a6c8299Sjmmvnamespace utils { 46*6a6c8299Sjmmv 47*6a6c8299Sjmmv 48*6a6c8299Sjmmvnamespace config { 49*6a6c8299Sjmmvnamespace detail { 50*6a6c8299Sjmmv 51*6a6c8299Sjmmv 52*6a6c8299Sjmmv/// Type of the new_node() family of functions. 53*6a6c8299Sjmmvtypedef base_node* (*new_node_hook)(void); 54*6a6c8299Sjmmv 55*6a6c8299Sjmmv 56*6a6c8299Sjmmv/// Creates a new leaf node of a given type. 57*6a6c8299Sjmmv/// 58*6a6c8299Sjmmv/// \tparam NodeType The type of the leaf node to create. 59*6a6c8299Sjmmv/// 60*6a6c8299Sjmmv/// \return A pointer to the newly-created node. 61*6a6c8299Sjmmvtemplate< class NodeType > 62*6a6c8299Sjmmvbase_node* 63*6a6c8299Sjmmvnew_node(void) 64*6a6c8299Sjmmv{ 65*6a6c8299Sjmmv return new NodeType(); 66*6a6c8299Sjmmv} 67*6a6c8299Sjmmv 68*6a6c8299Sjmmv 69*6a6c8299Sjmmv/// Internal node of the tree. 70*6a6c8299Sjmmv/// 71*6a6c8299Sjmmv/// This abstract base class provides the mechanism to implement both static and 72*6a6c8299Sjmmv/// dynamic nodes. Ideally, the implementation would be split in subclasses and 73*6a6c8299Sjmmv/// this class would not include the knowledge of whether the node is dynamic or 74*6a6c8299Sjmmv/// not. However, because the static/dynamic difference depends on the leaf 75*6a6c8299Sjmmv/// types, we need to declare template functions and these cannot be virtual. 76*6a6c8299Sjmmvclass inner_node : public base_node { 77*6a6c8299Sjmmv /// Whether the node is dynamic or not. 78*6a6c8299Sjmmv bool _dynamic; 79*6a6c8299Sjmmv 80*6a6c8299Sjmmvprotected: 81*6a6c8299Sjmmv /// Type to represent the collection of children of this node. 82*6a6c8299Sjmmv /// 83*6a6c8299Sjmmv /// Note that these are one-level keys. They cannot contain dots, and thus 84*6a6c8299Sjmmv /// is why we use a string rather than a tree_key. 85*6a6c8299Sjmmv typedef std::map< std::string, base_node* > children_map; 86*6a6c8299Sjmmv 87*6a6c8299Sjmmv /// Mapping of keys to values that are descendants of this node. 88*6a6c8299Sjmmv children_map _children; 89*6a6c8299Sjmmv 90*6a6c8299Sjmmv void copy_into(inner_node* new_node) const; 91*6a6c8299Sjmmv 92*6a6c8299Sjmmvpublic: 93*6a6c8299Sjmmv inner_node(const bool); 94*6a6c8299Sjmmv virtual ~inner_node(void) = 0; 95*6a6c8299Sjmmv 96*6a6c8299Sjmmv const base_node* lookup_ro(const tree_key&, 97*6a6c8299Sjmmv const tree_key::size_type) const; 98*6a6c8299Sjmmv leaf_node* lookup_rw(const tree_key&, const tree_key::size_type, 99*6a6c8299Sjmmv new_node_hook); 100*6a6c8299Sjmmv 101*6a6c8299Sjmmv void all_properties(properties_map&, const tree_key&) const; 102*6a6c8299Sjmmv}; 103*6a6c8299Sjmmv 104*6a6c8299Sjmmv 105*6a6c8299Sjmmv/// Static internal node of the tree. 106*6a6c8299Sjmmv/// 107*6a6c8299Sjmmv/// The direct children of this node must be pre-defined by calls to define(). 108*6a6c8299Sjmmv/// Attempts to traverse this node and resolve a key that is not a pre-defined 109*6a6c8299Sjmmv/// children will result in an "unknown key" error. 110*6a6c8299Sjmmvclass static_inner_node : public config::detail::inner_node { 111*6a6c8299Sjmmvpublic: 112*6a6c8299Sjmmv static_inner_node(void); 113*6a6c8299Sjmmv 114*6a6c8299Sjmmv virtual base_node* deep_copy(void) const; 115*6a6c8299Sjmmv 116*6a6c8299Sjmmv void define(const tree_key&, const tree_key::size_type, new_node_hook); 117*6a6c8299Sjmmv}; 118*6a6c8299Sjmmv 119*6a6c8299Sjmmv 120*6a6c8299Sjmmv/// Dynamic internal node of the tree. 121*6a6c8299Sjmmv/// 122*6a6c8299Sjmmv/// The children of this node need not be pre-defined. Attempts to traverse 123*6a6c8299Sjmmv/// this node and resolve a key will result in such key being created. Any 124*6a6c8299Sjmmv/// intermediate non-existent nodes of the traversal will be created as dynamic 125*6a6c8299Sjmmv/// inner nodes as well. 126*6a6c8299Sjmmvclass dynamic_inner_node : public config::detail::inner_node { 127*6a6c8299Sjmmvpublic: 128*6a6c8299Sjmmv virtual base_node* deep_copy(void) const; 129*6a6c8299Sjmmv 130*6a6c8299Sjmmv dynamic_inner_node(void); 131*6a6c8299Sjmmv}; 132*6a6c8299Sjmmv 133*6a6c8299Sjmmv 134*6a6c8299Sjmmv} // namespace detail 135*6a6c8299Sjmmv} // namespace config 136*6a6c8299Sjmmv 137*6a6c8299Sjmmv 138*6a6c8299Sjmmv/// Constructor for a node with an undefined value. 139*6a6c8299Sjmmv/// 140*6a6c8299Sjmmv/// This should only be called by the tree's define() method as a way to 141*6a6c8299Sjmmv/// register a node as known but undefined. The node will then serve as a 142*6a6c8299Sjmmv/// placeholder for future values. 143*6a6c8299Sjmmvtemplate< typename ValueType > 144*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::typed_leaf_node(void) : 145*6a6c8299Sjmmv _value(none) 146*6a6c8299Sjmmv{ 147*6a6c8299Sjmmv} 148*6a6c8299Sjmmv 149*6a6c8299Sjmmv 150*6a6c8299Sjmmv/// Checks whether the node has been set. 151*6a6c8299Sjmmv/// 152*6a6c8299Sjmmv/// Remember that a node can exist before holding a value (i.e. when the node 153*6a6c8299Sjmmv/// has been defined as "known" but not yet set by the user). This function 154*6a6c8299Sjmmv/// checks whether the node laready holds a value. 155*6a6c8299Sjmmv/// 156*6a6c8299Sjmmv/// \return True if a value has been set in the node. 157*6a6c8299Sjmmvtemplate< typename ValueType > 158*6a6c8299Sjmmvbool 159*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::is_set(void) const 160*6a6c8299Sjmmv{ 161*6a6c8299Sjmmv return static_cast< bool >(_value); 162*6a6c8299Sjmmv} 163*6a6c8299Sjmmv 164*6a6c8299Sjmmv 165*6a6c8299Sjmmv/// Gets the value stored in the node. 166*6a6c8299Sjmmv/// 167*6a6c8299Sjmmv/// \pre The node must have a value. 168*6a6c8299Sjmmv/// 169*6a6c8299Sjmmv/// \return The value in the node. 170*6a6c8299Sjmmvtemplate< typename ValueType > 171*6a6c8299Sjmmvconst typename config::typed_leaf_node< ValueType >::value_type& 172*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::value(void) const 173*6a6c8299Sjmmv{ 174*6a6c8299Sjmmv PRE(is_set()); 175*6a6c8299Sjmmv return _value.get(); 176*6a6c8299Sjmmv} 177*6a6c8299Sjmmv 178*6a6c8299Sjmmv 179*6a6c8299Sjmmv/// Gets the read-write value stored in the node. 180*6a6c8299Sjmmv/// 181*6a6c8299Sjmmv/// \pre The node must have a value. 182*6a6c8299Sjmmv/// 183*6a6c8299Sjmmv/// \return The value in the node. 184*6a6c8299Sjmmvtemplate< typename ValueType > 185*6a6c8299Sjmmvtypename config::typed_leaf_node< ValueType >::value_type& 186*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::value(void) 187*6a6c8299Sjmmv{ 188*6a6c8299Sjmmv PRE(is_set()); 189*6a6c8299Sjmmv return _value.get(); 190*6a6c8299Sjmmv} 191*6a6c8299Sjmmv 192*6a6c8299Sjmmv 193*6a6c8299Sjmmv/// Sets the value of the node. 194*6a6c8299Sjmmv/// 195*6a6c8299Sjmmv/// \param value_ The new value to set the node to. 196*6a6c8299Sjmmv/// 197*6a6c8299Sjmmv/// \throw value_error If the value is invalid, according to validate(). 198*6a6c8299Sjmmvtemplate< typename ValueType > 199*6a6c8299Sjmmvvoid 200*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::set(const value_type& value_) 201*6a6c8299Sjmmv{ 202*6a6c8299Sjmmv validate(value_); 203*6a6c8299Sjmmv _value = optional< value_type >(value_); 204*6a6c8299Sjmmv} 205*6a6c8299Sjmmv 206*6a6c8299Sjmmv 207*6a6c8299Sjmmv/// Checks a given value for validity. 208*6a6c8299Sjmmv/// 209*6a6c8299Sjmmv/// This is called internally by the node right before updating the recorded 210*6a6c8299Sjmmv/// value. This method can be redefined by subclasses. 211*6a6c8299Sjmmv/// 212*6a6c8299Sjmmv/// \param unused_new_value The value to validate. 213*6a6c8299Sjmmv/// 214*6a6c8299Sjmmv/// \throw value_error If the value is not valid. 215*6a6c8299Sjmmvtemplate< typename ValueType > 216*6a6c8299Sjmmvvoid 217*6a6c8299Sjmmvconfig::typed_leaf_node< ValueType >::validate( 218*6a6c8299Sjmmv const value_type& UTILS_UNUSED_PARAM(new_value)) const 219*6a6c8299Sjmmv{ 220*6a6c8299Sjmmv} 221*6a6c8299Sjmmv 222*6a6c8299Sjmmv 223*6a6c8299Sjmmv/// Sets the value of the node from a raw string representation. 224*6a6c8299Sjmmv/// 225*6a6c8299Sjmmv/// \param raw_value The value to set the node to. 226*6a6c8299Sjmmv/// 227*6a6c8299Sjmmv/// \throw value_error If the value is invalid. 228*6a6c8299Sjmmvtemplate< typename ValueType > 229*6a6c8299Sjmmvvoid 230*6a6c8299Sjmmvconfig::native_leaf_node< ValueType >::set_string(const std::string& raw_value) 231*6a6c8299Sjmmv{ 232*6a6c8299Sjmmv try { 233*6a6c8299Sjmmv typed_leaf_node< ValueType >::set(text::to_type< ValueType >( 234*6a6c8299Sjmmv raw_value)); 235*6a6c8299Sjmmv } catch (const text::value_error& e) { 236*6a6c8299Sjmmv throw config::value_error(F("Failed to convert string value '%s' to " 237*6a6c8299Sjmmv "the node's type") % raw_value); 238*6a6c8299Sjmmv } 239*6a6c8299Sjmmv} 240*6a6c8299Sjmmv 241*6a6c8299Sjmmv 242*6a6c8299Sjmmv/// Converts the contents of the node to a string. 243*6a6c8299Sjmmv/// 244*6a6c8299Sjmmv/// \pre The node must have a value. 245*6a6c8299Sjmmv/// 246*6a6c8299Sjmmv/// \return A string representation of the value held by the node. 247*6a6c8299Sjmmvtemplate< typename ValueType > 248*6a6c8299Sjmmvstd::string 249*6a6c8299Sjmmvconfig::native_leaf_node< ValueType >::to_string(void) const 250*6a6c8299Sjmmv{ 251*6a6c8299Sjmmv PRE(typed_leaf_node< ValueType >::is_set()); 252*6a6c8299Sjmmv return F("%s") % typed_leaf_node< ValueType >::value(); 253*6a6c8299Sjmmv} 254*6a6c8299Sjmmv 255*6a6c8299Sjmmv 256*6a6c8299Sjmmv/// Constructor for a node with an undefined value. 257*6a6c8299Sjmmv/// 258*6a6c8299Sjmmv/// This should only be called by the tree's define() method as a way to 259*6a6c8299Sjmmv/// register a node as known but undefined. The node will then serve as a 260*6a6c8299Sjmmv/// placeholder for future values. 261*6a6c8299Sjmmvtemplate< typename ValueType > 262*6a6c8299Sjmmvconfig::base_set_node< ValueType >::base_set_node(void) : 263*6a6c8299Sjmmv _value(none) 264*6a6c8299Sjmmv{ 265*6a6c8299Sjmmv} 266*6a6c8299Sjmmv 267*6a6c8299Sjmmv 268*6a6c8299Sjmmv/// Checks whether the node has been set. 269*6a6c8299Sjmmv/// 270*6a6c8299Sjmmv/// Remember that a node can exist before holding a value (i.e. when the node 271*6a6c8299Sjmmv/// has been defined as "known" but not yet set by the user). This function 272*6a6c8299Sjmmv/// checks whether the node laready holds a value. 273*6a6c8299Sjmmv/// 274*6a6c8299Sjmmv/// \return True if a value has been set in the node. 275*6a6c8299Sjmmvtemplate< typename ValueType > 276*6a6c8299Sjmmvbool 277*6a6c8299Sjmmvconfig::base_set_node< ValueType >::is_set(void) const 278*6a6c8299Sjmmv{ 279*6a6c8299Sjmmv return static_cast< bool >(_value); 280*6a6c8299Sjmmv} 281*6a6c8299Sjmmv 282*6a6c8299Sjmmv 283*6a6c8299Sjmmv/// Gets the value stored in the node. 284*6a6c8299Sjmmv/// 285*6a6c8299Sjmmv/// \pre The node must have a value. 286*6a6c8299Sjmmv/// 287*6a6c8299Sjmmv/// \return The value in the node. 288*6a6c8299Sjmmvtemplate< typename ValueType > 289*6a6c8299Sjmmvconst typename config::base_set_node< ValueType >::value_type& 290*6a6c8299Sjmmvconfig::base_set_node< ValueType >::value(void) const 291*6a6c8299Sjmmv{ 292*6a6c8299Sjmmv PRE(is_set()); 293*6a6c8299Sjmmv return _value.get(); 294*6a6c8299Sjmmv} 295*6a6c8299Sjmmv 296*6a6c8299Sjmmv 297*6a6c8299Sjmmv/// Gets the read-write value stored in the node. 298*6a6c8299Sjmmv/// 299*6a6c8299Sjmmv/// \pre The node must have a value. 300*6a6c8299Sjmmv/// 301*6a6c8299Sjmmv/// \return The value in the node. 302*6a6c8299Sjmmvtemplate< typename ValueType > 303*6a6c8299Sjmmvtypename config::base_set_node< ValueType >::value_type& 304*6a6c8299Sjmmvconfig::base_set_node< ValueType >::value(void) 305*6a6c8299Sjmmv{ 306*6a6c8299Sjmmv PRE(is_set()); 307*6a6c8299Sjmmv return _value.get(); 308*6a6c8299Sjmmv} 309*6a6c8299Sjmmv 310*6a6c8299Sjmmv 311*6a6c8299Sjmmv/// Sets the value of the node. 312*6a6c8299Sjmmv/// 313*6a6c8299Sjmmv/// \param value_ The new value to set the node to. 314*6a6c8299Sjmmv/// 315*6a6c8299Sjmmv/// \throw value_error If the value is invalid, according to validate(). 316*6a6c8299Sjmmvtemplate< typename ValueType > 317*6a6c8299Sjmmvvoid 318*6a6c8299Sjmmvconfig::base_set_node< ValueType >::set(const value_type& value_) 319*6a6c8299Sjmmv{ 320*6a6c8299Sjmmv validate(value_); 321*6a6c8299Sjmmv _value = optional< value_type >(value_); 322*6a6c8299Sjmmv} 323*6a6c8299Sjmmv 324*6a6c8299Sjmmv 325*6a6c8299Sjmmv/// Sets the value of the node from a raw string representation. 326*6a6c8299Sjmmv/// 327*6a6c8299Sjmmv/// \param raw_value The value to set the node to. 328*6a6c8299Sjmmv/// 329*6a6c8299Sjmmv/// \throw value_error If the value is invalid. 330*6a6c8299Sjmmvtemplate< typename ValueType > 331*6a6c8299Sjmmvvoid 332*6a6c8299Sjmmvconfig::base_set_node< ValueType >::set_string(const std::string& raw_value) 333*6a6c8299Sjmmv{ 334*6a6c8299Sjmmv std::set< ValueType > new_value; 335*6a6c8299Sjmmv 336*6a6c8299Sjmmv const std::vector< std::string > words = text::split(raw_value, ' '); 337*6a6c8299Sjmmv for (std::vector< std::string >::const_iterator iter = words.begin(); 338*6a6c8299Sjmmv iter != words.end(); ++iter) { 339*6a6c8299Sjmmv if (!(*iter).empty()) 340*6a6c8299Sjmmv new_value.insert(parse_one(*iter)); 341*6a6c8299Sjmmv } 342*6a6c8299Sjmmv 343*6a6c8299Sjmmv set(new_value); 344*6a6c8299Sjmmv} 345*6a6c8299Sjmmv 346*6a6c8299Sjmmv 347*6a6c8299Sjmmv/// Converts the contents of the node to a string. 348*6a6c8299Sjmmv/// 349*6a6c8299Sjmmv/// \pre The node must have a value. 350*6a6c8299Sjmmv/// 351*6a6c8299Sjmmv/// \return A string representation of the value held by the node. 352*6a6c8299Sjmmvtemplate< typename ValueType > 353*6a6c8299Sjmmvstd::string 354*6a6c8299Sjmmvconfig::base_set_node< ValueType >::to_string(void) const 355*6a6c8299Sjmmv{ 356*6a6c8299Sjmmv PRE(is_set()); 357*6a6c8299Sjmmv return text::join(_value.get(), " "); 358*6a6c8299Sjmmv} 359*6a6c8299Sjmmv 360*6a6c8299Sjmmv 361*6a6c8299Sjmmv/// Pushes the node's value onto the Lua stack. 362*6a6c8299Sjmmv/// 363*6a6c8299Sjmmv/// \param unused_state The Lua state onto which to push the value. 364*6a6c8299Sjmmvtemplate< typename ValueType > 365*6a6c8299Sjmmvvoid 366*6a6c8299Sjmmvconfig::base_set_node< ValueType >::push_lua( 367*6a6c8299Sjmmv lutok::state& UTILS_UNUSED_PARAM(state)) const 368*6a6c8299Sjmmv{ 369*6a6c8299Sjmmv UNREACHABLE; 370*6a6c8299Sjmmv} 371*6a6c8299Sjmmv 372*6a6c8299Sjmmv 373*6a6c8299Sjmmv/// Sets the value of the node from an entry in the Lua stack. 374*6a6c8299Sjmmv/// 375*6a6c8299Sjmmv/// \param unused_state The Lua state from which to get the value. 376*6a6c8299Sjmmv/// \param unused_value_index The stack index in which the value resides. 377*6a6c8299Sjmmv/// 378*6a6c8299Sjmmv/// \throw value_error If the value in state(value_index) cannot be 379*6a6c8299Sjmmv/// processed by this node. 380*6a6c8299Sjmmvtemplate< typename ValueType > 381*6a6c8299Sjmmvvoid 382*6a6c8299Sjmmvconfig::base_set_node< ValueType >::set_lua( 383*6a6c8299Sjmmv lutok::state& UTILS_UNUSED_PARAM(state), 384*6a6c8299Sjmmv const int UTILS_UNUSED_PARAM(value_index)) 385*6a6c8299Sjmmv{ 386*6a6c8299Sjmmv UNREACHABLE; 387*6a6c8299Sjmmv} 388*6a6c8299Sjmmv 389*6a6c8299Sjmmv 390*6a6c8299Sjmmv/// Checks a given value for validity. 391*6a6c8299Sjmmv/// 392*6a6c8299Sjmmv/// This is called internally by the node right before updating the recorded 393*6a6c8299Sjmmv/// value. This method can be redefined by subclasses. 394*6a6c8299Sjmmv/// 395*6a6c8299Sjmmv/// \param unused_new_value The value to validate. 396*6a6c8299Sjmmv/// 397*6a6c8299Sjmmv/// \throw value_error If the value is not valid. 398*6a6c8299Sjmmvtemplate< typename ValueType > 399*6a6c8299Sjmmvvoid 400*6a6c8299Sjmmvconfig::base_set_node< ValueType >::validate( 401*6a6c8299Sjmmv const value_type& UTILS_UNUSED_PARAM(new_value)) const 402*6a6c8299Sjmmv{ 403*6a6c8299Sjmmv} 404*6a6c8299Sjmmv 405*6a6c8299Sjmmv 406*6a6c8299Sjmmv} // namespace utils 407*6a6c8299Sjmmv 408*6a6c8299Sjmmv#endif // !defined(UTILS_CONFIG_NODES_IPP) 409