made simple WML ordered properly
This commit is contained in:
parent
f07b02eb6e
commit
5209493bc5
2 changed files with 181 additions and 37 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue