Refactored variant_iterator implementation
This generalizes the iterator interface beyond only TYPE_LIST and TYPE_MAP. The new implementation also makes TYPE_CALLABLE iterable.
This commit is contained in:
parent
30e0f14863
commit
aca6cae04b
6 changed files with 206 additions and 145 deletions
|
@ -24,20 +24,6 @@
|
|||
namespace wfl
|
||||
{
|
||||
|
||||
enum FORMULA_ACCESS_TYPE { FORMULA_READ_ONLY, FORMULA_WRITE_ONLY, FORMULA_READ_WRITE };
|
||||
|
||||
struct formula_input
|
||||
{
|
||||
explicit formula_input(const std::string& name, FORMULA_ACCESS_TYPE access = FORMULA_READ_WRITE)
|
||||
: name(name), access(access)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
FORMULA_ACCESS_TYPE access;
|
||||
};
|
||||
|
||||
using formula_input_vector = std::vector<formula_input>;
|
||||
|
||||
// Interface for objects that can have formulae run on them
|
||||
class formula_callable
|
||||
{
|
||||
|
|
|
@ -23,6 +23,17 @@ namespace wfl
|
|||
class formula_callable;
|
||||
class formula_debugger;
|
||||
|
||||
enum FORMULA_ACCESS_TYPE { FORMULA_READ_ONLY, FORMULA_WRITE_ONLY, FORMULA_READ_WRITE };
|
||||
|
||||
struct formula_input {
|
||||
explicit formula_input(const std::string& name, FORMULA_ACCESS_TYPE access = FORMULA_READ_WRITE)
|
||||
: name(name), access(access) {}
|
||||
|
||||
std::string name;
|
||||
FORMULA_ACCESS_TYPE access;
|
||||
};
|
||||
|
||||
using formula_input_vector = std::vector<formula_input>;
|
||||
using formula_callable_ptr = std::shared_ptr<formula_callable>;
|
||||
using const_formula_callable_ptr = std::shared_ptr<const formula_callable>;
|
||||
using formula_seen_stack = std::vector<const formula_callable*>;
|
||||
|
|
|
@ -88,65 +88,32 @@ type_error::type_error(const std::string& str) : game::error(str)
|
|||
}
|
||||
|
||||
variant_iterator::variant_iterator()
|
||||
: type_(TYPE_NULL)
|
||||
, list_iterator_()
|
||||
, map_iterator_()
|
||||
: type_(VARIANT_TYPE::TYPE_NULL)
|
||||
, container_(nullptr)
|
||||
, iter_()
|
||||
{
|
||||
}
|
||||
|
||||
variant_iterator::variant_iterator(const variant_iterator& iter)
|
||||
: type_(iter.type_)
|
||||
, list_iterator_()
|
||||
, map_iterator_()
|
||||
{
|
||||
switch(type_) {
|
||||
case TYPE_LIST :
|
||||
list_iterator_ = iter.list_iterator_;
|
||||
break;
|
||||
|
||||
case TYPE_MAP:
|
||||
map_iterator_ = iter.map_iterator_;
|
||||
break;
|
||||
|
||||
case TYPE_NULL:
|
||||
/* DO NOTHING */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
variant_iterator::variant_iterator(const std::vector<variant>::iterator& iter)
|
||||
: type_(TYPE_LIST)
|
||||
, list_iterator_(iter)
|
||||
, map_iterator_()
|
||||
{
|
||||
}
|
||||
|
||||
variant_iterator::variant_iterator(const std::map<variant, variant>::iterator& iter)
|
||||
: type_(TYPE_MAP)
|
||||
, list_iterator_()
|
||||
, map_iterator_(iter)
|
||||
variant_iterator::variant_iterator(const variant_value_base* value, const boost::any& iter)
|
||||
: type_(value->get_type())
|
||||
, container_(value)
|
||||
, iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
variant variant_iterator::operator*() const
|
||||
{
|
||||
if(type_ == TYPE_LIST) {
|
||||
return *list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
key_value_pair* p = new key_value_pair(map_iterator_->first, map_iterator_->second);
|
||||
variant res(p);
|
||||
return res;
|
||||
if(!container_) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return variant();
|
||||
return container_->deref_iterator(iter_);
|
||||
}
|
||||
|
||||
variant_iterator& variant_iterator::operator++()
|
||||
{
|
||||
if(type_ == TYPE_LIST) {
|
||||
++list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
++map_iterator_;
|
||||
if(container_) {
|
||||
container_->iterator_inc(iter_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
@ -154,22 +121,18 @@ variant_iterator& variant_iterator::operator++()
|
|||
|
||||
variant_iterator variant_iterator::operator++(int)
|
||||
{
|
||||
variant_iterator iter(*this);
|
||||
if(type_ == TYPE_LIST) {
|
||||
++list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
++map_iterator_;
|
||||
variant_iterator temp(*this);
|
||||
if(container_) {
|
||||
container_->iterator_inc(iter_);
|
||||
}
|
||||
|
||||
return iter;
|
||||
return temp;
|
||||
}
|
||||
|
||||
variant_iterator& variant_iterator::operator--()
|
||||
{
|
||||
if(type_ == TYPE_LIST) {
|
||||
--list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
--map_iterator_;
|
||||
if(container_) {
|
||||
container_->iterator_dec(iter_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
@ -177,50 +140,24 @@ variant_iterator& variant_iterator::operator--()
|
|||
|
||||
variant_iterator variant_iterator::operator--(int)
|
||||
{
|
||||
variant_iterator iter(*this);
|
||||
if(type_ == TYPE_LIST) {
|
||||
--list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
--map_iterator_;
|
||||
variant_iterator temp(*this);
|
||||
if(container_) {
|
||||
container_->iterator_dec(iter_);
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
variant_iterator& variant_iterator::operator=(const variant_iterator& that)
|
||||
{
|
||||
if(this == &that) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
type_ = that.type_;
|
||||
switch(type_) {
|
||||
case TYPE_LIST :
|
||||
list_iterator_ = that.list_iterator_;
|
||||
break;
|
||||
|
||||
case TYPE_MAP:
|
||||
map_iterator_ = that.map_iterator_;
|
||||
break;
|
||||
|
||||
case TYPE_NULL:
|
||||
/* DO NOTHING */
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool variant_iterator::operator==(const variant_iterator& that) const
|
||||
{
|
||||
if(type_ == TYPE_LIST) {
|
||||
return that.type_ == TYPE_LIST && list_iterator_ == that.list_iterator_;
|
||||
} else if(type_ == TYPE_MAP) {
|
||||
return that.type_ == TYPE_MAP && map_iterator_ == that.map_iterator_;
|
||||
} else if(type_== TYPE_NULL && that.type_ == TYPE_NULL) {
|
||||
if(!container_ && !that.container_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(container_ == that.container_) {
|
||||
return container_->iterator_equals(iter_, that.iter_);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -356,28 +293,12 @@ variant variant::get_values() const
|
|||
|
||||
variant_iterator variant::begin() const
|
||||
{
|
||||
if(is_list()) {
|
||||
return variant_iterator(value_cast<variant_list>()->get_container().begin());
|
||||
}
|
||||
|
||||
if(is_map()) {
|
||||
return variant_iterator(value_cast<variant_map>()->get_container().begin());
|
||||
}
|
||||
|
||||
return variant_iterator();
|
||||
return value_->make_iterator().begin();
|
||||
}
|
||||
|
||||
variant_iterator variant::end() const
|
||||
{
|
||||
if(is_list()) {
|
||||
return variant_iterator(value_cast<variant_list>()->get_container().end());
|
||||
}
|
||||
|
||||
if(is_map()) {
|
||||
return variant_iterator(value_cast<variant_map>()->get_container().end());
|
||||
}
|
||||
|
||||
return variant_iterator();
|
||||
return value_->make_iterator().end();
|
||||
}
|
||||
|
||||
bool variant::is_empty() const
|
||||
|
@ -768,7 +689,8 @@ std::string variant::to_debug_string(bool verbose, formula_seen_stack* seen) con
|
|||
return value_->get_debug_string(*seen, verbose);
|
||||
}
|
||||
|
||||
variant variant::execute_variant(const variant& var) {
|
||||
variant variant::execute_variant(const variant& var)
|
||||
{
|
||||
std::stack<variant> vars;
|
||||
if(var.is_list()) {
|
||||
for(size_t n = 1; n <= var.num_elements(); ++n) {
|
||||
|
|
|
@ -150,6 +150,7 @@ public:
|
|||
}
|
||||
|
||||
variant execute_variant(const variant& to_exec);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
std::shared_ptr<T> value_cast() const
|
||||
|
@ -191,44 +192,31 @@ public:
|
|||
typedef int difference_type;
|
||||
|
||||
/**
|
||||
* Constructor for a TYPE_NULL variant.
|
||||
* Constructor for a no-op iterator.
|
||||
*/
|
||||
variant_iterator();
|
||||
|
||||
/**
|
||||
* Constructor for a TYPE_LIST variant.
|
||||
* Constructor for a generic iterator.
|
||||
*
|
||||
* @pre @p iter is not singular.
|
||||
*
|
||||
* @param iter Iterator to initialize @p list_iterator_ with.
|
||||
* @param value A pointer to a variant value representing the container.
|
||||
* @param iter An underlying iterator for the underlying container.
|
||||
*/
|
||||
explicit variant_iterator(const std::vector<variant>::iterator& iter);
|
||||
|
||||
/**
|
||||
* Constructor for a TYPE_MAP variant.
|
||||
*
|
||||
* @pre @p iter is not singular.
|
||||
*
|
||||
* @param iter Iterator to initialize @p map_iterator_ with.
|
||||
*/
|
||||
explicit variant_iterator(const std::map<variant, variant>::iterator& iter);
|
||||
|
||||
variant_iterator(const variant_iterator&);
|
||||
variant_iterator(const variant_value_base* value, const boost::any& iter);
|
||||
|
||||
variant operator*() const;
|
||||
variant_iterator& operator++();
|
||||
variant_iterator operator++(int);
|
||||
variant_iterator& operator--();
|
||||
variant_iterator operator--(int);
|
||||
variant_iterator& operator=(const variant_iterator& that);
|
||||
bool operator==(const variant_iterator& that) const;
|
||||
bool operator!=(const variant_iterator& that) const;
|
||||
|
||||
enum TYPE { TYPE_NULL, TYPE_LIST, TYPE_MAP };
|
||||
private:
|
||||
TYPE type_;
|
||||
std::vector<variant>::iterator list_iterator_;
|
||||
std::map<variant,variant>::iterator map_iterator_;
|
||||
VARIANT_TYPE type_;
|
||||
const variant_value_base* container_;
|
||||
boost::any iter_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -15,10 +15,21 @@
|
|||
#include "formula/variant_value.hpp"
|
||||
|
||||
#include "formula/callable.hpp"
|
||||
#include "formula/function.hpp"
|
||||
|
||||
namespace wfl
|
||||
{
|
||||
|
||||
boost::iterator_range<variant_iterator> variant_value_base::make_iterator() const
|
||||
{
|
||||
return {variant_iterator(), variant_iterator()};
|
||||
}
|
||||
|
||||
variant variant_value_base::deref_iterator(const boost::any& /*iter*/) const
|
||||
{
|
||||
return variant();
|
||||
}
|
||||
|
||||
variant variant_int::build_range_variant(int limit) const
|
||||
{
|
||||
const int len = std::abs(limit - value_) + 1;
|
||||
|
@ -75,6 +86,7 @@ std::string variant_callable::get_serialized_string() const
|
|||
if(callable_) {
|
||||
callable_->serialize(str);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -130,6 +142,38 @@ bool variant_callable::less_than(variant_value_base& other) const
|
|||
return callable_ ? callable_->less(other_ref.callable_) : other_ref.callable_ != nullptr;
|
||||
}
|
||||
|
||||
boost::iterator_range<variant_iterator> variant_callable::make_iterator() const
|
||||
{
|
||||
if(!callable_) {
|
||||
return variant_value_base::make_iterator();
|
||||
}
|
||||
|
||||
if(inputs.empty()) {
|
||||
callable_->get_inputs(inputs);
|
||||
}
|
||||
|
||||
return {variant_iterator(this, inputs.cbegin()), variant_iterator(this, inputs.cend())};
|
||||
}
|
||||
|
||||
variant variant_callable::deref_iterator(const boost::any& iter) const
|
||||
{
|
||||
if(!callable_) {
|
||||
return variant();
|
||||
}
|
||||
|
||||
return callable_->query_value(boost::any_cast<const formula_input_vector::const_iterator&>(iter)->name);
|
||||
}
|
||||
|
||||
void variant_callable::iterator_inc(boost::any& iter) const
|
||||
{
|
||||
++boost::any_cast<formula_input_vector::const_iterator&>(iter);
|
||||
}
|
||||
|
||||
void variant_callable::iterator_dec(boost::any& iter) const
|
||||
{
|
||||
--boost::any_cast<formula_input_vector::const_iterator&>(iter);
|
||||
}
|
||||
|
||||
std::string variant_string::get_serialized_string() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
|
@ -208,6 +252,30 @@ std::string variant_container<T>::get_debug_string(formula_seen_stack& seen, boo
|
|||
return to_string_impl(true, false, [&](const variant& v) { return v.to_debug_string(verbose, &seen); });
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::iterator_range<variant_iterator> variant_container<T>::make_iterator() const
|
||||
{
|
||||
return {variant_iterator(this, get_container().cbegin()), variant_iterator(this, get_container().cend())};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void variant_container<T>::iterator_inc(boost::any& iter) const
|
||||
{
|
||||
++boost::any_cast<typename T::const_iterator&>(iter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void variant_container<T>::iterator_dec(boost::any& iter) const
|
||||
{
|
||||
--boost::any_cast<typename T::const_iterator&>(iter);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool variant_container<T>::iterator_equals(const boost::any& first, const boost::any& second) const
|
||||
{
|
||||
return boost::any_cast<typename T::const_iterator>(first) == boost::any_cast<typename T::const_iterator>(second);
|
||||
}
|
||||
|
||||
// Force compilation of the following template instantiations
|
||||
template class variant_container<variant_vector>;
|
||||
template class variant_container<variant_map_raw>;
|
||||
|
@ -262,6 +330,11 @@ bool variant_list::less_than(variant_value_base& other) const
|
|||
return num_elements() < other.num_elements();
|
||||
}
|
||||
|
||||
variant variant_list::deref_iterator(const boost::any& iter) const
|
||||
{
|
||||
return *boost::any_cast<const variant_vector::const_iterator&>(iter);
|
||||
}
|
||||
|
||||
std::string variant_map::to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
|
@ -283,4 +356,11 @@ bool variant_map::less_than(variant_value_base& other) const
|
|||
return get_container() < value_ref_cast<variant_map>(other).get_container();
|
||||
}
|
||||
|
||||
variant variant_map::deref_iterator(const boost::any& iter) const
|
||||
{
|
||||
const variant_map_raw::value_type& p = *boost::any_cast<const variant_map_raw::const_iterator&>(iter);
|
||||
key_value_pair* the_pair = new key_value_pair(p.first, p.second);
|
||||
return variant(the_pair);
|
||||
}
|
||||
|
||||
} // namespace wfl
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
namespace wfl
|
||||
{
|
||||
class formula_callable;
|
||||
class variant_value_base;
|
||||
class variant_iterator;
|
||||
class variant;
|
||||
|
||||
/** The various types the variant class is designed to handle */
|
||||
|
@ -148,6 +150,54 @@ public:
|
|||
static VARIANT_TYPE type = VARIANT_TYPE::TYPE_NULL;
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an iterator pair that can be used for iteration.
|
||||
* For an iterable type, it should use the two-argument constructor of variant-iterator,
|
||||
* passing the underlying iterator as the boost::any parameter.
|
||||
*
|
||||
* This creates both the begin and end iterator, but the variant implementation
|
||||
* discards one of the two.
|
||||
*/
|
||||
virtual boost::iterator_range<variant_iterator> make_iterator() const;
|
||||
|
||||
/**
|
||||
* Implements the dereference functionality of @ref variant_iterator
|
||||
* for a value of this type.
|
||||
*
|
||||
* @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
|
||||
*/
|
||||
virtual variant deref_iterator(const boost::any& iter) const;
|
||||
|
||||
/**
|
||||
* Implements the increment functionality of @ref variant_iterator
|
||||
* for a value of this type.
|
||||
*
|
||||
* @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
|
||||
*/
|
||||
virtual void iterator_inc(boost::any&) const {}
|
||||
|
||||
/**
|
||||
* Implements the decrement functionality of @ref variant_iterator
|
||||
* for a value of this type.
|
||||
*
|
||||
* @param iter The opaque reference that was passed to the variant_iterator by @ref make_iterator.
|
||||
*/
|
||||
virtual void iterator_dec(boost::any&) const {}
|
||||
|
||||
/**
|
||||
* Implements the equality functionality of @ref variant_iterator
|
||||
* for a value of this type.
|
||||
*
|
||||
* Note that this is only called if the two iterators are already known to be of the same type.
|
||||
*
|
||||
* @param first The opaque reference that was passed to the variant_iterator by @ref make_iterator.
|
||||
* @param second The opaque reference that was passed to the variant_iterator by @ref make_iterator.
|
||||
*/
|
||||
virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -297,8 +347,20 @@ public:
|
|||
return type;
|
||||
}
|
||||
|
||||
virtual boost::iterator_range<variant_iterator> make_iterator() const override;
|
||||
virtual variant deref_iterator(const boost::any& iter) const override;
|
||||
|
||||
virtual void iterator_inc(boost::any& iter) const override;
|
||||
virtual void iterator_dec(boost::any& iter) const override;
|
||||
virtual bool iterator_equals(const boost::any& /*first*/, const boost::any& /*second*/) const
|
||||
{
|
||||
return true; // TODO: implement
|
||||
}
|
||||
|
||||
private:
|
||||
const formula_callable* callable_;
|
||||
|
||||
mutable formula_input_vector inputs; // for iteration
|
||||
};
|
||||
|
||||
|
||||
|
@ -408,6 +470,14 @@ public:
|
|||
return util::contains<T, variant>(container_, member);
|
||||
}
|
||||
|
||||
// We implement these here since the interface is the same for all
|
||||
// specializations and leave the deref function to the derived classes.
|
||||
virtual boost::iterator_range<variant_iterator> make_iterator() const override;
|
||||
|
||||
virtual void iterator_inc(boost::any&) const override;
|
||||
virtual void iterator_dec(boost::any&) const override;
|
||||
virtual bool iterator_equals(const boost::any& first, const boost::any& second) const override;
|
||||
|
||||
protected:
|
||||
using mod_func_t = std::function<std::string(const variant&)>;
|
||||
|
||||
|
@ -447,6 +517,8 @@ public:
|
|||
return type;
|
||||
}
|
||||
|
||||
virtual variant deref_iterator(const boost::any&) const override;
|
||||
|
||||
private:
|
||||
virtual std::string to_string_detail(const variant_vector::value_type& container_val, mod_func_t mod_func) const override
|
||||
{
|
||||
|
@ -471,6 +543,8 @@ public:
|
|||
return type;
|
||||
}
|
||||
|
||||
virtual variant deref_iterator(const boost::any&) const;
|
||||
|
||||
private:
|
||||
virtual std::string to_string_detail(const variant_map_raw::value_type& container_val, mod_func_t mod_func) const override;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue