00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef PERSIST_CONTEXT_H_INCLUDED
00017 #define PERSIST_CONTEXT_H_INCLUDED
00018 #include "config.hpp"
00019 #include "log.hpp"
00020 static lg::log_domain log_persist("engine/persistence");
00021
00022 #define LOG_PERSIST LOG_STREAM(info, log_persist)
00023 #define ERR_PERSist LOG_STREAM(err, log_persist)
00024 config pack_scalar(const std::string &,const t_string &);
00025 class persist_context {
00026 public:
00027
00028 virtual ~persist_context() {}
00029
00030 struct name_space {
00031 std::string namespace_;
00032 std::string root_;
00033 std::string node_;
00034 std::string lineage_;
00035 std::string descendants_;
00036 bool valid_;
00037
00038 bool valid() const {
00039 return valid_;
00040 }
00041 void parse() {
00042 while (namespace_.find_first_of("^") < namespace_.size()) {
00043 if (namespace_[0] == '^') {
00044
00045 namespace_ = "";
00046 break;
00047 }
00048 std::string infix = namespace_.substr(namespace_.find_first_of("^"));
00049 size_t end = infix.find_first_not_of("^");
00050 if (!((end >= infix.length()) || (infix[end] == '.'))) {
00051
00052 namespace_ = "";
00053 break;
00054 }
00055 infix = infix.substr(0,end);
00056 std::string suffix = namespace_.substr(namespace_.find_first_of("^") + infix.length());
00057 while (!infix.empty())
00058 {
00059 std::string body = namespace_.substr(0,namespace_.find_first_of("^"));
00060 body = body.substr(0,body.find_last_of("."));
00061 infix = infix.substr(1);
00062 namespace_ = body + infix + suffix;
00063 }
00064 }
00065 }
00066 name_space next() const {
00067 return name_space(descendants_);
00068 }
00069 name_space prev() const {
00070 return name_space(lineage_);
00071 }
00072 operator bool () const { return valid_; }
00073 name_space()
00074 : namespace_()
00075 , root_()
00076 , node_()
00077 , lineage_()
00078 , descendants_()
00079 , valid_(false)
00080 {
00081 }
00082
00083 name_space(const std::string &ns, bool doParse = false)
00084 : namespace_(ns)
00085 , root_()
00086 , node_()
00087 , lineage_()
00088 , descendants_()
00089 , valid_(false)
00090 {
00091 if (doParse)
00092 parse();
00093 valid_ = ((namespace_.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.") > namespace_.length()) && !namespace_.empty());
00094 root_ = namespace_.substr(0,namespace_.find_first_of("."));
00095 node_ = namespace_.substr(namespace_.find_last_of(".") + 1);
00096 if (namespace_.find_last_of(".") <= namespace_.length())
00097 lineage_ = namespace_.substr(0,namespace_.find_last_of("."));
00098 if (namespace_.find_first_of(".") <= namespace_.length())
00099 descendants_ = namespace_.substr(namespace_.find_first_of(".") + 1);
00100 }
00101 };
00102 protected:
00103 struct node {
00104 typedef std::map<std::string,node*> child_map;
00105
00106 std::string name_;
00107 persist_context *root_;
00108 node *parent_;
00109 child_map children_;
00110 config &cfg_;
00111
00112 node(std::string name, persist_context *root, config & cfg, node *parent = NULL)
00113 : name_(name)
00114 , root_(root)
00115 , parent_(parent)
00116 , children_()
00117 , cfg_(cfg)
00118 {
00119 }
00120
00121 ~node() {
00122 for (child_map::iterator i = children_.begin(); i != children_.end(); ++i)
00123 delete (i->second);
00124 }
00125 config &cfg() { return cfg_; }
00126 node &add_child(const std::string &name) {
00127 children_[name] = new node(name,root_,cfg_.child_or_add(name),this);
00128 return *(children_[name]);
00129 }
00130 bool remove_child(const std::string &name) {
00131 bool ret = false;
00132 if (children_.find(name) != children_.end()) {
00133 cfg_.clear_children(name);
00134 cfg_.remove_attribute(name);
00135 if (cfg_.child("variables").empty()) {
00136 cfg_.clear_children("variables");
00137 cfg_.remove_attribute("variables");
00138 }
00139 delete children_[name];
00140 children_.erase(name);
00141 ret = true;
00142 }
00143 return ret;
00144 }
00145 node &child(const name_space &name) {
00146 if (name) {
00147 if (children_.find(name.root_) == children_.end())
00148 add_child(name.root_);
00149 node &chld = *children_[name.root_];
00150 return chld.child(name.next());
00151 }
00152 else return *this;
00153 }
00154 void init () {
00155 for (config::all_children_iterator i = cfg_.ordered_begin(); i != cfg_.ordered_end(); ++i) {
00156 if (i->key != "variables") {
00157 child(i->key).init();
00158 }
00159 }
00160 if (!cfg_.child("variables"))
00161 cfg_.add_child("variables");
00162 }
00163 };
00164
00165 config cfg_;
00166 name_space namespace_;
00167 node root_node_;
00168 node *active_;
00169 bool valid_;
00170 bool in_transaction_;
00171
00172 persist_context()
00173 : cfg_()
00174 , namespace_()
00175 , root_node_("",this,cfg_)
00176 , active_(&root_node_)
00177 , valid_(false)
00178 , in_transaction_(false)
00179 {};
00180
00181 persist_context(const std::string &name_space)
00182 : cfg_()
00183 , namespace_(name_space,true)
00184 , root_node_(namespace_.root_,this,cfg_)
00185 , active_(&root_node_)
00186 , valid_(namespace_.valid())
00187 , in_transaction_(false)
00188 {};
00189
00190 public:
00191 virtual bool clear_var(const std::string &, bool immediate = false) = 0;
00192 virtual config get_var(const std::string &) const = 0;
00193 virtual bool set_var(const std::string &, const config &, bool immediate = false) = 0;
00194 virtual bool start_transaction () = 0;
00195 virtual bool end_transaction () = 0;
00196 virtual bool cancel_transaction () = 0;
00197 std::string get_node() const;
00198 void set_node(const std::string &);
00199 bool valid() const { return valid_; };
00200 bool dirty() const {
00201 return true;
00202 };
00203 operator bool() const { return valid_; }
00204 };
00205
00206 class persist_file_context : public persist_context {
00207 private:
00208 void load();
00209 void init();
00210 bool save_context();
00211
00212 public:
00213 persist_file_context(const std::string &name_space);
00214 bool clear_var(const std::string &, bool immediate = false);
00215 config get_var(const std::string &) const;
00216 bool set_var(const std::string &, const config &, bool immediate = false);
00217
00218 bool start_transaction () {
00219 if (in_transaction_)
00220 return false;
00221 in_transaction_ = true;
00222 return true;
00223 }
00224 bool end_transaction () {
00225 if (!in_transaction_)
00226 return false;
00227 in_transaction_ = false;
00228 save_context();
00229 return true;
00230 }
00231 bool cancel_transaction () {
00232 if (!in_transaction_)
00233 return false;
00234 load();
00235 root_node_.init();
00236 in_transaction_ = false;
00237 return true;
00238 }
00239 };
00240 #endif