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:
Celtic Minstrel 2017-04-04 03:02:06 +11:00 committed by Charles Dang
parent 30e0f14863
commit aca6cae04b
6 changed files with 206 additions and 145 deletions

View file

@ -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
{

View file

@ -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*>;

View file

@ -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) {

View file

@ -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_;
};
}

View file

@ -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

View file

@ -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;
};