1 #pragma once 2 3 #include <vector> 4 #include <string> 5 #include <algorithm> 6 #include <cstdint> 7 #include <limits> 8 #include <iostream> 9 #include <memory> 10 11 // Workaround for https://bugreports.qt-project.org/browse/QTBUG-22829 12 #ifndef Q_MOC_RUN 13 #include <boost/variant.hpp> 14 #include <boost/lexical_cast.hpp> 15 #include <glib.h> 16 #endif 17 18 #include "Assignment.h" 19 #include "memory.h" 20 21 class tostring_visitor; 22 class tostream_visitor; 23 class Context; 24 class Expression; 25 26 class QuotedString : public std::string 27 { 28 public: QuotedString()29 QuotedString() : std::string() {} QuotedString(const std::string & s)30 QuotedString(const std::string &s) : std::string(s) {} 31 }; 32 std::ostream &operator<<(std::ostream &stream, const QuotedString &s); 33 34 class Filename : public QuotedString 35 { 36 public: Filename()37 Filename() : QuotedString() {} Filename(const std::string & f)38 Filename(const std::string &f) : QuotedString(f) {} 39 }; 40 std::ostream &operator<<(std::ostream &stream, const Filename &filename); 41 42 class RangeType { 43 private: 44 double begin_val; 45 double step_val; 46 double end_val; 47 48 public: 49 static constexpr uint32_t MAX_RANGE_STEPS = 10000; 50 static const RangeType EMPTY; 51 52 enum class type_t { RANGE_TYPE_BEGIN, RANGE_TYPE_RUNNING, RANGE_TYPE_END }; 53 54 class iterator { 55 public: 56 // iterator_traits required types: 57 using iterator_category = std::forward_iterator_tag ; 58 using value_type = double; 59 using difference_type = void; // type used by operator-(iterator), not implemented for forward interator 60 using reference = value_type; // type used by operator*(), not actually a reference 61 using pointer = void; // type used by operator->(), not implemented 62 iterator(const RangeType &range, type_t type); 63 iterator& operator++(); 64 reference operator*(); 65 bool operator==(const iterator& other) const; 66 bool operator!=(const iterator& other) const; 67 private: 68 const RangeType ⦥ 69 double val; 70 type_t type; 71 const uint32_t num_values; 72 uint32_t i_step; 73 void update_type(); 74 }; 75 76 RangeType(const RangeType &) = delete; // never copy, move instead 77 RangeType& operator=(const RangeType &) = delete; // never copy, move instead 78 RangeType(RangeType&&) = default; 79 RangeType& operator=(RangeType&&) = default; 80 RangeType(double begin,double end)81 explicit RangeType(double begin, double end) 82 : begin_val(begin), step_val(1.0), end_val(end) {} 83 RangeType(double begin,double step,double end)84 explicit RangeType(double begin, double step, double end) 85 : begin_val(begin), step_val(step), end_val(end) {} 86 87 bool operator==(const RangeType &other) const { 88 auto n1 = this->numValues(); 89 auto n2 = other.numValues(); 90 if (n1 == 0) return n2 == 0; 91 if (n2 == 0) return false; 92 return this == &other || 93 (this->begin_val == other.begin_val && 94 this->step_val == other.step_val && 95 n1 == n2); 96 } 97 98 bool operator!=(const RangeType &other) const { 99 return !(*this==other); 100 } 101 102 bool operator<(const RangeType &other) const { 103 auto n1 = this->numValues(); 104 auto n2 = other.numValues(); 105 if (n1 == 0) return 0 < n2; 106 if (n2 == 0) return false; 107 return this->begin_val < other.begin_val || 108 (this->begin_val == other.begin_val && 109 (this->step_val < other.step_val || (this->step_val == other.step_val && n1 < n2)) 110 ); 111 } 112 113 bool operator<=(const RangeType &other) const { 114 auto n1 = this->numValues(); 115 auto n2 = other.numValues(); 116 if (n1 == 0) return true; // (0 <= n2) is always true 117 if (n2 == 0) return false; 118 return this->begin_val < other.begin_val || 119 (this->begin_val == other.begin_val && 120 (this->step_val < other.step_val || (this->step_val == other.step_val && n1 <= n2)) 121 ); 122 } 123 124 bool operator>(const RangeType &other) const { 125 auto n1 = this->numValues(); 126 auto n2 = other.numValues(); 127 if (n2 == 0) return n1 > 0; 128 if (n1 == 0) return false; 129 return this->begin_val > other.begin_val || 130 (this->begin_val == other.begin_val && 131 (this->step_val > other.step_val || (this->step_val == other.step_val && n1 > n2)) 132 ); 133 } 134 135 bool operator>=(const RangeType &other) const { 136 auto n1 = this->numValues(); 137 auto n2 = other.numValues(); 138 if (n2 == 0) return true; // (n1 >= 0) is always true 139 if (n1 == 0) return false; 140 return this->begin_val > other.begin_val || 141 (this->begin_val == other.begin_val && 142 (this->step_val > other.step_val || (this->step_val == other.step_val && n1 >= n2)) 143 ); 144 } 145 begin_value()146 double begin_value() const { return begin_val; } step_value()147 double step_value() const { return step_val; } end_value()148 double end_value() const { return end_val; } 149 begin()150 iterator begin() const { return iterator(*this, type_t::RANGE_TYPE_BEGIN); } end()151 iterator end() const{ return iterator(*this, type_t::RANGE_TYPE_END); } 152 153 /// return number of values, max uint32_t value if step is 0 or range is infinite 154 uint32_t numValues() const; 155 }; 156 std::ostream& operator<<(std::ostream& stream, const RangeType& r); 157 158 159 template <typename T> 160 class ValuePtr { 161 private: ValuePtr(const std::shared_ptr<T> & val_in)162 explicit ValuePtr(const std::shared_ptr<T> &val_in) : value(val_in) { } 163 public: ValuePtr(T && value)164 ValuePtr(T&& value) : value(std::make_shared<T>(std::move(value))) { } clone()165 ValuePtr clone() const { return ValuePtr(value); } 166 167 const T& operator*() const { return *value; } 168 const T* operator->() const { return value.get(); } 169 170 private: 171 std::shared_ptr<T> value; 172 }; 173 174 using RangePtr = ValuePtr<RangeType>; 175 176 class str_utf8_wrapper 177 { 178 private: 179 // store the cached length in glong, paired with its string 180 struct str_utf8_t { 181 static constexpr glong LENGTH_UNKNOWN = -1; str_utf8_tstr_utf8_t182 str_utf8_t() : u8str(), u8len(0) { } str_utf8_tstr_utf8_t183 str_utf8_t(const std::string& s) : u8str(s) { } str_utf8_tstr_utf8_t184 str_utf8_t(const char* cstr) : u8str(cstr) { } str_utf8_tstr_utf8_t185 str_utf8_t(const char* cstr, size_t size, glong u8len) : u8str(cstr, size), u8len(u8len) { } 186 const std::string u8str; 187 glong u8len = LENGTH_UNKNOWN; 188 }; 189 // private constructor for copying members str_utf8_wrapper(const shared_ptr<str_utf8_t> & str_in)190 explicit str_utf8_wrapper(const shared_ptr<str_utf8_t> &str_in) : str_ptr(str_in) { } 191 192 public: 193 class iterator { 194 public: 195 // iterator_traits required types: 196 using iterator_category = std::forward_iterator_tag ; 197 using value_type = str_utf8_wrapper; 198 using difference_type = void; 199 using reference = value_type; // type used by operator*(), not actually a reference 200 using pointer = void; iterator()201 iterator() : ptr(&nullterm) {} // DefaultConstructible iterator(const str_utf8_wrapper & str)202 iterator(const str_utf8_wrapper& str) : ptr(str.c_str()), len(char_len()) { } iterator(const str_utf8_wrapper & str,bool)203 iterator(const str_utf8_wrapper& str, bool /*end*/) : ptr(str.c_str() + str.size()) { } 204 205 iterator& operator++() { ptr += len; len = char_len(); return *this; } 206 reference operator*() { return {ptr, len}; } // Note: returns a new str_utf8_wrapper **by value**, representing a single UTF8 character. 207 bool operator==(const iterator &other) const { return ptr == other.ptr; } 208 bool operator!=(const iterator &other) const { return ptr != other.ptr; } 209 private: 210 size_t char_len(); 211 static const char nullterm = '\0'; 212 const char *ptr; 213 size_t len = 0; 214 }; 215 begin()216 iterator begin() const { return iterator(*this); } end()217 iterator end() const{ return iterator(*this, true); } str_utf8_wrapper()218 str_utf8_wrapper() : str_ptr(make_shared<str_utf8_t>()) { } str_utf8_wrapper(const std::string & s)219 str_utf8_wrapper(const std::string& s) : str_ptr(make_shared<str_utf8_t>(s)) { } str_utf8_wrapper(const char * cstr)220 str_utf8_wrapper(const char* cstr) : str_ptr(make_shared<str_utf8_t>(cstr)) { } 221 // for enumerating single utf8 chars from iterator str_utf8_wrapper(const char * cstr,size_t clen)222 str_utf8_wrapper(const char* cstr, size_t clen) : str_ptr(make_shared<str_utf8_t>(cstr,clen,1)) { } 223 str_utf8_wrapper(const str_utf8_wrapper &) = delete; // never copy, move instead 224 str_utf8_wrapper& operator=(const str_utf8_wrapper &) = delete; // never copy, move instead 225 str_utf8_wrapper(str_utf8_wrapper&&) = default; 226 str_utf8_wrapper& operator=(str_utf8_wrapper&&) = default; clone()227 str_utf8_wrapper clone() const { return str_utf8_wrapper(this->str_ptr); } // makes a copy of shared_ptr 228 229 bool operator==(const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str == rhs.str_ptr->u8str; } 230 bool operator!=(const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str != rhs.str_ptr->u8str; } 231 bool operator< (const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str < rhs.str_ptr->u8str; } 232 bool operator> (const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str > rhs.str_ptr->u8str; } 233 bool operator<=(const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str <= rhs.str_ptr->u8str; } 234 bool operator>=(const str_utf8_wrapper &rhs) const { return this->str_ptr->u8str >= rhs.str_ptr->u8str; } empty()235 bool empty() const { return this->str_ptr->u8str.empty(); } c_str()236 const char* c_str() const { return this->str_ptr->u8str.c_str(); } toString()237 const std::string& toString() const { return this->str_ptr->u8str; } size()238 size_t size() const { return this->str_ptr->u8str.size(); } 239 get_utf8_strlen()240 glong get_utf8_strlen() const { 241 if (str_ptr->u8len == str_utf8_t::LENGTH_UNKNOWN) { 242 str_ptr->u8len = g_utf8_strlen(str_ptr->u8str.c_str(), str_ptr->u8str.size()); 243 } 244 return str_ptr->u8len; 245 }; 246 247 private: 248 shared_ptr<str_utf8_t> str_ptr; 249 }; 250 251 class FunctionType { 252 public: FunctionType(std::shared_ptr<Context> ctx,std::shared_ptr<Expression> expr,std::shared_ptr<AssignmentList> args)253 FunctionType(std::shared_ptr<Context> ctx, std::shared_ptr<Expression> expr, std::shared_ptr<AssignmentList> args) 254 : ctx(ctx), expr(expr), args(args) { } 255 Value operator==(const FunctionType &other) const; 256 Value operator!=(const FunctionType &other) const; 257 Value operator< (const FunctionType &other) const; 258 Value operator> (const FunctionType &other) const; 259 Value operator<=(const FunctionType &other) const; 260 Value operator>=(const FunctionType &other) const; 261 getCtx()262 const std::shared_ptr<Context>& getCtx() const { return ctx; } getExpr()263 const std::shared_ptr<Expression>& getExpr() const { return expr; } getArgs()264 const std::shared_ptr<AssignmentList>& getArgs() const { return args; } 265 private: 266 std::shared_ptr<Context> ctx; 267 std::shared_ptr<Expression> expr; 268 std::shared_ptr<AssignmentList> args; 269 }; 270 271 using FunctionPtr = ValuePtr<FunctionType>; 272 273 std::ostream& operator<<(std::ostream& stream, const FunctionType& f); 274 275 /* 276 Require a reason why (string), any time an undefined value is created/returned. 277 This allows for passing of "exception" information from low level functions (i.e. from value.cc) 278 up to Expression::evaluate() or other functions where a proper "WARNING: ..." 279 with ASTNode Location info (source file, line number) can be included. 280 */ 281 class UndefType 282 { 283 public: 284 // TODO: eventually deprecate undef creation without a reason. UndefType()285 UndefType() : reasons{ std::make_unique<std::vector<std::string>>() } { } UndefType(const std::string & why)286 explicit UndefType(const std::string &why) : reasons{ std::make_unique<std::vector<std::string>>(std::initializer_list<std::string>({why})) } { } 287 288 // Append another reason in case a chain of undefined operations are made before handling append(const std::string & why)289 const UndefType &append(const std::string &why) const { reasons->push_back(why); return *this; } 290 291 Value operator< (const UndefType &other) const; 292 Value operator> (const UndefType &other) const; 293 Value operator<=(const UndefType &other) const; 294 Value operator>=(const UndefType &other) const; 295 friend std::ostream& operator<<(std::ostream& stream, const ValuePtr<UndefType>& u); 296 297 std::string toString() const; empty()298 bool empty() const { return reasons->empty(); } 299 private: 300 // using unique_ptr to keep the size small enough that the variant of 301 // all value types does not exceed the 24 bytes. 302 // mutable to allow clearing reasons, which should avoid duplication of warnings that have already been displayed. 303 mutable std::unique_ptr<std::vector<std::string>> reasons; 304 }; 305 306 std::ostream& operator<<(std::ostream& stream, const UndefType& u); 307 308 /** 309 * Value class encapsulates a boost::variant value which can represent any of the 310 * value types existing in the SCAD language. 311 * -- As part of a refactoring effort which began as PR #2881 and continued as PR #3102, 312 * Value and its constituent types have been made (nominally) "move only". 313 * -- In some cases a copy of a Value is necessary or unavoidable, in which case Value::clone() can be used. 314 * -- Value::clone() is used instead of automatic copy construction/assignment so this action is 315 * made deliberate and explicit (and discouraged). 316 * -- Recommended to make use of RVO (Return Value Optimization) wherever possible: 317 * https://en.cppreference.com/w/cpp/language/copy_elision 318 * -- Classes which cache Values such as Context or dxf_dim_cache(see dxfdim.cc), when queried 319 * should return either a const reference or a clone of the cached value if returning by-value. 320 * NEVER return a non-const reference! 321 */ 322 class Value 323 { 324 public: 325 enum class Type { 326 UNDEFINED, 327 BOOL, 328 NUMBER, 329 STRING, 330 VECTOR, 331 EMBEDDED_VECTOR, 332 RANGE, 333 FUNCTION 334 }; 335 // FIXME: eventually remove this in favor of specific messages for each undef usage 336 static const Value undefined; 337 338 /** 339 * VectorType is the underlying "BoundedType" of boost::variant for OpenSCAD vectors. 340 * It holds only a shared_ptr to its VectorObject type, and provides a convenient 341 * interface for various operations needed on the vector. 342 * 343 * EmbeddedVectorType class derives from VectorType and enables O(1) concatentation of vectors 344 * by treating their elements as elements of their parent, traversable via VectorType's custom iterator. 345 * -- An embedded vector should never exist "in the wild", only as a pseudo-element of a parent vector. 346 * Eg "Lc*" Expressions return Embedded Vectors but they are necessairly child expressions of a Vector expression. 347 * -- Any VectorType containing embedded elements will be forced to "flatten" upon usage of operator[], 348 * which is the only case of random-access. 349 * -- Any loops through VectorTypes should prefer automatic range-based for loops eg: for(const auto& value : vec) { ... } 350 * which make use of begin() and end() iterators of VectorType. https://en.cppreference.com/w/cpp/language/range-for 351 * -- Moving a temporary Value of type VectorType or EmbeddedVectorType is always safe, 352 * since it just moves the shared_ptr in its possession (which might be a copy but that doesn't matter). 353 * Additionally any VectorType can be converted to an EmbeddedVectorType by moving it into 354 * EmbeddedVectorType's converting constructor (or vice-versa). 355 * -- HOWEVER, moving elements out of a [Embedded]VectorType is potentially DANGEROUS unless it can be 356 * verified that ( ptr.use_count() == 1 ) for that outermost [Embedded]VectorType 357 * AND recursively any EmbeddedVectorTypes which led to that element. 358 * Therefore elements are currently cloned rather than making any attempt to move. 359 * Performing such use_count checks may be an area for further optimization. 360 */ 361 class EmbeddedVectorType; 362 class VectorType { 363 364 protected: 365 // The object type which VectorType's shared_ptr points to. 366 struct VectorObject { 367 using vec_t = std::vector<Value>; 368 using size_type = vec_t::size_type; 369 vec_t vec; 370 size_type embed_excess = 0; // Keep count of the number of embedded elements *excess of* vec.size() sizeVectorObject371 size_type size() const { return vec.size() + embed_excess; } 372 }; 373 using vec_t = VectorObject::vec_t; 374 shared_ptr<VectorObject> ptr; 375 376 // A Deleter is used on the shared_ptrs to avoid stack overflow in cases 377 // of destructing a very large list of nested embedded vectors, such as from a 378 // recursive function which concats one element at a time. 379 // (A similar solution can also be seen with csgnode.h:CSGOperationDeleter). 380 struct VectorObjectDeleter { 381 void operator()(VectorObject* vec); 382 }; 383 void flatten() const; // flatten replaces VectorObject::vec with a new vector 384 // where any embedded elements are copied direclty into the top level vec, 385 // leaving only true elements for straightforward indexing by operator[]. VectorType(const shared_ptr<VectorObject> & copy)386 explicit VectorType(const shared_ptr<VectorObject> ©) : ptr(copy) { } // called by clone() 387 public: 388 using size_type = VectorObject::size_type; 389 static const VectorType EMPTY; 390 // EmbeddedVectorType-aware iterator, manages its own stack of begin/end vec_t::const_iterators 391 // such that calling code will only receive references to "true" elements (i.e. NOT EmbeddedVectorTypes). 392 // Also tracks the overall element index. In case flattening occurs during iteration, it can continue based on that index. (Issue #3541) 393 class iterator { 394 private: 395 const VectorObject* vo; 396 std::vector<std::pair<vec_t::const_iterator, vec_t::const_iterator> > it_stack; 397 vec_t::const_iterator it, end; 398 size_t index; 399 400 // Recursively push stack while current (pseudo)element is an EmbeddedVector 401 // - Depends on the fact that VectorType::emplace_back(EmbeddedVectorType&& mbed) 402 // will not embed an empty vector, which ensures iterator will arrive at an actual element, 403 // unless already at end of parent VectorType. check_and_push()404 void check_and_push() 405 { 406 if (it != end) { 407 while (it->type() == Type::EMBEDDED_VECTOR) { 408 const vec_t &cur = it->toEmbeddedVector().ptr->vec; 409 it_stack.emplace_back(it, end); 410 it = cur.begin(); 411 end = cur.end(); 412 } 413 } 414 } 415 public: 416 using iterator_category = std::forward_iterator_tag ; 417 using value_type = Value; 418 using difference_type = void; 419 using reference = const value_type&; 420 using pointer = const value_type*; 421 iterator()422 iterator() : vo(EMPTY.ptr.get()), it_stack(), it(EMPTY.ptr->vec.begin()), end(EMPTY.ptr->vec.end()), index(0) {} iterator(const VectorObject * v)423 iterator(const VectorObject* v) : vo(v), it(v->vec.begin()), end(v->vec.end()), index(0) { 424 if (vo->embed_excess) check_and_push(); 425 } iterator(const VectorObject * v,bool)426 iterator(const VectorObject* v, bool /*end*/) : vo(v), index(v->size()) { } 427 iterator& operator++() { 428 ++index; 429 if (vo->embed_excess) { 430 // recursively increment and pop stack while at the end of EmbeddedVector(s) 431 while (++it == end && !it_stack.empty()) { 432 const auto& up = it_stack.back(); 433 it = up.first; 434 end = up.second; 435 it_stack.pop_back(); 436 } 437 check_and_push(); 438 } else { // vo->vec is flat 439 it = vo->vec.begin() + index; 440 } 441 return *this; 442 } 443 reference operator*() const { return *it; }; 444 pointer operator->() const { return &*it; }; 445 bool operator==(const iterator &other) const { return this->vo == other.vo && this->index == other.index; } 446 bool operator!=(const iterator &other) const { return this->vo != other.vo || this->index != other.index; } 447 }; 448 using const_iterator = const iterator; VectorType()449 VectorType() : ptr(shared_ptr<VectorObject>(new VectorObject(), VectorObjectDeleter() )) {} 450 VectorType(double x, double y, double z); 451 VectorType(const VectorType &) = delete; // never copy, move instead 452 VectorType& operator=(const VectorType &) = delete; // never copy, move instead 453 VectorType(VectorType&&) = default; 454 VectorType& operator=(VectorType&&) = default; clone()455 VectorType clone() const { return VectorType(this->ptr); } // Copy explicitly only when necessary Empty()456 static Value Empty() { return VectorType(); } 457 begin()458 const_iterator begin() const { return iterator(ptr.get()); } end()459 const_iterator end() const { return iterator(ptr.get(), true); } size()460 size_type size() const { return ptr->size(); } empty()461 bool empty() const { return ptr->vec.empty(); } 462 // const accesses to VectorObject require .clone to be move-able 463 const Value &operator[](size_t idx) const { 464 if (idx < this->size()) { 465 if (ptr->embed_excess) flatten(); 466 return ptr->vec[idx]; 467 } else { 468 return Value::undefined; 469 } 470 } 471 Value operator==(const VectorType &v) const; 472 Value operator< (const VectorType &v) const; 473 Value operator> (const VectorType &v) const; 474 Value operator!=(const VectorType &v) const; 475 Value operator<=(const VectorType &v) const; 476 Value operator>=(const VectorType &v) const; 477 478 void emplace_back(Value&& val); 479 void emplace_back(EmbeddedVectorType&& mbed); emplace_back(Args &&...args)480 template<typename... Args> void emplace_back(Args&&... args) { ptr->vec.emplace_back(std::forward<Args>(args)...); } 481 }; 482 483 class EmbeddedVectorType : public VectorType { 484 private: EmbeddedVectorType(const shared_ptr<VectorObject> & copy)485 explicit EmbeddedVectorType(const shared_ptr<VectorObject> ©) : VectorType(copy) { } // called by clone() 486 public: EmbeddedVectorType()487 EmbeddedVectorType() : VectorType() {}; 488 EmbeddedVectorType(const EmbeddedVectorType &) = delete; 489 EmbeddedVectorType& operator=(const EmbeddedVectorType &) = delete; 490 EmbeddedVectorType(EmbeddedVectorType&&) = default; 491 EmbeddedVectorType& operator=(EmbeddedVectorType&&) = default; 492 EmbeddedVectorType(VectorType && v)493 EmbeddedVectorType(VectorType&& v) : VectorType(std::move(v)) {}; // converting constructor clone()494 EmbeddedVectorType clone() const { return EmbeddedVectorType(this->ptr); } Empty()495 static Value Empty() { return EmbeddedVectorType(); } 496 }; 497 498 private: Value()499 Value() : value(UndefType()) { } // Don't default construct empty Values. If "undefined" needed, use reference to Value::undefined, or call Value::undef() for return by value 500 public: 501 Value(const Value &) = delete; // never copy, move instead 502 Value &operator=(const Value &v) = delete; // never copy, move instead 503 Value(Value&&) = default; 504 Value& operator=(Value&&) = default; 505 Value clone() const; // Use sparingly to explicitly copy a Value 506 Value(int v)507 Value(int v) : value(double(v)) { } Value(const char * v)508 Value(const char *v) : value(str_utf8_wrapper(v)) { } // prevent insane implicit conversion to bool! Value(char * v)509 Value( char *v) : value(str_utf8_wrapper(v)) { } // prevent insane implicit conversion to bool! 510 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r3.html Value(T && val)511 template<class T> Value(T&& val) : value(std::forward<T>(val)) { } 512 513 static Value undef(const std::string &why); // creation of undef requires a reason! 514 515 const std::string typeName() const; type()516 Type type() const { return static_cast<Type>(this->value.which()); } isDefinedAs(const Type type)517 bool isDefinedAs(const Type type) const { return this->type() == type; } isDefined()518 bool isDefined() const { return this->type() != Type::UNDEFINED; } isUndefined()519 bool isUndefined() const { return this->type() == Type::UNDEFINED; } 520 bool isUncheckedUndef() const; 521 522 // Conversion to boost::variant "BoundedType"s. const ref where appropriate. 523 bool toBool() const; 524 double toDouble() const; 525 const str_utf8_wrapper& toStrUtf8Wrapper() const; 526 const VectorType &toVector() const; 527 const EmbeddedVectorType& toEmbeddedVector() const; 528 VectorType &toVectorNonConst(); 529 EmbeddedVectorType &toEmbeddedVectorNonConst(); 530 const RangeType& toRange() const; 531 const FunctionType& toFunction() const; 532 533 // Other conversion utility functions 534 bool getDouble(double &v) const; 535 bool getFiniteDouble(double &v) const; 536 std::string toString() const; 537 std::string toString(const tostring_visitor *visitor) const; 538 std::string toEchoString() const; 539 std::string toEchoString(const tostring_visitor *visitor) const; 540 const UndefType& toUndef(); 541 std::string toUndefString() const; 542 void toStream(std::ostringstream &stream) const; 543 void toStream(const tostream_visitor *visitor) const; 544 std::string chrString() const; 545 bool getVec2(double &x, double &y, bool ignoreInfinite = false) const; 546 bool getVec3(double &x, double &y, double &z) const; 547 bool getVec3(double &x, double &y, double &z, double defaultval) const; 548 549 // Common Operators 550 operator bool() const = delete; 551 Value operator==(const Value &v) const; 552 Value operator!=(const Value &v) const; 553 Value operator< (const Value &v) const; 554 Value operator<=(const Value &v) const; 555 Value operator>=(const Value &v) const; 556 Value operator> (const Value &v) const; 557 Value operator-() const; 558 Value operator[](size_t idx) const; 559 Value operator[](const Value &v) const; 560 Value operator+(const Value &v) const; 561 Value operator-(const Value &v) const; 562 Value operator*(const Value &v) const; 563 Value operator/(const Value &v) const; 564 Value operator%(const Value &v) const; 565 Value operator^(const Value &v) const; 566 567 static bool cmp_less(const Value& v1, const Value& v2); 568 569 friend std::ostream &operator<<(std::ostream &stream, const Value &value) { 570 if (value.type() == Value::Type::STRING) stream << QuotedString(value.toString()); 571 else stream << value.toString(); 572 return stream; 573 } 574 575 typedef boost::variant<UndefType, bool, double, str_utf8_wrapper, VectorType, EmbeddedVectorType, RangePtr, FunctionPtr> Variant; 576 static_assert(sizeof(Variant) <= 24, "Memory size of Value too big"); 577 578 private: 579 Variant value; 580 }; 581 582 using VectorType = Value::VectorType; 583 using EmbeddedVectorType = Value::EmbeddedVectorType; 584