made simple WML ordered properly

This commit is contained in:
Gunter Labes 2009-02-01 12:41:34 +00:00
parent f07b02eb6e
commit 5209493bc5
2 changed files with 181 additions and 37 deletions

View file

@ -153,11 +153,14 @@ node::node(document& doc, node* parent, const char** str, int depth)
throw error("unterminated element");
}
child_list& list = get_children(string_span(s, end - s));
const int list_index = get_children(string_span(s, end - s));
check_ordered_children();
s = end + 1;
list.push_back(new node(doc, this, str, depth+1));
children_[list_index].second.push_back(new node(doc, this, str, depth+1));
ordered_children_.push_back(node_pos(list_index, children_[list_index].second.size() - 1));
check_ordered_children();
break;
}
@ -236,6 +239,7 @@ node::node(document& doc, node* parent, const char** str, int depth)
}
output_cache_ = string_span(begin, s - begin);
check_ordered_children();
}
node::~node()
@ -330,12 +334,17 @@ node& node::add_child_at(const char* name, size_t index)
{
set_dirty();
child_list& list = get_children(name);
const int list_index = get_children(name);
child_list& list = children_[list_index].second;
if(index > list.size()) {
index = list.size();
}
check_ordered_children();
list.insert(list.begin() + index, new node(*doc_, this));
insert_ordered_child(list_index, index);
check_ordered_children();
return *list[index];
}
@ -344,8 +353,12 @@ node& node::add_child(const char* name)
{
set_dirty();
child_list& list = get_children(name);
const int list_index = get_children(name);
check_ordered_children();
child_list& list = children_[list_index].second;
list.push_back(new node(*doc_, this));
ordered_children_.push_back(node_pos(list_index, list.size() - 1));
check_ordered_children();
return *list.back();
}
@ -364,14 +377,109 @@ void node::remove_child(const string_span& name, size_t index)
return;
}
remove_ordered_child(itor - children_.begin(), index);
delete list[index];
list.erase(list.begin() + index);
if(list.empty()) {
remove_ordered_child_list(itor - children_.begin());
children_.erase(itor);
}
}
void node::insert_ordered_child(int child_map_index, int child_list_index)
{
bool inserted = false;
std::vector<node_pos>::iterator i = ordered_children_.begin();
while(i != ordered_children_.end()) {
if(i->child_map_index == child_map_index && i->child_list_index > child_list_index) {
i->child_list_index++;
} else if(i->child_map_index == child_map_index && i->child_list_index == child_list_index) {
inserted = true;
i->child_list_index++;
i = ordered_children_.insert(i, node_pos(child_map_index, child_list_index));
++i;
}
++i;
}
if(!inserted) {
ordered_children_.push_back(node_pos(child_map_index, child_list_index));
}
}
void node::remove_ordered_child(int child_map_index, int child_list_index)
{
std::vector<node_pos>::iterator i = ordered_children_.begin();
while(i != ordered_children_.end()) {
if(i->child_map_index == child_map_index && i->child_list_index == child_list_index) {
i = ordered_children_.erase(i);
} else {
if(i->child_map_index == child_map_index && i->child_list_index > child_list_index) {
i->child_list_index--;
}
++i;
}
}
}
void node::insert_ordered_child_list(int child_map_index)
{
std::vector<node_pos>::iterator i = ordered_children_.begin();
while(i != ordered_children_.end()) {
if(i->child_map_index >= child_map_index) {
i->child_map_index++;
}
}
}
void node::remove_ordered_child_list(int child_map_index)
{
std::vector<node_pos>::iterator i = ordered_children_.begin();
while(i != ordered_children_.end()) {
if(i->child_map_index == child_map_index) {
i = ordered_children_.erase(i);
} else {
if(i->child_map_index > child_map_index) {
i->child_map_index--;
}
++i;
}
}
}
void node::check_ordered_children() const
{
// only define this symbol in debug mode to work out child ordering.
#ifdef CHECK_ORDERED_CHILDREN
std::vector<node_pos>::const_iterator i = ordered_children_.begin();
while(i != ordered_children_.end()) {
assert(i->child_map_index < children_.size());
assert(i->child_list_index < children_[i->child_map_index].second.size());
++i;
}
for(child_map::const_iterator j = children_.begin(); j != children_.end(); ++j) {
const unsigned short child_map_index = j - children_.begin();
for(child_list::const_iterator k = j->second.begin(); k != j->second.end(); ++k) {
const unsigned short child_list_index = k - j->second.begin();
bool found = false;
for(int n = 0; n != ordered_children_.size(); ++n) {
if(ordered_children_[n].child_map_index == child_map_index &&
ordered_children_[n].child_list_index == child_list_index) {
found = true;
break;
}
}
assert(found);
}
}
#endif // CHECK_ORDERED_CHILDREN
}
void node::remove_child(const char* name, size_t index)
{
remove_child(string_span(name), index);
@ -416,21 +524,21 @@ const node::child_list& node::children(const char* name) const
return empty;
}
node::child_list& node::get_children(const char* name)
int node::get_children(const char* name)
{
return get_children(string_span(name));
}
node::child_list& node::get_children(const string_span& name)
int node::get_children(const string_span& name)
{
for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
if(i->first == name) {
return i->second;
return i - children_.begin();
}
}
children_.push_back(child_pair(string_span(name), child_list()));
return children_.back().second;
return children_.size() - 1;
}
node::child_map::const_iterator node::find_in_map(const child_map& m, const string_span& attr)
@ -469,6 +577,7 @@ const string_span& node::first_child() const
int node::output_size() const
{
check_ordered_children();
if(output_cache_.empty() == false) {
return output_cache_.size();
}
@ -478,13 +587,17 @@ int node::output_size() const
res += i->first.size() + i->second.size() + 4;
}
int count_children = 0;
for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
for(child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
res += i->first.size()*2 + 7;
res += (*j)->output_size();
++count_children;
}
}
assert(count_children == ordered_children_.size());
return res;
}
@ -532,23 +645,24 @@ void node::output(char*& buf)
*buf++ = '\n';
}
for(child_map::iterator i = children_.begin(); i != children_.end(); ++i) {
assert(i->second.empty() == false);
for(child_list::iterator j = i->second.begin(); j != i->second.end(); ++j) {
*buf++ = '[';
memcpy(buf, i->first.begin(), i->first.size());
i->first = string_span(buf, i->first.size());
buf += i->first.size();
*buf++ = ']';
*buf++ = '\n';
(*j)->output(buf);
*buf++ = '[';
*buf++ = '/';
memcpy(buf, i->first.begin(), i->first.size());
buf += i->first.size();
*buf++ = ']';
*buf++ = '\n';
}
for(std::vector<node_pos>::const_iterator i = ordered_children_.begin();
i != ordered_children_.end(); ++i) {
assert(i->child_map_index < children_.size());
assert(i->child_list_index < children_[i->child_map_index].second.size());
string_span& attr = children_[i->child_map_index].first;
*buf++ = '[';
memcpy(buf, attr.begin(), attr.size());
attr = string_span(buf, attr.size());
buf += attr.size();
*buf++ = ']';
*buf++ = '\n';
children_[i->child_map_index].second[i->child_list_index]->output(buf);
*buf++ = '[';
*buf++ = '/';
memcpy(buf, attr.begin(), attr.size());
buf += attr.size();
*buf++ = ']';
*buf++ = '\n';
}
output_cache_ = string_span(begin, buf - begin);
@ -565,17 +679,13 @@ void node::copy_into(node& n) const
n.set_attr(key, value);
}
for(child_map::const_iterator i = children_.begin(); i != children_.end(); ++i) {
if(i->second.empty()) {
continue;
}
char* buf = i->first.duplicate();
for(std::vector<node_pos>::const_iterator i = ordered_children_.begin();
i != ordered_children_.end(); ++i) {
assert(i->child_map_index < children_.size());
assert(i->child_list_index < children_[i->child_map_index].second.size());
char* buf = children_[i->child_map_index].first.duplicate();
n.doc_->take_ownership_of_buffer(buf);
for(child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
(*j)->copy_into(n.add_child(buf));
}
children_[i->child_map_index].second[i->child_list_index]->copy_into(n.add_child(buf));
}
}

View file

@ -104,9 +104,23 @@ public:
bool has_attr(const char* key) const;
//sets an attribute in the WML node. The node will keep a direct reference
//to key and value which it will maintain for its lifetime. The caller
//MUST guarantee that the key and value buffers remain valid for the
//lifetime of the node.
node& set_attr(const char* key, const char* value);
//functions which are identical to set_attr() except that the buffer
//referred to by 'value' will be duplicated and the new buffer managed by
//the node. The caller may destroy the value buffer as soon as the function
//returns. The key buffer must remain valid for the lifetime of the node.
node& set_attr_dup(const char* key, const char* value);
node& set_attr_dup(const char* key, const string_span& value);
//sets an attribute with identical behavior to set_attr_dup, except that
//the buffer referred to by 'key' will also be duplicated and managed by
//the node. The caller may destroy both key and value as soon as the
//call returns.
node& set_attr_dup_key_and_value(const char* key, const char* value);
node& set_attr_int(const char* key, int value);
@ -144,8 +158,8 @@ private:
node(const node&);
void operator=(const node&);
child_list& get_children(const string_span& name);
child_list& get_children(const char* name);
int get_children(const string_span& name);
int get_children(const char* name);
void set_dirty();
void shift_buffers(ptrdiff_t offset);
@ -164,6 +178,26 @@ private:
static child_map::iterator find_in_map(child_map& m, const string_span& attr);
child_map children_;
//a node position indicates the index into the child map where the node
//is, and then the index into the child list within where the node is.
struct node_pos {
node_pos(int child_map_index, int child_list_index)
: child_map_index(child_map_index), child_list_index(child_list_index)
{}
unsigned short child_map_index;
unsigned short child_list_index;
};
//a list of all the children in order.
std::vector<node_pos> ordered_children_;
void insert_ordered_child(int child_map_index, int child_list_index);
void remove_ordered_child(int child_map_index, int child_list_index);
void insert_ordered_child_list(int child_map_index);
void remove_ordered_child_list(int child_map_index);
void check_ordered_children() const;
string_span output_cache_;
};