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 /// \file utils/config/nodes.hpp 30 /// Representation of tree nodes. 31 32 #if !defined(UTILS_CONFIG_NODES_HPP) 33 #define UTILS_CONFIG_NODES_HPP 34 35 #include <map> 36 #include <set> 37 #include <string> 38 39 #include <lutok/state.hpp> 40 41 #include "utils/config/keys.hpp" 42 #include "utils/noncopyable.hpp" 43 #include "utils/optional.hpp" 44 45 namespace utils { 46 namespace config { 47 48 49 /// Flat representation of all properties as strings. 50 typedef std::map< std::string, std::string > properties_map; 51 52 53 namespace detail { 54 55 56 /// Base representation of a node. 57 /// 58 /// This abstract class provides the base type for every node in the tree. Due 59 /// to the dynamic nature of our trees (each leaf being able to hold arbitrary 60 /// data types), this base type is a necessity. 61 class base_node : noncopyable { 62 public: 63 virtual ~base_node(void) = 0; 64 65 /// Copies the node. 66 /// 67 /// \return A dynamically-allocated node. 68 virtual base_node* deep_copy(void) const = 0; 69 }; 70 71 72 class static_inner_node; 73 74 75 } // namespace detail 76 77 78 /// Abstract leaf node without any specified type. 79 /// 80 /// This base abstract type is necessary to have a common pointer type to which 81 /// to cast any leaf. We later provide templated derivates of this class, and 82 /// those cannot act in this manner. 83 /// 84 /// It is important to understand that a leaf can exist without actually holding 85 /// a value. Our trees are "strictly keyed": keys must have been pre-defined 86 /// before a value can be set on them. This is to ensure that the end user is 87 /// using valid key names and not making mistakes due to typos, for example. To 88 /// represent this condition, we define an "empty" key in the tree to denote 89 /// that the key is valid, yet it has not been set by the user. Only when an 90 /// explicit set is performed on the key, it gets a value. 91 class leaf_node : public detail::base_node { 92 public: 93 virtual ~leaf_node(void); 94 95 /// Checks whether the node has been set by the user. 96 /// 97 /// Nodes of the tree are predefined by the caller to specify the valid 98 /// types of the leaves. Such predefinition results in the creation of 99 /// nodes within the tree, but these nodes have not yet been set. 100 /// Traversing these nodes is invalid and should result in an "unknown key" 101 /// error. 102 /// 103 /// \return True if a value has been set in the node. 104 virtual bool is_set(void) const = 0; 105 106 /// Pushes the node's value onto the Lua stack. 107 /// 108 /// \param state The Lua state onto which to push the value. 109 virtual void push_lua(lutok::state& state) const = 0; 110 111 /// Sets the value of the node from an entry in the Lua stack. 112 /// 113 /// \param state The Lua state from which to get the value. 114 /// \param value_index The stack index in which the value resides. 115 /// 116 /// \throw value_error If the value in state(value_index) cannot be 117 /// processed by this node. 118 virtual void set_lua(lutok::state& state, const int value_index) = 0; 119 120 /// Sets the value of the node from a raw string representation. 121 /// 122 /// \param raw_value The value to set the node to. 123 /// 124 /// \throw value_error If the value is invalid. 125 virtual void set_string(const std::string& raw_value) = 0; 126 127 /// Converts the contents of the node to a string. 128 /// 129 /// \pre The node must have a value. 130 /// 131 /// \return A string representation of the value held by the node. 132 virtual std::string to_string(void) const = 0; 133 }; 134 135 136 /// Base leaf node for a single arbitrary type. 137 /// 138 /// This templated leaf node holds a single object of any type. The conversion 139 /// to/from string representations is undefined, as that depends on the 140 /// particular type being processed. You should reimplement this class for any 141 /// type that needs additional processing/validation during conversion. 142 template< typename ValueType > 143 class typed_leaf_node : public leaf_node { 144 public: 145 /// The type of the value held by this node. 146 typedef ValueType value_type; 147 148 typed_leaf_node(void); 149 150 bool is_set(void) const; 151 152 /// Gets the value stored in the node. 153 /// 154 /// \todo Figure out why Doxygen is unable to pick up the documentation for 155 /// this function from the nodes.ipp file. 156 /// 157 /// \pre The node must have a value. 158 /// 159 /// \return The value in the node. 160 const value_type& value(void) const; 161 162 /// Gets the read-write value stored in the node. 163 /// 164 /// \todo Figure out why Doxygen is unable to pick up the documentation for 165 /// this function from the nodes.ipp file. 166 /// 167 /// \pre The node must have a value. 168 /// 169 /// \return The value in the node. 170 value_type& value(void); 171 172 /// Sets the value of the node. 173 /// 174 /// \todo Figure out why Doxygen is unable to pick up the documentation for 175 /// this function from the nodes.ipp file. 176 /// 177 /// \param value_ The new value to set the node to. 178 void set(const value_type&); 179 180 protected: 181 /// The value held by this node. 182 optional< value_type > _value; 183 184 private: 185 virtual void validate(const value_type&) const; 186 }; 187 188 189 /// Leaf node holding a native type. 190 /// 191 /// This templated leaf node holds a native type. The conversion to/from string 192 /// representations of the value happens by means of iostreams. 193 template< typename ValueType > 194 class native_leaf_node : public typed_leaf_node< ValueType > { 195 public: 196 void set_string(const std::string&); 197 std::string to_string(void) const; 198 }; 199 200 201 /// A leaf node that holds a boolean value. 202 class bool_node : public native_leaf_node< bool > { 203 public: 204 virtual base_node* deep_copy(void) const; 205 206 void push_lua(lutok::state&) const; 207 void set_lua(lutok::state&, const int); 208 }; 209 210 211 /// A leaf node that holds an integer value. 212 class int_node : public native_leaf_node< int > { 213 public: 214 virtual base_node* deep_copy(void) const; 215 216 void push_lua(lutok::state&) const; 217 void set_lua(lutok::state&, const int); 218 }; 219 220 221 /// A leaf node that holds a string value. 222 class string_node : public native_leaf_node< std::string > { 223 public: 224 virtual base_node* deep_copy(void) const; 225 226 void push_lua(lutok::state&) const; 227 void set_lua(lutok::state&, const int); 228 }; 229 230 231 /// Base leaf node for a set of native types. 232 /// 233 /// This is a base abstract class because there is no generic way to parse a 234 /// single word in the textual representation of the set to the native value. 235 template< typename ValueType > 236 class base_set_node : public leaf_node { 237 public: 238 /// The type of the value held by this node. 239 typedef std::set< ValueType > value_type; 240 241 base_set_node(void); 242 243 bool is_set(void) const; 244 245 /// Gets the value stored in the node. 246 /// 247 /// \todo Figure out why Doxygen is unable to pick up the documentation for 248 /// this function from the nodes.ipp file. 249 /// 250 /// \pre The node must have a value. 251 /// 252 /// \return The value in the node. 253 const value_type& value(void) const; 254 255 /// Gets the read-write value stored in the node. 256 /// 257 /// \todo Figure out why Doxygen is unable to pick up the documentation for 258 /// this function from the nodes.ipp file. 259 /// 260 /// \pre The node must have a value. 261 /// 262 /// \return The value in the node. 263 value_type& value(void); 264 265 /// Sets the value of the node. 266 /// 267 /// \todo Figure out why Doxygen is unable to pick up the documentation for 268 /// this function from the nodes.ipp file. 269 /// 270 /// \param value_ The new value to set the node to. 271 void set(const value_type&); 272 273 void set_string(const std::string&); 274 std::string to_string(void) const; 275 276 void push_lua(lutok::state&) const; 277 void set_lua(lutok::state&, const int); 278 279 protected: 280 /// The value held by this node. 281 optional< value_type > _value; 282 283 private: 284 /// Converts a single word to the native type. 285 /// 286 /// \param raw_value The value to parse. 287 /// 288 /// \return The parsed value. 289 /// 290 /// \throw value_error If the value is invalid. 291 virtual ValueType parse_one(const std::string& raw_value) const = 0; 292 293 virtual void validate(const value_type&) const; 294 }; 295 296 297 /// A leaf node that holds a set of strings. 298 class strings_set_node : public base_set_node< std::string > { 299 public: 300 virtual base_node* deep_copy(void) const; 301 302 private: 303 std::string parse_one(const std::string&) const; 304 }; 305 306 307 } // namespace config 308 } // namespace utils 309 310 #endif // !defined(UTILS_CONFIG_NODES_HPP) 311