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:
parent
a10698cc01
commit
3235ef47bf
2 changed files with 127 additions and 36 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue