1 /* 2 Copyright (C) 2008 - 2018 by David White <dave@whitevine.net> 3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/ 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY. 11 12 See the COPYING file for more details. 13 */ 14 15 #pragma once 16 17 #include "formula/variant_value.hpp" 18 19 #include <map> 20 #include <vector> 21 22 namespace wfl 23 { 24 class formula_callable; 25 class variant_iterator; 26 27 class variant 28 { 29 public: 30 enum DECIMAL_VARIANT_TYPE { DECIMAL_VARIANT }; 31 32 variant(); 33 explicit variant(int n); 34 variant(int n, DECIMAL_VARIANT_TYPE /*type*/); 35 variant(double n, DECIMAL_VARIANT_TYPE /*type*/); 36 explicit variant(const std::vector<variant>& array); 37 explicit variant(const std::string& str); 38 explicit variant(const std::map<variant, variant>& map); 39 variant(const variant& v) = default; 40 variant(variant&& v) = default; 41 42 template<typename T> variant(std::shared_ptr<T> callable)43 variant(std::shared_ptr<T> callable) 44 : value_(std::make_shared<variant_callable>(callable)) 45 { 46 assert(value_.get()); 47 } 48 49 variant& operator=(const variant& v) = default; 50 variant& operator=(variant&& v) = default; 51 52 variant operator[](size_t n) const; 53 variant operator[](const variant& v) const; 54 55 size_t num_elements() const; 56 bool is_empty() const; 57 58 variant get_member(const std::string& name) const; 59 60 /** Functions to test the type of the internal value. */ is_null() const61 bool is_null() const { return type() == VARIANT_TYPE::TYPE_NULL; } is_int() const62 bool is_int() const { return type() == VARIANT_TYPE::TYPE_INT; } is_decimal() const63 bool is_decimal() const { return type() == VARIANT_TYPE::TYPE_DECIMAL; } is_callable() const64 bool is_callable() const { return type() == VARIANT_TYPE::TYPE_CALLABLE; } is_list() const65 bool is_list() const { return type() == VARIANT_TYPE::TYPE_LIST; } is_string() const66 bool is_string() const { return type() == VARIANT_TYPE::TYPE_STRING; } is_map() const67 bool is_map() const { return type() == VARIANT_TYPE::TYPE_MAP; } 68 69 int as_int() const; 70 71 /** Returns variant's internal representation of decimal number: ie, 1.234 is represented as 1234 */ 72 int as_decimal() const; 73 74 /** Returns a boolean state of the variant value. The implementation is type-dependent. */ 75 bool as_bool() const; 76 77 const std::vector<variant>& as_list() const; 78 const std::map<variant, variant>& as_map() const; 79 80 const std::string& as_string() const; 81 as_callable() const82 const_formula_callable_ptr as_callable() const 83 { 84 must_be(VARIANT_TYPE::TYPE_CALLABLE); 85 return value_cast<variant_callable>()->get_callable(); 86 } 87 88 template<typename T> try_convert() const89 std::shared_ptr<T> try_convert() const 90 { 91 if(!is_callable()) { 92 return nullptr; 93 } 94 95 return std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable())); 96 } 97 98 template<typename T> convert_to() const99 std::shared_ptr<T> convert_to() const 100 { 101 std::shared_ptr<T> res = std::dynamic_pointer_cast<T>(std::const_pointer_cast<formula_callable>(as_callable())); 102 if(!res) { 103 throw type_error("could not convert type"); 104 } 105 106 return res; 107 } 108 109 variant operator+(const variant&) const; 110 variant operator-(const variant&) const; 111 variant operator*(const variant&) const; 112 variant operator/(const variant&) const; 113 variant operator^(const variant&) const; 114 variant operator%(const variant&) const; 115 variant operator-() const; 116 117 bool operator==(const variant&) const; 118 bool operator!=(const variant&) const; 119 bool operator<(const variant&) const; 120 bool operator>(const variant&) const; 121 bool operator<=(const variant&) const; 122 bool operator>=(const variant&) const; 123 124 variant list_elements_add(const variant& v) const; 125 variant list_elements_sub(const variant& v) const; 126 variant list_elements_mul(const variant& v) const; 127 variant list_elements_div(const variant& v) const; 128 variant concatenate(const variant& v) const; 129 variant build_range(const variant& v) const; 130 131 bool contains(const variant& other) const; 132 133 variant get_keys() const; 134 variant get_values() const; 135 136 variant_iterator begin() const; 137 variant_iterator end() const; 138 139 std::string serialize_to_string() const; 140 void serialize_from_string(const std::string& str); 141 142 std::string string_cast() const; 143 144 std::string to_debug_string(bool verbose = false, formula_seen_stack* seen = nullptr) const; 145 146 /** Gets string name of the current value type */ type_string() const147 std::string type_string() const 148 { 149 return type().to_string(); 150 } 151 152 variant execute_variant(const variant& to_exec); 153 154 private: 155 template<typename T> value_cast() const156 std::shared_ptr<T> value_cast() const 157 { 158 return wfl::value_cast<T>(value_); 159 } 160 161 void must_be(VARIANT_TYPE t) const; 162 163 void must_both_be(VARIANT_TYPE t, const variant& second) const; 164 type() const165 VARIANT_TYPE type() const 166 { 167 return value_->get_type(); 168 } 169 170 /** 171 * Variant value. 172 * Each of the constructors initialized this with the appropriate helper class. 173 */ 174 value_base_ptr value_; 175 }; 176 177 /** 178 * Iterator class for the variant. 179 * 180 * Depending on the @p type_ the @p list_iterator_ and the @p map_iterator_ are 181 * a valid iterator or singular. Since most actions on singular iterators 182 * result in Undefined Behavior care should be taken when copying the 183 * @p list_iterator_ and @p map_iterator_. 184 */ 185 class variant_iterator 186 { 187 public: 188 typedef variant value_type; 189 typedef std::bidirectional_iterator_tag iterator_category; 190 typedef variant& reference; 191 typedef variant* pointer; 192 typedef int difference_type; 193 194 /** 195 * Constructor for a no-op iterator. 196 */ 197 variant_iterator(); 198 199 /** 200 * Constructor for a generic iterator. 201 * 202 * @pre @p iter is not singular. 203 * 204 * @param value A pointer to a variant value representing the container. 205 * @param iter An underlying iterator for the underlying container. 206 */ 207 variant_iterator(const variant_value_base* value, const boost::any& iter); 208 209 variant operator*() const; 210 variant_iterator& operator++(); 211 variant_iterator operator++(int); 212 variant_iterator& operator--(); 213 variant_iterator operator--(int); 214 bool operator==(const variant_iterator& that) const; 215 bool operator!=(const variant_iterator& that) const; 216 private: 217 VARIANT_TYPE type_; 218 const variant_value_base* container_; 219 boost::any iter_; 220 }; 221 222 } 223