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 &range;
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> &copy) : 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> &copy) : 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