Improvements to the config interfaces, mainly iterators

- config::attribute_count() now excludes blank (ie, unset) attributes
  Blank attributes in the map are generally a result of the mutating
  behaviour of operator[], so they're not "logically" existing attributes.
- Non-const versions of attribute iterator and all-children iterator
- Attribute iterators are now bi-directional
- vconfig all-children iterator is now a bi-directional Boost iterator range
- vconfig now has a bidirectional attribute iterator
This commit is contained in:
Celtic Minstrel 2016-08-29 14:24:19 -04:00
parent e5354766ce
commit 116ff67c6e
8 changed files with 277 additions and 38 deletions

View file

@ -648,6 +648,13 @@ unsigned config::all_children_count() const
return ordered_children.size(); return ordered_children.size();
} }
unsigned config::attribute_count() const
{
return std::count_if(values.begin(), values.end(), [](const attribute& v) {
return !v.second.blank();
});
}
bool config::has_child(const std::string &key) const bool config::has_child(const std::string &key) const
{ {
check_valid(); check_valid();
@ -987,8 +994,26 @@ config::const_attr_itors config::attribute_range() const
{ {
check_valid(); check_valid();
return const_attr_itors(const_attribute_iterator(values.begin()), const_attr_itors range (const_attribute_iterator(values.begin()),
const_attribute_iterator(values.end())); const_attribute_iterator(values.end()));
// Ensure the first element is not blank, as a few places assume this
while(range.begin() != range.end() && range.begin()->second.blank()) {
range.pop_front();
}
return range;
}
config::attr_itors config::attribute_range()
{
check_valid();
attr_itors range(attribute_iterator(values.begin()), attribute_iterator(values.end()));
// Ensure the first element is not blank, as a few places assume this
while(range.begin() != range.end() && range.begin()->second.blank()) {
range.pop_front();
}
return range;
} }
namespace { namespace {
@ -1116,17 +1141,49 @@ config::all_children_iterator::reference config::all_children_iterator::operator
return any_child(&i_->pos->first, i_->pos->second[i_->index]); return any_child(&i_->pos->first, i_->pos->second[i_->index]);
} }
config::all_children_iterator config::ordered_begin() const config::const_all_children_iterator::reference config::const_all_children_iterator::operator*() const
{
return any_child(&i_->pos->first, i_->pos->second[i_->index]);
}
config::const_all_children_iterator config::ordered_begin() const
{
return const_all_children_iterator(ordered_children.cbegin());
}
config::const_all_children_iterator config::ordered_cbegin() const
{
return const_all_children_iterator(ordered_children.cbegin());
}
config::const_all_children_iterator config::ordered_end() const
{
return const_all_children_iterator(ordered_children.cend());
}
config::const_all_children_iterator config::ordered_cend() const
{
return const_all_children_iterator(ordered_children.cend());
}
config::const_all_children_itors config::all_children_range() const
{
return const_all_children_itors(
const_all_children_iterator(ordered_children.cbegin()),
const_all_children_iterator(ordered_children.cend()));
}
config::all_children_iterator config::ordered_begin()
{ {
return all_children_iterator(ordered_children.begin()); return all_children_iterator(ordered_children.begin());
} }
config::all_children_iterator config::ordered_end() const config::all_children_iterator config::ordered_end()
{ {
return all_children_iterator(ordered_children.end()); return all_children_iterator(ordered_children.end());
} }
config::all_children_itors config::all_children_range() const config::all_children_itors config::all_children_range()
{ {
return all_children_itors( return all_children_itors(
all_children_iterator(ordered_children.begin()), all_children_iterator(ordered_children.begin()),
@ -1535,7 +1592,7 @@ bool operator==(const config& a, const config& b)
if (a.values != b.values) if (a.values != b.values)
return false; return false;
config::all_children_itors x = a.all_children_range(), y = b.all_children_range(); config::const_all_children_itors x = a.all_children_range(), y = b.all_children_range();
for (; !x.empty() && !y.empty(); x.pop_front(), y.pop_front()) { for (; !x.empty() && !y.empty(); x.pop_front(), y.pop_front()) {
if (x.front().key != y.front().key || x.front().cfg != y.front().cfg) { if (x.front().key != y.front().key || x.front().cfg != y.front().cfg) {
return false; return false;

View file

@ -142,11 +142,13 @@ public:
child_iterator &operator--() { --i_; return *this; } child_iterator &operator--() { --i_; return *this; }
child_iterator operator--(int) { return child_iterator(i_--); } child_iterator operator--(int) { return child_iterator(i_--); }
config &operator*() const { return **i_; } reference operator*() const { return **i_; }
config *operator->() const { return &**i_; } pointer operator->() const { return &**i_; }
bool operator==(const child_iterator &i) const { return i_ == i.i_; } bool operator==(const child_iterator &i) const { return i_ == i.i_; }
bool operator!=(const child_iterator &i) const { return i_ != i.i_; } bool operator!=(const child_iterator &i) const { return i_ != i.i_; }
bool operator==(const const_child_iterator &i) const { return i == *this; }
bool operator!=(const const_child_iterator &i) const { return i == *this; }
friend bool operator<(const this_type& a, const this_type& b) { return a.i_ < b.i_; } friend bool operator<(const this_type& a, const this_type& b) { return a.i_ < b.i_; }
friend bool operator<=(const this_type& a, const this_type& b) { return a.i_ <= b.i_; } friend bool operator<=(const this_type& a, const this_type& b) { return a.i_ <= b.i_; }
@ -168,7 +170,7 @@ public:
struct const_child_iterator struct const_child_iterator
{ {
typedef config value_type; typedef const config value_type;
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type; typedef int difference_type;
typedef const config *pointer; typedef const config *pointer;
@ -183,11 +185,13 @@ public:
const_child_iterator &operator--() { --i_; return *this; } const_child_iterator &operator--() { --i_; return *this; }
const_child_iterator operator--(int) { return const_child_iterator(i_--); } const_child_iterator operator--(int) { return const_child_iterator(i_--); }
const config &operator*() const { return **i_; } reference operator*() const { return **i_; }
const config *operator->() const { return &**i_; } pointer operator->() const { return &**i_; }
bool operator==(const const_child_iterator &i) const { return i_ == i.i_; } bool operator==(const const_child_iterator &i) const { return i_ == i.i_; }
bool operator!=(const const_child_iterator &i) const { return i_ != i.i_; } bool operator!=(const const_child_iterator &i) const { return i_ != i.i_; }
bool operator==(const child_iterator &i) const { return i_ == i.i_; }
bool operator!=(const child_iterator &i) const { return i_ != i.i_; }
friend bool operator<(const this_type& a, const this_type& b) { return a.i_ < b.i_; } friend bool operator<(const this_type& a, const this_type& b) { return a.i_ < b.i_; }
friend bool operator<=(const this_type& a, const this_type& b) { return a.i_ <= b.i_; } friend bool operator<=(const this_type& a, const this_type& b) { return a.i_ <= b.i_; }
@ -388,39 +392,74 @@ public:
#endif #endif
> attribute_map; > attribute_map;
typedef attribute_map::value_type attribute; typedef attribute_map::value_type attribute;
struct const_attribute_iterator;
struct attribute_iterator
{
typedef attribute value_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef attribute *pointer;
typedef attribute &reference;
typedef attribute_map::iterator Itor;
explicit attribute_iterator(const Itor &i): i_(i) {}
attribute_iterator &operator++() { ++i_; return *this; }
attribute_iterator operator++(int) { return attribute_iterator(i_++); }
attribute_iterator &operator--() { --i_; return *this; }
attribute_iterator operator--(int) { return attribute_iterator(i_--); }
reference operator*() const { return *i_; }
pointer operator->() const { return &*i_; }
bool operator==(const attribute_iterator &i) const { return i_ == i.i_; }
bool operator!=(const attribute_iterator &i) const { return i_ != i.i_; }
bool operator==(const const_attribute_iterator &i) const { return i == *this; }
bool operator!=(const const_attribute_iterator &i) const { return i == *this; }
private:
friend struct config::const_attribute_iterator;
Itor i_;
};
struct const_attribute_iterator struct const_attribute_iterator
{ {
typedef attribute value_type; typedef const attribute value_type;
typedef std::forward_iterator_tag iterator_category; typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type; typedef int difference_type;
typedef const attribute *pointer; typedef const attribute *pointer;
typedef const attribute &reference; typedef const attribute &reference;
typedef attribute_map::const_iterator Itor; typedef attribute_map::const_iterator Itor;
explicit const_attribute_iterator(const Itor &i): i_(i) {} explicit const_attribute_iterator(const Itor &i): i_(i) {}
const_attribute_iterator(attribute_iterator& i): i_(i.i_) {}
const_attribute_iterator &operator++() { ++i_; return *this; } const_attribute_iterator &operator++() { ++i_; return *this; }
const_attribute_iterator operator++(int) { return const_attribute_iterator(i_++); } const_attribute_iterator operator++(int) { return const_attribute_iterator(i_++); }
const attribute &operator*() const { return *i_; } const_attribute_iterator &operator--() { --i_; return *this; }
const attribute *operator->() const { return &*i_; } const_attribute_iterator operator--(int) { return const_attribute_iterator(i_--); }
reference operator*() const { return *i_; }
pointer operator->() const { return &*i_; }
bool operator==(const const_attribute_iterator &i) const { return i_ == i.i_; } bool operator==(const const_attribute_iterator &i) const { return i_ == i.i_; }
bool operator!=(const const_attribute_iterator &i) const { return i_ != i.i_; } bool operator!=(const const_attribute_iterator &i) const { return i_ != i.i_; }
bool operator==(const attribute_iterator &i) const { return i_ == i.i_; }
bool operator!=(const attribute_iterator &i) const { return i_ != i.i_; }
private: private:
Itor i_; Itor i_;
}; };
typedef boost::iterator_range<const_attribute_iterator> const_attr_itors; typedef boost::iterator_range<const_attribute_iterator> const_attr_itors;
typedef boost::iterator_range<attribute_iterator> attr_itors;
child_itors child_range(const std::string& key); child_itors child_range(const std::string& key);
const_child_itors child_range(const std::string& key) const; const_child_itors child_range(const std::string& key) const;
unsigned child_count(const std::string &key) const; unsigned child_count(const std::string &key) const;
unsigned all_children_count() const; unsigned all_children_count() const;
/** Note: this function also counts the 'blank' attributes, so it might return more than one might expect */ /** Count the number of non-blank attributes */
unsigned attribute_count() const unsigned attribute_count() const;
{ return values.size(); }
/** /**
* Determine whether a config has a child or not. * Determine whether a config has a child or not.
@ -572,6 +611,7 @@ public:
} }
const_attr_itors attribute_range() const; const_attr_itors attribute_range() const;
attr_itors attribute_range();
/** /**
* Returns the first child of tag @a key with a @a name attribute * Returns the first child of tag @a key with a @a name attribute
@ -623,10 +663,12 @@ public:
struct any_child struct any_child
{ {
const child_map::key_type &key; const child_map::key_type &key;
const config &cfg; config &cfg;
any_child(const child_map::key_type *k, const config *c): key(*k), cfg(*c) {} any_child(const child_map::key_type *k, config *c): key(*k), cfg(*c) {}
}; };
struct const_all_children_iterator;
struct all_children_iterator struct all_children_iterator
{ {
struct arrow_helper struct arrow_helper
@ -639,9 +681,9 @@ public:
typedef any_child value_type; typedef any_child value_type;
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type; typedef int difference_type;
typedef const arrow_helper pointer; typedef arrow_helper pointer;
typedef const any_child reference; typedef any_child reference;
typedef std::vector<child_pos>::const_iterator Itor; typedef std::vector<child_pos>::iterator Itor;
typedef all_children_iterator this_type; typedef all_children_iterator this_type;
explicit all_children_iterator(const Itor &i): i_(i) {} explicit all_children_iterator(const Itor &i): i_(i) {}
@ -653,6 +695,61 @@ public:
reference operator*() const; reference operator*() const;
pointer operator->() const { return *this; } pointer operator->() const { return *this; }
bool operator==(const all_children_iterator &i) const { return i_ == i.i_; }
bool operator!=(const all_children_iterator &i) const { return i_ != i.i_; }
bool operator==(const const_all_children_iterator &i) const { return i_ == i.i_; }
bool operator!=(const const_all_children_iterator &i) const { return i_ != i.i_; }
friend bool operator<(const this_type& a, const this_type& b) { return a.i_ < b.i_; }
friend bool operator<=(const this_type& a, const this_type& b) { return a.i_ <= b.i_; }
friend bool operator>=(const this_type& a, const this_type& b) { return a.i_ >= b.i_; }
friend bool operator>(const this_type& a, const this_type& b) { return a.i_ > b.i_; }
this_type& operator+=(difference_type n) { i_ += n; return *this; }
this_type& operator-=(difference_type n) { i_ -= n; return *this; }
reference operator[](difference_type n) const { return any_child(&i_[n].pos->first, i_[n].pos->second[i_->index]); }
friend difference_type operator-(const this_type& a, const this_type& b) { return a.i_ - b.i_; }
friend this_type operator-(const this_type& a, difference_type n) { return this_type(a.i_ - n); }
friend this_type operator+(const this_type& a, difference_type n) { return this_type(a.i_ + n); }
friend this_type operator+(difference_type n, const this_type& a) { return this_type(a.i_ + n); }
private:
Itor i_;
friend class config;
friend struct const_all_children_iterator;
};
struct const_all_children_iterator
{
struct arrow_helper
{
const any_child data;
arrow_helper(const const_all_children_iterator &i): data(*i) {}
const any_child *operator->() const { return &data; }
};
typedef const any_child value_type;
typedef std::random_access_iterator_tag iterator_category;
typedef int difference_type;
typedef const arrow_helper pointer;
typedef const any_child reference;
typedef std::vector<child_pos>::const_iterator Itor;
typedef const_all_children_iterator this_type;
explicit const_all_children_iterator(const Itor &i): i_(i) {}
const_all_children_iterator(all_children_iterator& i): i_(i.i_) {}
const_all_children_iterator &operator++() { ++i_; return *this; }
const_all_children_iterator operator++(int) { return const_all_children_iterator(i_++); }
this_type &operator--() { --i_; return *this; }
this_type operator--(int) { return this_type(i_--); }
reference operator*() const;
pointer operator->() const { return *this; }
bool operator==(const const_all_children_iterator &i) const { return i_ == i.i_; }
bool operator!=(const const_all_children_iterator &i) const { return i_ != i.i_; }
bool operator==(const all_children_iterator &i) const { return i_ == i.i_; } bool operator==(const all_children_iterator &i) const { return i_ == i.i_; }
bool operator!=(const all_children_iterator &i) const { return i_ != i.i_; } bool operator!=(const all_children_iterator &i) const { return i_ != i.i_; }
@ -677,12 +774,18 @@ public:
}; };
typedef boost::iterator_range<all_children_iterator> all_children_itors; typedef boost::iterator_range<all_children_iterator> all_children_itors;
typedef boost::iterator_range<const_all_children_iterator> const_all_children_itors;
/** In-order iteration over all children. */ /** In-order iteration over all children. */
all_children_itors all_children_range() const; const_all_children_itors all_children_range() const;
all_children_itors all_children_range();
all_children_iterator ordered_begin() const; const_all_children_iterator ordered_cbegin() const;
all_children_iterator ordered_end() const; const_all_children_iterator ordered_cend() const;
const_all_children_iterator ordered_begin() const;
const_all_children_iterator ordered_end() const;
all_children_iterator ordered_begin();
all_children_iterator ordered_end();
all_children_iterator erase(const all_children_iterator& i); all_children_iterator erase(const all_children_iterator& i);
/** /**

View file

@ -243,9 +243,9 @@ const config& manager::get_value_cfg_or_empty(const std::string& id) const
config::any_child manager::get_option_parent(const std::string& id) const config::any_child manager::get_option_parent(const std::string& id) const
{ {
static const config empty; static config empty;
static const std::string empty_key = ""; static const std::string empty_key = "";
static config::any_child not_found(&empty_key, &empty); static const config::any_child not_found(&empty_key, &empty);
for (const config::any_child& i : options_info_.all_children_range()) { for (const config::any_child& i : options_info_.all_children_range()) {
for (const config::any_child& j : i.cfg.all_children_range()) { for (const config::any_child& j : i.cfg.all_children_range()) {

View file

@ -154,7 +154,7 @@ register_builder_widget(const std::string& id,
tbuilder_widget_ptr create_builder_widget(const config& cfg) tbuilder_widget_ptr create_builder_widget(const config& cfg)
{ {
config::all_children_itors children = cfg.all_children_range(); config::const_all_children_itors children = cfg.all_children_range();
size_t nb_children = std::distance(children.begin(), children.end()); size_t nb_children = std::distance(children.begin(), children.end());
VALIDATE(nb_children == 1, "Grid cell does not have exactly 1 child."); VALIDATE(nb_children == 1, "Grid cell does not have exactly 1 child.");

View file

@ -696,7 +696,7 @@ REPLAY_RETURN do_replay_handle(bool one_move)
} }
const config::all_children_itors ch_itors = cfg->all_children_range(); const config::const_all_children_itors ch_itors = cfg->all_children_range();
//if there is an empty command tag or a start tag //if there is an empty command tag or a start tag
if (ch_itors.empty() || cfg->has_child("start")) if (ch_itors.empty() || cfg->has_child("start"))
{ {

View file

@ -74,11 +74,11 @@ struct animation_branch
} }
config attributes; config attributes;
std::vector<config::all_children_iterator> children; std::vector<config::const_all_children_iterator> children;
config merge() const config merge() const
{ {
config result = attributes; config result = attributes;
for (const config::all_children_iterator &i : children) { for (const config::const_all_children_iterator &i : children) {
result.add_child(i->key, i->cfg); result.add_child(i->key, i->cfg);
} }
return result; return result;
@ -89,7 +89,7 @@ typedef std::list<animation_branch> animation_branches;
struct animation_cursor struct animation_cursor
{ {
config::all_children_itors itors; config::const_all_children_itors itors;
animation_branches branches; animation_branches branches;
animation_cursor *parent; animation_cursor *parent;
animation_cursor(const config &cfg): animation_cursor(const config &cfg):
@ -638,7 +638,7 @@ void unit_animation::add_anims( std::vector<unit_animation> & animations, const
anim["apply_to"] = "standing"; anim["apply_to"] = "standing";
anim["cycles"] = "true"; anim["cycles"] = "true";
// add cycles to all frames within a standing animation block // add cycles to all frames within a standing animation block
for (config::all_children_iterator ci : ab.children) for (config::const_all_children_iterator ci : ab.children)
{ {
std::string sub_frame_name = ci->key; std::string sub_frame_name = ci->key;
size_t pos = sub_frame_name.find("_frame"); size_t pos = sub_frame_name.find("_frame");
@ -656,7 +656,7 @@ void unit_animation::add_anims( std::vector<unit_animation> & animations, const
config anim = ab.merge(); config anim = ab.merge();
anim["apply_to"] = "default"; anim["apply_to"] = "default";
anim["cycles"] = "true"; anim["cycles"] = "true";
for (config::all_children_iterator ci : ab.children) for (config::const_all_children_iterator ci : ab.children)
{ {
std::string sub_frame_name = ci->key; std::string sub_frame_name = ci->key;
size_t pos = sub_frame_name.find("_frame"); size_t pos = sub_frame_name.find("_frame");

View file

@ -309,6 +309,25 @@ config::attribute_value vconfig::expand(const std::string &key) const
return val; return val;
} }
vconfig::attribute_iterator::reference vconfig::attribute_iterator::operator*() const
{
config::attribute val = *i_;
if(resources::gamedata) {
val.second.apply_visitor(vconfig_expand_visitor(val.second));
}
return val;
}
vconfig::attribute_iterator::pointer vconfig::attribute_iterator::operator->() const
{
config::attribute val = *i_;
if(resources::gamedata) {
val.second.apply_visitor(vconfig_expand_visitor(val.second));
}
pointer_proxy p = {val};
return p;
}
vconfig::all_children_iterator::all_children_iterator(const Itor &i) : vconfig::all_children_iterator::all_children_iterator(const Itor &i) :
i_(i), inner_index_(0), cache_() i_(i), inner_index_(0), cache_()
{ {
@ -351,6 +370,25 @@ vconfig::all_children_iterator vconfig::all_children_iterator::operator++(int)
return i; return i;
} }
vconfig::all_children_iterator& vconfig::all_children_iterator::operator--()
{
if(inner_index_ >= 0 && i_->key == "insert_tag") {
if(--inner_index_ >= 0) {
return *this;
}
inner_index_ = 0;
}
--i_;
return *this;
}
vconfig::all_children_iterator vconfig::all_children_iterator::operator--(int)
{
vconfig::all_children_iterator i = *this;
this->operator--();
return i;
}
vconfig::all_children_iterator::reference vconfig::all_children_iterator::operator*() const vconfig::all_children_iterator::reference vconfig::all_children_iterator::operator*() const
{ {
return value_type(get_key(), get_child()); return value_type(get_key(), get_child());

View file

@ -90,21 +90,56 @@ public:
bool has_attribute(const std::string& key) const { return cfg_->has_attribute(key); } bool has_attribute(const std::string& key) const { return cfg_->has_attribute(key); }
bool empty() const { return (null() || cfg_->empty()); } bool empty() const { return (null() || cfg_->empty()); }
struct attribute_iterator
{
struct pointer_proxy;
typedef const config::attribute value_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type;
typedef const pointer_proxy pointer;
typedef const config::attribute reference;
typedef config::const_attribute_iterator Itor;
explicit attribute_iterator(const Itor &i): i_(i) {}
attribute_iterator &operator++() { ++i_; return *this; }
attribute_iterator operator++(int) { return attribute_iterator(i_++); }
attribute_iterator &operator--() { --i_; return *this; }
attribute_iterator operator--(int) { return attribute_iterator(i_--); }
reference operator*() const;
pointer operator->() const;
bool operator==(const attribute_iterator &i) const { return i_ == i.i_; }
bool operator!=(const attribute_iterator &i) const { return i_ != i.i_; }
private:
Itor i_;
};
boost::iterator_range<attribute_iterator> attribute_range() {
config::const_attr_itors range = cfg_->attribute_range();
return boost::make_iterator_range(attribute_iterator(range.begin()), attribute_iterator(range.end()));
}
struct all_children_iterator struct all_children_iterator
{ {
struct pointer_proxy; struct pointer_proxy;
typedef std::pair<std::string, vconfig> value_type; typedef std::pair<std::string, vconfig> value_type;
typedef std::forward_iterator_tag iterator_category; typedef std::bidirectional_iterator_tag iterator_category;
typedef int difference_type; typedef int difference_type;
typedef const pointer_proxy pointer; typedef const pointer_proxy pointer;
typedef const value_type reference; typedef const value_type reference;
typedef config::all_children_iterator Itor; typedef config::const_all_children_iterator Itor;
explicit all_children_iterator(const Itor &i); explicit all_children_iterator(const Itor &i);
all_children_iterator(const Itor &i, const std::shared_ptr<const config> & cache); all_children_iterator(const Itor &i, const std::shared_ptr<const config> & cache);
all_children_iterator& operator++(); all_children_iterator& operator++();
all_children_iterator operator++(int); all_children_iterator operator++(int);
all_children_iterator& operator--();
all_children_iterator operator--(int);
reference operator*() const; reference operator*() const;
pointer operator->() const; pointer operator->() const;
@ -141,8 +176,8 @@ public:
/** In-order iteration over all children. */ /** In-order iteration over all children. */
all_children_iterator ordered_begin() const; all_children_iterator ordered_begin() const;
all_children_iterator ordered_end() const; all_children_iterator ordered_end() const;
std::pair<all_children_iterator,all_children_iterator> all_ordered() const { boost::iterator_range<all_children_iterator> all_ordered() const {
return std::make_pair(ordered_begin(), ordered_end()); return boost::make_iterator_range(ordered_begin(), ordered_end());
} }
private: private:
@ -157,6 +192,12 @@ private:
static const config default_empty_config; static const config default_empty_config;
}; };
struct vconfig::attribute_iterator::pointer_proxy
{
value_type p;
const value_type *operator->() const { return &p; }
};
struct vconfig::all_children_iterator::pointer_proxy struct vconfig::all_children_iterator::pointer_proxy
{ {
value_type p; value_type p;