Implementation might not be robust,

...but persist_context now correctly populates parent and child nodes
based on persist config file contents.
This commit is contained in:
Jody Northup 2010-05-29 11:00:21 +00:00
parent a10698cc01
commit 3235ef47bf
2 changed files with 127 additions and 36 deletions

View file

@ -21,16 +21,24 @@
#include "resources.hpp"
#include "serialization/binary_or_text.hpp"
static bool is_valid_namespace(const std::string &name_space)
{
return (name_space.find_first_not_of("!'(),-0123456789;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") > name_space.length());
static bool is_valid_namespace(const std::string &name_space) {
return (name_space.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_") > name_space.length());
}
static std::string get_persist_cfg_name(const std::string &name_space)
{
static std::string get_namespace_ancestry(const std::string &name_space) {
return name_space.substr(0,name_space.find_last_of("."));
}
static std::string get_namespace_leaf(const std::string &name_space) {
return name_space.substr(name_space.find_last_of(".") + 1);
}
static std::string get_namespace_root(const std::string &name_space) {
return name_space.substr(0,name_space.find_first_of("."));
}
static std::string get_persist_cfg_name(const std::string &name_space) {
// TODO: get namespace base name
if (is_valid_namespace(name_space))
return (get_dir(get_user_data_dir() + "/persist/") + name_space + ".cfg");
if (is_valid_namespace(get_namespace_root(name_space)))
return (get_dir(get_user_data_dir() + "/persist/") + get_namespace_root(name_space) + ".cfg");
else
return "";
}
@ -41,7 +49,6 @@ static bool load_persist_data(const std::string &name_space, config &cfg, const
std::string cfg_dir = get_dir(get_user_data_dir() + "/persist");
create_directory_if_missing(cfg_dir);
// TODO: Support nested namespaces
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
scoped_istream file_stream = istream_file(cfg_name);
@ -67,7 +74,6 @@ static bool save_persist_data(std::string &name_space, config &cfg)
{
bool success = false;
// TODO: Support nested namespaces
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
if (cfg.empty()) {
@ -97,22 +103,73 @@ config pack_scalar(const std::string &name, const t_string &val)
return cfg;
}
// TODO: support nested namespaces
persist_context::persist_context(const std::string &name_space) : namespace_(name_space), cfg_(), valid_(is_valid_namespace(namespace_.substr(0,name_space.find_first_of(".")))) {}
void persist_context::load() {
if (parent_ == NULL)
load_persist_data(namespace_,cfg_,false);
for (config::all_children_iterator i = cfg_.ordered_begin(); i != cfg_.ordered_end(); i++) {
if (i->key != "variables") {
if (children_.find(i->key) == children_.end()) {
persist_context *child = new persist_context(i->key);
children_[i->key] = child;
}
children_[i->key]->parent_ = this;
children_[i->key]->cfg_ = cfg_.child_or_add(i->key);
}
}
}
void persist_context::init(const std::string &name_space) {
if (name_space.find_last_of(".") < name_space.length()) {
std::string ancestry = get_namespace_ancestry(name_space);
std::string parent_name = get_namespace_leaf(ancestry);
parent_ = new persist_context(ancestry,*this);
}
load();
if (!cfg_.child("variables"))
cfg_.add_child("variables");
}
persist_context::persist_context(const std::string &name_space) :
namespace_(get_namespace_leaf(name_space)),
cfg_(),
parent_(NULL),
children_(),
valid_(is_valid_namespace(namespace_)),
dirty_(false)
{
init(name_space);
}
persist_context::persist_context(const std::string &name_space, persist_context &child) :
namespace_(get_namespace_leaf(name_space)),
cfg_(),
parent_(NULL),
children_(),
valid_(is_valid_namespace(namespace_)),
dirty_(false)
{
children_[child.namespace_] = &child;
init(name_space);
if (!cfg_.child(child.namespace_))
cfg_.add_child(child.namespace_);
}
persist_context::~persist_context() {
for (persist_context::child_map::iterator i = children_.begin(); i != children_.end(); i++)
delete i->second;
}
bool persist_context::clear_var(std::string &global)
{
if (cfg_.empty()) {
load_persist_data(namespace_,cfg_);
if (!cfg_.child("variables"))
cfg_.add_child("variables");
}
// TODO: get config's variables.
bool exists = cfg_.child("variables").has_attribute(global);
config &cfg = cfg_.child("variables");
bool exists = cfg.has_attribute(global);
bool ret;
if (!exists) {
if (cfg_.child("variables").child(global)) {
if (cfg.child(global)) {
exists = true;
std::string::iterator index_start = std::find(global.begin(),global.end(),'[');
if (index_start != global.end())
@ -120,19 +177,20 @@ bool persist_context::clear_var(std::string &global)
const std::string::iterator index_end = std::find(global.begin(),global.end(),']');
const std::string index_str(index_start+1,index_end);
size_t index = static_cast<size_t>(lexical_cast_default<int>(index_str));
cfg_.child("variables").remove_child(global,index);
cfg.remove_child(global,index);
} else {
cfg_.child("variables").clear_children(global);
cfg.clear_children(global);
}
}
}
if (exists) {
cfg_.child("variables").remove_attribute(global);
if (cfg_.child("variables").empty()) {
cfg.remove_attribute(global);
if (cfg.empty()) {
cfg_.clear_children("variables");
cfg_.remove_attribute("variables");
}
ret = save_persist_data(namespace_,cfg_);
dirty_ = true;
ret = save_context();
} else {
ret = exists;
}
@ -144,31 +202,45 @@ config persist_context::get_var(const std::string &global)
config ret;
if (cfg_.empty()) {
load_persist_data(namespace_,cfg_,false);
if (!cfg_.child("variables"))
cfg_.add_child("variables");
}
//TODO: get config's [variables]
if (cfg_.child("variables").child(global)) {
ret.add_child(global,cfg_.child("variables").child(global));
config &cfg = cfg_.child("variables");
if (cfg.child(global)) {
ret.add_child(global,cfg.child(global));
} else {
ret = pack_scalar(global,cfg_.child("variables")[global]);
ret = pack_scalar(global,cfg[global]);
}
return ret;
}
void persist_context::update_configs() {
for (child_map::iterator i = children_.begin(); i != children_.end(); i++) {
if (i->second->dirty()) {
i->second->update_configs();
cfg_.clear_children(i->second->namespace_);
cfg_.remove_attribute(i->second->namespace_);
cfg_.add_child(i->second->namespace_,i->second->cfg_);
i->second->dirty_ = false;
}
}
}
bool persist_context::save_context() {
if (parent_ != NULL)
return parent_->save_context();
update_configs();
return save_persist_data(namespace_,cfg_);
}
bool persist_context::set_var(const std::string &global,const config &val)
{
if (cfg_.empty()) {
load_persist_data(namespace_,cfg_);
if (!cfg_.child("variables"))
cfg_.add_child("variables");
}
//TODO: get config's [variables]
config &cfg = cfg_.child("variables");
if (val.has_attribute(global)) {
cfg_.child("variables")[global] = val[global];
cfg[global] = val[global];
} else {
cfg_.child("variables").add_child(global,val.child(global));
cfg.add_child(global,val.child(global));
}
return save_persist_data(namespace_,cfg_);
dirty_ = true;
return save_context();
}

View file

@ -23,16 +23,35 @@ static lg::log_domain log_persist("engine/persistence");
config pack_scalar(const std::string &,const t_string &);
class persist_context {
private:
// TODO: dirty marking
// TODO: child persist_contexts for embedded namespaces?
// TODO: transaction support (needed for MP)
typedef std::map<std::string,persist_context*> child_map;
// TODO: parent and child members (needed for namespace embeddeding)
std::string namespace_;
config cfg_;
persist_context *parent_;
child_map children_;
bool valid_;
bool dirty_;
void load();
void init(const std::string &name_space);
bool save_context();
void update_configs();
public:
persist_context(const std::string &);
persist_context(const std::string &, persist_context &);
~persist_context();
bool clear_var(std::string &);
config get_var(const std::string &);
bool set_var(const std::string &, const config &);
bool valid() const { return valid_; };
bool dirty() const {
bool dirt = dirty_;
child_map::const_iterator i = children_.begin();
while ((!dirt) && (i != children_.end())) {
dirt |= i->second->dirty();
i++;
}
return dirt;
};
};
#endif