diff --git a/src/server/simple_wml.cpp b/src/server/simple_wml.cpp index b9d187c6bf2..5f2e41ef1a7 100644 --- a/src/server/simple_wml.cpp +++ b/src/server/simple_wml.cpp @@ -162,11 +162,12 @@ 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)); 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)); break; } @@ -339,12 +340,14 @@ 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(); } list.insert(list.begin() + index, new node(*doc_, this)); + insert_ordered_child(list_index, index); return *list[index]; } @@ -353,8 +356,10 @@ node& node::add_child(const char* name) { set_dirty(); - child_list& list = get_children(name); + const int list_index = get_children(name); + 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)); return *list.back(); } @@ -373,14 +378,64 @@ void node::remove_child(const string_span& name, size_t index) return; } + remove_ordered_child(itor - children_.begin(), index); + debug_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) +{ + + std::vector::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) { + i->child_list_index++; + i = ordered_children_.insert(i, node_pos(child_map_index, child_list_index)); + ++i; + } + + ++i; + } +} + +void node::remove_ordered_child(int child_map_index, int child_list_index) +{ + std::vector::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::remove_ordered_child_list(int child_map_index) +{ + std::vector::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->child_map_index--; + } + } +} + void node::remove_child(const char* name, size_t index) { remove_child(string_span(name), index); @@ -425,21 +480,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) @@ -487,13 +542,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; } @@ -541,23 +600,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::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); @@ -574,17 +634,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::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)); } } diff --git a/src/server/simple_wml.hpp b/src/server/simple_wml.hpp index a4244bc57b9..cdfd49639f8 100644 --- a/src/server/simple_wml.hpp +++ b/src/server/simple_wml.hpp @@ -144,8 +144,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 +164,23 @@ 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 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 remove_ordered_child_list(int child_map_index); + string_span output_cache_; };