00001 #if !defined(__CONFIG_NODE_HPP__)
00002 #define __CONFIG_NODE_HPP__
00003
00004
00005
00006
00007 #include <string>
00008 #include <vector>
00009
00010
00011
00012
00013 #include "core/util/noncopyable.hpp"
00014 #include "core/util/c++0x.hpp"
00015 #include "core/system/log.hpp"
00016
00017
00018
00019
00020 namespace detail
00021 {
00022 template <typename NodeTypeT>
00023 struct node_traits
00024 {};
00025 }
00026
00030 struct config_node : private noncopyable
00031 {
00032
00033
00034
00035 std::string id;
00036
00037
00038
00039
00040 enum type
00041 {
00042 BOOL, NUMBER, INTERVAL, STRING, LIST, SECTION
00043 } type;
00044
00045
00046
00047
00048 union
00049 {
00050 bool boolean;
00051 unsigned long number;
00052 struct
00053 {
00054 unsigned long low, high;
00055 };
00056 };
00057
00058 std::string string;
00059
00060 protected:
00061
00062
00063
00064 config_node *next, *children;
00065
00066 public:
00067
00068
00069
00070 inline config_node(const std::string &id, bool boolean)
00071 : id(id), type(BOOL), boolean(boolean), next(nullptr), children(nullptr)
00072 {}
00073
00074 inline config_node(const std::string &id, unsigned long number)
00075 : id(id), type(NUMBER), number(number), next(nullptr), children(nullptr)
00076 {}
00077
00078 inline config_node(const std::string &id, unsigned long low, unsigned long high)
00079 : id(id), type(INTERVAL), low(low), high(high), next(nullptr), children(nullptr)
00080 {}
00081
00082 inline config_node(const std::string &id, const char *string)
00083 : id(id), type(STRING), string(string), next(nullptr), children(nullptr)
00084 {}
00085
00086 inline config_node(const std::string &id, config_node *children)
00087 : id(id), type(LIST), next(nullptr), children(children)
00088 {}
00089
00090 inline config_node(const std::string &id, enum type type, config_node *next, config_node *children)
00091 : id(id), type(type), next(next), children(children)
00092 {}
00093
00094 inline ~config_node(void)
00095 {
00096 delete next;
00097 delete children;
00098 }
00099
00100
00101
00102
00103 inline bool is(enum type type) const
00104 {
00105 return this->type == type;
00106 }
00107
00108 inline bool is_bool(void) const
00109 {
00110 return is(BOOL);
00111 }
00112
00113 inline bool is_number(void) const
00114 {
00115 return is(NUMBER);
00116 }
00117
00118 inline bool is_interval(void) const
00119 {
00120 return is(INTERVAL);
00121 }
00122
00123 inline bool is_string(void) const
00124 {
00125 return is(STRING);
00126 }
00127
00128 inline bool is_list(void) const
00129 {
00130 return is(LIST);
00131 }
00132
00133 inline bool is_section(void) const
00134 {
00135 return is(SECTION);
00136 }
00137
00138 inline bool is_attribute(void) const
00139 {
00140 return !is_section();
00141 }
00142
00143 inline bool is_or_warn(enum type type) const
00144 {
00145 if (is(type)) return true;
00146 warn_wrong_type(type);
00147 return false;
00148 }
00149
00150
00151
00152
00153 void set_ID(const std::string &id, bool recursive=false);
00154
00155
00156
00157
00158 inline int num_siblings(void) const
00159 {
00160 return num_nodes(next);
00161 }
00162
00163 inline bool has_sibling(const std::string &id="") const
00164 {
00165 return get_node(next, id) != nullptr;
00166 }
00167
00168 inline const config_node *get_sibling(const std::string &id="") const
00169 {
00170 return get_node(next, id);
00171 }
00172
00173 inline void append_sibling(config_node *node)
00174 {
00175
00176 return append_node(next, node);
00177 }
00178
00179 inline const config_node *remove_sibling(const std::string &id="")
00180 {
00181
00182
00183 return remove_node(next, id);
00184 }
00185
00186
00187
00188
00189 inline int num_children(void) const
00190 {
00191 return num_nodes(children);
00192 }
00193
00194 inline bool has_child(const std::string &id="") const
00195 {
00196 return get_node(children, id) != nullptr;
00197 }
00198
00199 inline const config_node *get_child(const std::string &id="") const
00200 {
00201 return get_node(children, id);
00202 }
00203
00204 inline void append_child(config_node *node)
00205 {
00206
00207 return append_node(children, node);
00208 }
00209
00210 inline config_node *remove_child(const std::string &id="")
00211 {
00212
00213
00214 return remove_node(children, id);
00215 }
00216
00217
00218
00219
00220 inline void warn_wrong_type(void) const
00221 {
00222 log::warn("wrong type for option: %s, ignored\n", id.c_str());
00223 }
00224
00225 inline void warn_wrong_type(enum type type) const
00226 {
00227 log::warn("wrong type for option: %s, expected: %s\n", id.c_str(), type2string(type));
00228 }
00229
00230 inline void warn_wrong_value(void) const
00231 {
00232 log::warn("wrong value '%s' for option: %s, ignored\n", get_value().c_str(), id.c_str());
00233 }
00234
00235 void warn_non_empty_section(const char *message=nullptr) const;
00236 std::string get_value(void) const;
00237
00238 template <typename NodeTypeT>
00239 inline NodeTypeT get_value(const NodeTypeT default_value=NodeTypeT()) const
00240 {
00241 return is_or_warn(detail::node_traits<NodeTypeT>::type) ?
00242 detail::node_traits<NodeTypeT>::value(*this) : default_value;
00243 }
00244
00245
00246
00247
00248
00249 template <typename NodeTypeT>
00250 NodeTypeT get_option(const std::string &id, NodeTypeT default_value=NodeTypeT());
00251
00252 template <typename NodeTypeT>
00253 int get_list_option(std::vector<NodeTypeT> &result, const std::string &id);
00254
00255
00256
00257
00258 static inline const char *type2string(enum type type)
00259 {
00260 return (type == BOOL) ? "bool" :
00261 (type == NUMBER) ? "number" :
00262 (type == INTERVAL) ? "interval" :
00263 (type == STRING) ? "string" :
00264 (type == LIST) ? "list" :
00265 (type == SECTION) ? "section" : "unknown";
00266 }
00267
00268 inline const char *type2string(void) const
00269 {
00270 return type2string(type);
00271 }
00272
00273 void print(int indent=0, int indent_inc=2, bool siblings=false) const;
00274
00275 protected:
00276
00277
00278
00279 static inline int num_nodes(const config_node *chain)
00280 {
00281 for (int n=0; ; chain=chain->next, n++)
00282 if (!chain) return n;
00283 }
00284
00285 static inline const config_node *get_node(const config_node *chain, const std::string &id="")
00286 {
00287 for (const config_node *p=chain; ; p=p->next)
00288 if (!p || (id == "") || (p->id == id)) return p;
00289 }
00290
00291 static void append_node(config_node *&chain, config_node *node);
00292 static config_node *remove_node(config_node *&chain, const std::string &id="");
00293 };
00294
00295
00296
00297
00298 namespace detail
00299 {
00300 using ::config_node;
00301
00302 template <>
00303 struct node_traits<bool>
00304 {
00305 static const enum config_node::type type=config_node::BOOL;
00306
00307 static inline bool value(const config_node &node)
00308 {
00309 return node.boolean;
00310 }
00311 };
00312
00313 template <>
00314 struct node_traits<unsigned long>
00315 {
00316 static const enum config_node::type type=config_node::NUMBER;
00317
00318 static inline unsigned long value(const config_node &node)
00319 {
00320 return node.number;
00321 }
00322 };
00323
00324 template <>
00325 struct node_traits<std::string>
00326 {
00327 static const enum config_node::type type=config_node::STRING;
00328
00329 static inline std::string value(const config_node &node)
00330 {
00331 return node.string;
00332 }
00333 };
00334 }
00335
00336 #endif
00337
00338
00339