Refactor persist_context to correct subnamespace crash and avoid holding stale config references in general.

This commit is contained in:
upthorn 2013-04-13 05:08:38 -07:00 committed by Ignacio R. Morelle
parent 70902724a6
commit c6da4fcbd0
2 changed files with 92 additions and 119 deletions

View file

@ -53,30 +53,29 @@ persist_file_context::persist_file_context(const std::string &name_space)
: persist_context(name_space)
{
load();
root_node_.init();
active_ = &(root_node_.child(namespace_.next()));
}
bool persist_file_context::clear_var(const std::string &global, bool immediate)
{
// if (cfg_.empty()) {
// load_persist_data(namespace_.root(),cfg_);
// }
config bak;
config bactive;
if (immediate) {
bak = cfg_;
bactive = active_->cfg_.child_or_add("variables");
config *node = get_node(bak, namespace_);
if (node)
bactive = node->child_or_add("variables");
load();
root_node_.init();
}
config &cfg = active_->cfg_.child_or_add("variables");
bool ret(cfg);
config *active = get_node(cfg_, namespace_);
if (active == NULL)
return false;
bool ret = active->has_child("variables");
if (ret) {
config &cfg = active->child("variables");
bool exists = cfg.has_attribute(global);
if (!exists) {
if (cfg.child(global)) {
if (cfg.has_child(global)) {
exists = true;
std::string::const_iterator index_start = std::find(global.begin(),global.end(),'[');
if (index_start != global.end())
@ -96,52 +95,69 @@ bool persist_file_context::clear_var(const std::string &global, bool immediate)
cfg.remove_attribute(global);
if (immediate) bactive.remove_attribute(global);
if (cfg.empty()) {
active_->cfg_.clear_children("variables");
active_->cfg_.remove_attribute("variables");
while ((active_->cfg_.empty()) && (active_->parent_ != NULL)) {
active_ = active_->parent_;
active_->remove_child(namespace_.node_);
namespace_ = namespace_.prev();
active->clear_children("variables");
active->remove_attribute("variables");
name_space working = namespace_;
while ((active->empty()) && (!working.lineage_.empty())) {
name_space prev = working.prev();
active = get_node(cfg_, prev);
active->clear_children(working.node_);
if (active->has_child("variables") && active->child("variables").empty()) {
active->clear_children("variables");
active->remove_attribute("variables");
}
working = prev;
}
}
// dirty_ = true;
if (!in_transaction_)
ret = save_context();
else if (immediate) {
ret = save_context();
cfg_ = bak;
root_node_.init();
active_->cfg_.clear_children("variables");
active_->cfg_.remove_attribute("variables");
active_->cfg_.add_child("variables",bactive);
config &cfg = active_->cfg_.child("variables");
if (cfg.empty()) {
active_->cfg_.clear_children("variables");
active_->cfg_.remove_attribute("variables");
while ((active_->cfg_.empty()) && (active_->parent_ != NULL)) {
active_ = active_->parent_;
active_->remove_child(namespace_.node_);
namespace_ = namespace_.prev();
}
active = get_node(cfg_, namespace_);
if (active != NULL) {
active->clear_children("variables");
active->remove_attribute("variables");
if (!bactive.empty())
active->add_child("variables",bactive);
}
} else
} else {
ret = true;
}
} else {
if (immediate) {
cfg_ = bak;
config *active = get_node(cfg_, namespace_);
if (active != NULL) {
active->clear_children("variables");
active->remove_attribute("variables");
if (!bactive.empty())
active->add_child("variables",bactive);
}
}
ret = exists;
}
}
while ((active->empty()) && (!namespace_.lineage_.empty())) {
name_space prev = namespace_.prev();
active = get_node(cfg_, prev);
active->clear_children(namespace_.node_);
if (active->has_child("variables") && active->child("variables").empty()) {
active->clear_children("variables");
active->remove_attribute("variables");
}
namespace_ = prev;
}
return ret;
}
config persist_file_context::get_var(const std::string &global) const
{
config ret;
// if (cfg_.empty()) {
// load_persist_data(namespace_,cfg_,false);
// }
config &cfg = active_->cfg_.child("variables");
if (cfg) {
const config *active = get_node(cfg_, namespace_);
if (active && (active->has_child("variables"))) {
const config &cfg = active->child("variables");
size_t arrsize = cfg.child_count(global);
if (arrsize > 0) {
for (size_t i = 0; i < arrsize; i++)
@ -180,19 +196,16 @@ bool persist_file_context::save_context() {
}
bool persist_file_context::set_var(const std::string &global,const config &val, bool immediate)
{
// if (cfg_.empty()) {
// load_persist_data(namespace_,cfg_);
// }
config bak;
config bactive;
if (immediate) {
bak = cfg_;
bactive = active_->cfg_.child_or_add("variables");
bactive = get_node(bak, namespace_, true)->child_or_add("variables");
load();
root_node_.init();
}
config &cfg = active_->cfg_.child_or_add("variables");
config *active = get_node(cfg_, namespace_, true);
config &cfg = active->child_or_add("variables");
if (val.has_attribute(global)) {
if (val[global].empty()) {
clear_var(global,immediate);
@ -214,17 +227,20 @@ bool persist_file_context::set_var(const std::string &global,const config &val,
else if (immediate) {
bool ret = save_context();
cfg_ = bak;
root_node_.init();
active_->cfg_.clear_children("variables");
active_->cfg_.remove_attribute("variables");
active_->cfg_.add_child("variables",bactive);
active = get_node(cfg_, namespace_, true);
active->clear_children("variables");
active->remove_attribute("variables");
active->add_child("variables",bactive);
return ret;
} else
return true;
}
void persist_context::set_node(const std::string &name) {
active_ = &(root_node_.child(name));
namespace_ = name_space(namespace_.namespace_ + "." + name);
std::string newspace = namespace_.root_;
if (!name.empty())
newspace += "." + name;
namespace_ = name_space(newspace);
}
std::string persist_context::get_node() const

View file

@ -99,80 +99,14 @@ public:
}
};
protected:
struct node {
typedef std::map<std::string,node*> child_map;
std::string name_;
persist_context *root_;
node *parent_;
child_map children_;
config &cfg_;
node(std::string name, persist_context *root, config & cfg, node *parent = NULL)
: name_(name)
, root_(root)
, parent_(parent)
, children_()
, cfg_(cfg)
{
}
~node() {
for (child_map::iterator i = children_.begin(); i != children_.end(); ++i)
delete (i->second);
}
config &cfg() { return cfg_; }
node &add_child(const std::string &name) {
children_[name] = new node(name,root_,cfg_.child_or_add(name),this);
return *(children_[name]);
}
bool remove_child(const std::string &name) {
bool ret = false;
if (children_.find(name) != children_.end()) {
cfg_.clear_children(name);
cfg_.remove_attribute(name);
if (cfg_.child("variables").empty()) {
cfg_.clear_children("variables");
cfg_.remove_attribute("variables");
}
delete children_[name];
children_.erase(name);
ret = true;
}
return ret;
}
node &child(const name_space &name) {
if (name) {
if (children_.find(name.root_) == children_.end())
add_child(name.root_);
node &chld = *children_[name.root_];
return chld.child(name.next());
}
else return *this;
}
void init () {
for (config::all_children_iterator i = cfg_.ordered_begin(); i != cfg_.ordered_end(); ++i) {
if (i->key != "variables") {
child(i->key).init();
}
}
if (!cfg_.child("variables"))
cfg_.add_child("variables");
}
};
config cfg_;
name_space namespace_;
node root_node_;
node *active_;
bool valid_;
bool in_transaction_;
persist_context()
: cfg_()
, namespace_()
, root_node_("",this,cfg_)
, active_(&root_node_)
, valid_(false)
, in_transaction_(false)
{};
@ -180,12 +114,36 @@ protected:
persist_context(const std::string &name_space)
: cfg_()
, namespace_(name_space,true)
, root_node_(namespace_.root_,this,cfg_)
, active_(&root_node_)
, valid_(namespace_.valid())
, in_transaction_(false)
{};
config *get_node(config &cfg, name_space &ns, bool force = false) {
name_space next = ns.next();
if (next) {
if (force)
return get_node(cfg.child_or_add(next.root_), next, true);
else if (cfg.has_child(next.root_))
return get_node(cfg.child(next.root_), next);
else
return NULL;
}
else
return &cfg;
}
const config *get_node(const config &cfg, const name_space &ns) const {
name_space next = ns.next();
if (next) {
if (cfg.has_child(next.root_))
return get_node(cfg.child(next.root_), next);
else
return NULL;
}
else
return &cfg;
}
public:
virtual bool clear_var(const std::string &, bool immediate = false) = 0;
virtual config get_var(const std::string &) const = 0;
@ -231,7 +189,6 @@ public:
if (!in_transaction_)
return false;
load();
root_node_.init();
in_transaction_ = false;
return true;
}