Turi Create  4.0
flexible_type.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 
7 #ifndef TURI_FLEXIBLE_TYPE_HPP
8 #define TURI_FLEXIBLE_TYPE_HPP
9 #include <string>
10 #include <vector>
11 #include <tuple>
12 #include <iostream>
13 #include <functional>
14 #include <typeindex>
15 #include <core/parallel/atomic.hpp>
17 #include <core/data/flexible_type/flexible_type_base_types.hpp>
18 namespace turi {
19 void flexible_type_fail(bool);
20 }
21 
22 // Note: Uses the same assert behavior in both release and debug,
23 // to ensure we never crash (always throw instead).
24 // See https://github.com/apple/turicreate/issues/1835
25 #define FLEX_TYPE_ASSERT(param) flexible_type_fail(param);
26 
27 #ifdef NDEBUG
28 // ---- RELEASE MODE ---
29 // enable all the inline and flatten attributes
30 #define FLEX_ALWAYS_INLINE __attribute__((always_inline))
31 #define FLEX_ALWAYS_INLINE_FLATTEN __attribute__((always_inline,flatten))
32 #define FLEX_TYPE_DASSERT(param)
33 
34 #else
35 // ---- DEBUG MODE ---
36 // disable the always_inline and flatten attributes
37 #define FLEX_ALWAYS_INLINE
38 #define FLEX_ALWAYS_INLINE_FLATTEN
39 #define FLEX_TYPE_DASSERT(param) FLEX_TYPE_ASSERT(param)
40 
41 #endif
42 
43 namespace turi {
44 
45 /**
46  * \ingroup group_gl_flexible_type
47  *
48  * The flexible_type is an automatic, self-managing union between the
49  * following types.
50  * - \ref flex_int
51  * - \ref flex_float
52  * - \ref flex_string
53  * - \ref flex_nd_vec
54  * - \ref flex_list
55  * - \ref flex_dict
56  * - \ref flex_image
57  * - \ref flex_undefined
58  *
59  * It is nearly every operator overloaded which
60  * allows it to behave very similarly to python data types.
61  *
62  * The internal representation of the flexible_type is simply:
63  * - 8 bytes of (flex_int, flex_double, flex_string* and flex_vec*)
64  * - 1 byte tag corresponding to a member of the enumeration \ref flex_type_enum
65  *
66  * \code
67  * flexible_type f = 1;
68  * flexible_type f2 = 2;
69  * f += f2; // f is now 3
70  * f += 1; // f is now 4
71  * if (f == 4) std::cout << "!";
72  * f = float(f); // convert f to float
73  * f += 2.5; // f is now 6.5
74  *
75  * // convert to string
76  * f = std::string(f); f is now "5"
77  * f += "hello"; // f is now "5hello"
78  *
79  * // vector test
80  * f = {1.1, 2.2}; // f is now a vector if {1.1, 2.2}
81  * f.push_back(3.3); // f is now a vector if {1.1, 2.2, 3.3}
82  * f.clear(); // f is now an empty vector
83  *
84  * for (flexible_type i = 0;i < 10; ++i) {
85  * f.push_back(i);
86  * }
87  * // f is now a vector from 1.0 to 10.0
88  *
89  * f = std::string("hello"); // f is now a string again
90  * f.mutable_get<flex_string>() = "boo"; // this gets a reference to the underlying storage
91  * f.mutable_get<flex_int>() = 5; // this will implode at runtime
92  * \endcode
93  *
94  * ### Type Information and Contents
95  * The type information for the contents of the flexible type can be obtained in
96  * three ways.
97  * - \ref flexible_type::get_type() Returns a member of the enumeration flex_type_enum
98  * - \ref flexible_type::which() Returns a number corresponding to size_t(get_type())
99  * Provided for compatibility with boost::variant
100  * - \ref flexible_type::type() Returns a std::type_index object corresponding to
101  * the typeid of the stored object.
102  * Provided for compatibility with boost::variant
103  *
104  * Knowing the type of the contents, the \ref flexible_type::get() function
105  * can be used to extract a reference to the content.
106  *
107  * \code
108  * flexible_type f(5);
109  * f.mutable_get<flex_int>() = 10;
110  * std::cout << f.get<flex_int>();
111  * \endcode
112  *
113  * If the incorrect type is provided, the \ref flexible_type::get() function
114  * will throw a runtime exception.
115  *
116  * A large number of casting operators are also provided and these work as expected.
117  * \code
118  * (int)f // casts doubles and integers to a integer. strings and vectors will fail.
119  * (float)f // casts doubles and integers to a double . strings and vectors will fail.
120  * (string)f // returns a printable string representation of all types.
121  * \endcode
122  *
123  * However, there are certain ambiguous cases whch do cause issues when
124  * using the explicit cast so, the \ref flexible_type::to() function is generally
125  * preferred:
126  * \code
127  * f.to<int>()
128  * f.to<float>()
129  * f.to<string>()
130  * \endcode
131  *
132  * ### Undefined
133  * A special undefined type is provided which is useful for identifying missing
134  * values (or the None value/type in Python). Such a value can be created using:
135  * \code
136  * flexible_type f = flex_undefined();
137  * // or
138  * flexible_type f = FLEX_UNDEFINED;
139  * \endcode
140  *
141  * ### Operators
142  * Practically every operator is overloaded, and the behaviors are relatively
143  * intuitive. See the documentation for each operator to determine legality.
144  * There are also special operator overloads to simplify access to the vector.
145  * For instance, flexible_type::operator[], flexible_type::clear() and
146  * flexible_type::push_back().
147  * In all cases, a runtime exception is thrown if an invalid type combination
148  * is encountered.
149  *
150  * The basic rule of the flexible_type is that the internal type is always
151  * preserved. Only an assignment can change the internal type of the object.
152  * Also, for consistency, operations between two flexible types always return
153  * a type corresponding to the flexible_type on the left of the operation.
154  * i.e.
155  * \code
156  * flexible_type f_int(5);
157  * flexible_type f_float(2.1);
158  *
159  * flexible_type f_res = f_int * f_float;
160  * // the type of f_res is an integer
161  *
162  * f_res = f_float * f_int;
163  * // the type of f_res is a float
164  * \endcode
165  *
166  * This is true also for operations where the 2nd argument is an arbitrary type.
167  *
168  * \code
169  * flexible_type f_float(2.1);
170  *
171  * flexible_type f_res = f_float + 2;
172  * // the type of f_res is a float
173  * \endcode
174  *
175  * The only exception to the rule is when the first argument is not a flexible type
176  * and the 2nd argument is a flexible type. In which case, the return type is the
177  * a flexible type corresponding to the type on the right.
178  *
179  * \code
180  * flexible_type f_float(2.1);
181  *
182  * flexible_type f_res = 2 + f_float;
183  * // the type of f_res is a float
184  * \endcode
185  *
186  * In summary:
187  * Where flexible_type_A is used to denote a flexible_type where the internal
188  * contents are of type A, and OP is an arbitrary operator,
189  * - flexible_type_A OP flexible_type_B ==> flexible_type_A
190  * - flexible_type_A OP T ==> flexible_type_A
191  * - T OP flexible_type_A ==> flexible_type_A
192  *
193  * This does mean that the binary operators are not commutative when performed
194  * across different types. ex:
195  * - (integer * float) produces an integer
196  * - (float * integer) produces an float
197  *
198  *
199  * ### Visitors
200  * Of the most powerful feature of the flexible_type, is the visitor mechanism
201  * which is designed in a very similar manner to that of the boost::variant.
202  * See \ref flexible_type::apply_visitor(Visitor) or
203  * \ref flexible_type::apply_mutating_visitor(Visitor) for details.
204  *
205  *
206  * ### Capability Checking
207  * Sometimes it can be useful to be able to query (at runtime, or at compile
208  * time) whether certain flexible_type operations will succeed or not. A number
209  * of useful functions are provided.
210  *
211  * Runtime Capability Queries:
212  * - \ref flex_type_has_binary_op . Checks if binary operators between certain
213  * types are supported.
214  * - \ref flex_type_is_convertible . Checks if certain type conversions can
215  * be performed.
216  *
217  * Compile-time Capability Queries:
218  * - \ref is_valid_flex_type . Checks at compile time if a type is one of the
219  * internal flexible_type types.
220  * - \ref enum_to_type . Gets the internal type from an enumeration value.
221  * - \ref type_to_enum . Gets the enumeration value from the internal type.
222  * - \ref has_direct_conversion_to_flexible_type . Can be casted to a flexible_type.
223  *
224  * ### Performance
225  * Performance of the flexible_type is generally extremely good. With modern
226  * compilers (sometimes with inlining limit bumped up) can sometimes produce
227  * code which is equivalent to, or runs as fast as the version using native
228  * types especially if certain type constraints are set-up before hand.
229  * For instance:
230  *
231  * \code
232  * if (x.get_type() == flex_type_enum::INTEGER) {
233  * ... do a whole bunch of stuff on x ...
234  * }
235  * \endcode
236  *
237  * Integers and Floating point values are stored in-place inside the
238  * flexible_type. All other types are somewhat more complex (strings,
239  * vectors etc) and are optimized by copy on write. i.e.
240  * \code
241  * flexible_type a = "hello world";
242  * flexible_type b = a;
243  * \endcode
244  * Both b and a will reference the same "hello world" until either one of them
245  * gets mutated. As such, all inplace operations
246  * (\ref get(), \ref apply_visitor(Visitor)) require const, but also have a
247  * mutating version (\ref mutating_get(), \ref apply_mutating_visitor(Visitor)).
248  */
250  private:
251  // used only for decltype deduction
252  // the instantiation does not actually exist
253  static flex_int prototype_flex_int;
254  public:
255  /**
256  * Default Constructor.
257  * By default constructs an integer of value 0.
258  */
259  flexible_type() noexcept;
260 
261  /**
262  * Construct from initializer List. Makes a vector
263  */
264  template <typename T>
265  flexible_type(std::initializer_list<T>&& list);
266 
267  /**
268  * Destructor.
269  */
270  ~flexible_type();
271 
272  /*
273  * Type constructor. Constructs a flexible type with a content type.
274  */
275  explicit flexible_type(flex_type_enum start_type) noexcept;
276 
277  /**
278  * Copy constructor. Assigns this to a copy of other.
279  */
280  flexible_type(const flexible_type& other) noexcept;
281 
282 
283  /**
284  * Copy constructor. Assigns this to a copy of other.
285  */
286  flexible_type(flexible_type& other) noexcept;
287 
288  template <size_t N>
289  flexible_type(const char v[N]):flexible_type() {
290  (*this) = flex_string(v, N);
291  }
292 
293  flexible_type(const char* c):flexible_type() {
294  (*this) = flex_string(c);
295  }
296  /**
297  * Copy constructor. Assigns this from arbitrary type.
298  * See \ref flexible_type::operator=
299  */
300  template <typename T>
301  flexible_type(const T& other, typename std::enable_if<has_direct_conversion_to_flexible_type<T>::value>::type* = nullptr);
302 
303 
304  /**
305  * Move constructor. Just assigns myself to the other, destroying the other.
306  */
307  flexible_type(flexible_type&& other) noexcept;
308 
309  /**
310  * Move constructor. (Const overload. Required since the T&& universal
311  * reference has a tendency to capture everything)
312  */
313  flexible_type(const flexible_type&& other) noexcept;
314 
315 
316  /**
317  * Move constructor. Assigns this from arbitrary type
318  */
319  template <typename T>
320  flexible_type(T&& other, typename std::enable_if<has_direct_conversion_to_flexible_type<typename std::remove_reference<T>::type>::value>::type* = nullptr);
321 
322 
323  /**
324  * Assign from another while preserving the type of the current flexible_type.
325  * - If left side is numeric and right side is numeric, the operation works
326  * as expected.
327  * - If left side is a string, the right side is converted to a string
328  * representation
329  * - if left side is a vector and right side is a vector, the vector is copied.
330  * - All other cases will result in an assertion failure.
331  */
332  flexible_type& soft_assign(const flexible_type& other);
333 
334 
335  /**
336  * Assignment operator. Copies the other to myself.
337  * See \ref flexible_type::operator=
338  */
339  flexible_type& operator=(const flexible_type& other) noexcept;
340 
341  /**
342  * Assignment operator. Copies the other to myself.
343  * See \ref flexible_type::operator=
344  */
345  flexible_type& operator=(flexible_type& other) noexcept;
346 
347 
348  /**
349  * Move assignment. Assigns myself from the other, destroying the other.
350  */
351  flexible_type& operator=(flexible_type&& other) noexcept;
352 
353 
354  /**
355  * Move assignment. (Const overload. Required since the T&& universal
356  * reference has a tendency to capture everything).
357  */
358  flexible_type& operator=(const flexible_type&& other) noexcept;
359 
360 
361  /**
362  * Assignment from arbitrary type.
363  * Figures out what can be casted from provided argument and stores that.
364  * Specifically, it tests the following operations in this order.
365  * - If T is an integral type, create a flexible_type of an integer
366  * - If T is a floating point type, create a flexible_type of a float
367  * - If T can be converted to a string, create a flexible_type of a string
368  * - If T can be converted to a flex_vec. create a flexible_type of a flex_vec.
369  */
370  template <typename T>
371  typename std::enable_if<
373  flexible_type&>::type operator=(const T& other);
374 
375 
376  template <size_t N>
377  flexible_type& operator=(const char v[N]) {
378  (*this) = flex_string(v, N);
379  return (*this);
380  }
381 
382  flexible_type& operator=(const char* c) {
383  (*this) = flex_string(c);
384  return (*this);
385  }
386  /**
387  * operator= for the undefined type
388  * See \ref flexible_type::operator=
389  */
390  flexible_type& operator=(flex_undefined other);
391 
392 
393  /**
394  * Move assignment from arbitrary type.
395  * Figures out what can be casted from provided argument and stores that.
396  * Specifically, it tests the following operations in this order.
397  * - If T is an integral type, create a flexible_type of an integer
398  * - If T is a floating point type, create a flexible_type of a float
399  * - If T can be converted to a string, create a flexible_type of a string
400  * - If T can be converted to a flex_vec. create a flexible_type of a flex_vec.
401  */
402  template <typename T>
403  typename std::enable_if<has_direct_conversion_to_flexible_type<
404  typename std::remove_reference<T>::type>::value,
405  flexible_type&>::type operator=(T&& other);
406 
407  /**
408  * Deletes the contents of this class, resetting to a different type.
409  *
410  * Note: Also ensures that that the reference count becomes 1.
411  */
412  void reset(flex_type_enum target_type);
413 
414  /**
415  * Deletes the contents of this class, resetting to an integer
416  */
417  void reset();
418 
419  /**
420  * Converts the current flexible type to a datetime type containing
421  * posix_timestamp value and timezone offset.
422  * The timezone offset is integral in \b fifteen-minute increments.
423  * i.e. a offset of 8 means timezone +2
424  */
425  flexible_type& set_date_time_from_timestamp_and_offset(const std::pair<flex_int,int32_t> & datetime,
426  const int32_t microsecond=0);
427 
428 
429  /**
430  * Where the current flexible_type contains a datetime type, returns
431  * the datetime as a pair of posix timestamp value and its timezone offset.
432  *
433  * The timezone offset is integral in \b fifteen-minute increments.
434  * i.e. a offset of 8 means timezone +2
435  */
436  std::pair<flex_int,int32_t> get_date_time_as_timestamp_and_offset() const;
437 
438  /**
439  * Gets the date_time microsecond value
440  */
441  int32_t get_date_time_microsecond() const;
442 
443  /**
444  * Swaps contents with another flexible_type
445  */
446  void swap(flexible_type& b);
447 
448 
449  /**
450  * Gets a modifiable reference to the value stored inside the flexible_type.
451  * T must be one of the flexible_type types.
452  * All other types will result in a compile type assertion failure.
453  * If the stored type does not match T, it will result in a run-time
454  * assertion failure.
455  */
456  template <typename T>
457  T& mutable_get();
458 
459  /**
460  * Gets a const reference to the value stored inside the flexible_type.
461  * T must be one of the flexible_type types.
462  * All other types will result in a compile type assertion failure.
463  * If the stored type does not match T, it will result in a run-time
464  * assertion failure.
465  */
466  template <typename T>
467  const T& get() const;
468 
469 
470  /**
471  * Gets a modifiable type unchecked modifiable reference to the value stored
472  * inside the flexible_type.
473  *
474  * This is generally unsafe to use unless you *really* know what
475  * you are doing. Use \ref get() instead.
476  *
477  * Note that this is only defined for flex_int and flex_float type. It really
478  * does not make sense to use this anywhere else.
479  */
480  template <typename T>
482 
483  /**
484  * Gets a type unchecked modifiable reference to the value stored
485  * inside the flexible_type.
486  *
487  * This is generally unsafe to use unless you *really* know what
488  * you are doing. Use \ref get() instead.
489  *
490  * Note that this is only defined for flex_int and flex_float type. It really
491  * does not make sense to use this anywhere else.
492  */
493  template <typename T>
494  const T& reinterpret_get() const;
495 
496  /**
497  * \{
498  * Converts the flexible_type to a particular type.
499  * Behaves like the implicit cast operators, but explicit.
500  * In particular, this gets around the thorny issue that there is no way
501  * to cast to an flex_vec, flex_list or flex_dict even though the
502  * implicit cast operators exist. This is due to std::vector<T> having two
503  * constructors:
504  * \code
505  * // regular copy constructor
506  * vector<T>::vector(const std::vector<T>&) ...
507  *
508  * // constructs a vector of a particular size
509  * vector<T>::vector(size_t N, T val = T()) ...
510  * \endcode
511  * Resulting in two possible implicit cast routes when doing:
512  * \code
513  * flexible_type f;
514  * ...
515  * flex_vec v = f; // fails
516  * flex_vec v = (flex_vec)f; // fails
517  * \endcode
518  *
519  * This function provides an explicit cast allowing the following to be
520  * written:
521  * \code
522  * flex_vec v = f.to<flex_vec>();
523  * \endcode
524  *
525  * Of course, the alternative of is always available.
526  * \code
527  * flex_vec v = f.operator flex_vec();
528  * \endcode
529  * And indeed, the implementation of to() simply redirects the calls.
530  */
531  template <typename T>
532  typename std::enable_if<!std::is_integral<T>::value && !std::is_floating_point<T>::value, T>::type
533  to() const;
534 
535  template<typename T>
536  typename std::enable_if<std::is_integral<T>::value, T>::type
537  to() const;
538 
539  template<typename T>
540  typename std::enable_if<std::is_floating_point<T>::value, T>::type
541  to() const;
542  /// \}
543 
544  /**
545  * Returns the type of the underlying storage
546  */
547  flex_type_enum get_type() const;
548 
549 
550  /**
551  * Returns the type index of the underlying storage.
552  * For compatibility with variant.
553  */
554  std::type_index type() const;
555 
556  /**
557  * Returns an integer ID identifying the type of the underlying storage.
558  * Equivalent to (size_t)(get_type()). For compatibility with variant.
559  */
560  size_t which() const;
561 
562  /**
563  * Returns a 64 bit hash of the underlying value, switched on type.
564  */
565  size_t hash() const;
566 
567  /**
568  * Returns a 128 bit hash of the underlying value, switched on type.
569  * This hash is appropriate for unique identification.
570  */
571  uint128_t hash128() const;
572 
573  /**
574  * Returns true if the value is equal to this type's equivalent of zero.
575  */
576  inline bool is_zero() const;
577 
578  /**
579  * Returns true if the value is considered a "missing value" or NA.
580  */
581  inline bool is_na() const;
582 
583  /**
584  * Returns true if the value, or any contained value in a dictionary or list type,
585  * is considered a "missing value" or NA.
586  */
587  bool contains_na() const;
588 
589 /**************************************************************************/
590 /* */
591 /* Visitor Functions */
592 /* */
593 /**************************************************************************/
594 
595  /**
596  * Executes an apply visitor on the flexible type.
597  * The apply visitor object must have a function void operator()(T& t) for
598  * every type T the flexible type can contain. The operator() function
599  * can be itself templated for convenience. For instance, the following
600  * visitor will add the value "1" to the flexible_type if the flexible_type
601  * contains an integer, and will ignore otherwise.
602  * \code
603  * struct add_one_to_integer {
604  * // do nothing
605  * template <typename T>
606  * void operator()(T& t) { }
607  *
608  * void operator()(flex_int& t) { t += 1; }
609  * };
610  * \endcode
611  *
612  * The visitor can return values but all versions of the operator() function
613  * must return exactly the same type. For instance:
614  *
615  * \code
616  * struct add_one_and_return {
617  * // do nothing
618  * template <typename T>
619  * int operator()(T& t) { return 0; }
620  *
621  * int operator()(flex_int& t) { t += 1; return t; }
622  * };
623  * \endcode
624  *
625  * In which case, apply_mutating_visitor will return a value:
626  * \code
627  * int ret = flex.apply_mutating_visitor(add_one_and_return());
628  * \endcode
629  *
630  * This function assumes that the function will mutate the value. If
631  * the function does not mutate the value, the alternative
632  * \ref apply_visitor(Visitor) should be used.
633  */
634  template <typename Visitor>
635  auto apply_mutating_visitor(Visitor visitor) -> decltype(visitor(prototype_flex_int));
636 
637 
638  /**
639  * Executes a non-mutating apply visitor on the flexible type.
640  * The apply visitor object must have a function void operator()(const T& t) for
641  * every type T the flexible type can contain. The operator() function
642  * can be itself templated for convenience. For instance, the following
643  * visitor will return one plus the value of the flexible_type if it
644  * contains an integer, or returns 0 otherwise.
645  *
646  * \code
647  * struct non_mutating_add_one {
648  * // do nothing
649  * template <typename T>
650  * int operator()(T& t) { return 0; }
651  *
652  * int operator()(flex_int& t) { return t + 1; }
653  * };
654  * \endcode
655  *
656  * \code
657  * int ret = flex.apply_visitor(non_mutating_add_one());
658  * \endcode
659  *
660  * This function requires that the function does not mutate the value. If
661  * the function does mutate the value, the alternative
662  * \ref apply_mutating_visitor(Visitor) should be used.
663  */
664  template <typename Visitor>
665  auto apply_visitor(Visitor visitor) const -> decltype(visitor(prototype_flex_int));
666 
667 
668 
669  /**
670  * Executes a binary visitor on the flexible type.
671  * The binary apply visitor object must have a function void
672  * operator()(T& t, const U& u) for every pair of types T and U the flexible
673  * type can contain. The operator() function can be itself templated for
674  * convenience. For instance, the following visitor will do a += if both
675  * types are integer.
676  * \code
677  * struct add_one_to_integer {
678  * // do nothing
679  * template <typename T, typename U>
680  * void operator()(T& t, const U& u) const { }
681  *
682  * void operator()(flex_int& t, const flex_int& u) const { t += u; }
683  * };
684  * \endcode
685  *
686  * Just like the unary apply_mutating_visitor. the visitor can return a value,
687  * but all versions of operator() must return an identical type.
688  *
689  * This function assumes that the function will mutate the value. If
690  * the function does not mutate the value, the alternative
691  * \ref apply_visitor(Visitor, const flexible_type&) should be used.
692  */
693  template <typename Visitor>
694  auto apply_mutating_visitor(Visitor visitor, const flexible_type& other) -> decltype(visitor(prototype_flex_int, flex_int()));
695 
696  /**
697  * Executes a binary visitor on the flexible type.
698  * The binary apply visitor object must have a function void
699  * operator()(const T& t, const U& u) for every pair of types T and U the
700  * flexible type can contain. The operator() function can be itself templated
701  * for convenience. For instance, the following visitor will return the sum
702  * of both values if only if both types are integral.
703  * \code
704  * struct add_one_to_integer {
705  * // do nothing
706  * template <typename T, typename U>
707  * int operator()(T& t, const U& u) const { return 0; }
708  *
709  * int operator()(flex_int& t, const flex_int& u) const { return t + u; }
710  * };
711  * \endcode
712  *
713  * Just like the unary apply_visitor. the visitor can return a value,
714  * but all versions of operator() must return an identical type.
715  *
716  * This function assumes that the function will not mutate the value. If
717  * the function does mutate the value, the alternative
718  * \ref apply_mutating_visitor(Visitor, const flexible_type&) should be used.
719  */
720  template <typename Visitor>
721  auto apply_visitor(Visitor visitor, const flexible_type& other) const -> decltype(visitor(prototype_flex_int, flex_int()));
722  /**************************************************************************/
723  /* */
724  /* Convenience Operator Overloads */
725  /* */
726  /**************************************************************************/
727  /// Implicit cast to integral types
728  template<class T,
729  typename std::enable_if<std::is_integral<T>::value>::type* = (void*)NULL>
730  inline FLEX_ALWAYS_INLINE_FLATTEN operator T() const {
731  return to<T>();
732  }
733 
734 
735  /// Implicit cast to floating point types
736  template<class T,
737  typename std::enable_if<std::is_floating_point<T>::value>::type* = (void*)NULL>
738  inline FLEX_ALWAYS_INLINE_FLATTEN operator T() const {
739  return to<T>();
740  }
741 
742  /**
743  * Implicit cast to string
744  */
745  operator flex_string() const;
746 
747  /**
748  * Implicit cast to vector<double>
749  */
750  operator flex_vec() const;
751 
752  /**
753  * Implicit cast to ndarray<double>
754  */
755  operator flex_nd_vec() const;
756 
757  /**
758  * Implicit cast to vector<flexible_type>
759  */
760  operator flex_list() const;
761 
762  /**
763  * Implicit cast to vector<pair<flexible_type, flexible_type>>
764  */
765  operator flex_dict() const;
766 
767 
768  /**
769  * Implicit cast to flex_date_time
770  */
771  operator flex_date_time() const;
772 
773  /**
774  * Implicit cast to flex_image
775  */
776  operator flex_image() const;
777 
778  /**
779  * negation operator.
780  * - negation operator.
781  * - If the value is a numeric, the negation will return a negated value
782  * of the same type.
783  * - If the value is a vector, the negation will return a vector with every
784  * element negated.
785  * - All other conditions will result in an assertion failure.
786  */
787  flexible_type operator-() const ;
788 
789 
790  /**
791  * plus-equal operator.
792  * - If both are numeric types (int / flex_float), the += will behave as expected.
793  * - If both are strings, the += will append.
794  * - If both are vectors, the += will perform a vector addition.
795  * - If the left hand side is a vector, and right hand side is an int/float,
796  * the right hand side value will be added to each value in the vector.
797  * - All other conditions will result in an assertion failure.
798  */
799  flexible_type& operator+=(const flexible_type& other) ;
800 
801 
802  /**
803  * subtract-equal operator.
804  * - If both are numeric types (int / float), the -= will behave as expected.
805  * - If both are vectors, the -= will perform a vector subtraction.
806  * - If the left hand side is a vector, and right hand side is an int/float,
807  * the right hand side value will be subtracted from each value in the vector.
808  * - All other conditions will result in an assertion failure.
809  */
810  flexible_type& operator-=(const flexible_type& other) ;
811 
812 
813 
814  /**
815  * divide-equal operator.
816  * - If both are numeric types (int / float), the /= will behave as expected.
817  * - If the left hand side is a vector, and right hand side is an int/float,
818  * the right hand side value will be divided from each value in the vector.
819  * - All other conditions will result in an assertion failure.
820  */
821  flexible_type& operator/=(const flexible_type& other) ;
822 
823 
824 
825  /**
826  * mod-equal operator.
827  * - If both are numeric types (int / float), the %= will behave as expected.
828  * - If the left hand side is a vector, and right hand side is an int/float,
829  * the right hand side value will be divided from each value in the vector.
830  * - All other conditions will result in an assertion failure.
831  */
832  flexible_type& operator%=(const flexible_type& other) ;
833 
834  /**
835  * times-equal operator.
836  * - If both are numeric types (int / float), the *= will behave as expected.
837  * - If the left hand side is a vector, and right hand side is an int/float,
838  * the right hand side value will be multiplied to each value in the vector.
839  * - All other conditions will result in an assertion failure.
840  */
841  flexible_type& operator*=(const flexible_type& other) ;
842 
843 
844  /**
845  * Plus operator.
846  * \code
847  * a = (*this);
848  * a += other;
849  * return a;
850  * \endcode
851  *
852  * Note that unlike regular C++ typing rules, the resultant type is
853  * always the type of the left hand side. i.e. int + float = int,
854  * and float + int = float.
855  */
856  flexible_type operator+(const flexible_type& other) const;
857 
858  /**
859  * Subtract operator.
860  * Equivalent to
861  * \code
862  * a = (*this);
863  * a += other;
864  * return a;
865  * \endcode
866  *
867  * Note that unlike regular C++ typing rules, the resultant type is
868  * always the type of the left hand side. i.e. int + float = int,
869  * and float + int = float.
870  */
871  flexible_type operator-(const flexible_type& other) const;
872 
873 
874  /**
875  * Multiplication operator.
876  * Equivalent to
877  * \code
878  * a = (*this);
879  * a *= other;
880  * return a;
881  * \endcode
882  *
883  * Note that unlike regular C++ typing rules, the resultant type is
884  * always the type of the left hand side. i.e. int + float = int,
885  * and float + int = float.
886  */
887  flexible_type operator*(const flexible_type& other) const;
888 
889 
890 
891  /**
892  * Division operator.
893  * Equivalent to
894  * \code
895  * a = (*this);
896  * a /= other;
897  * return a;
898  * \endcode
899  *
900  * Note that unlike regular C++ typing rules, the resultant type is
901  * always the type of the left hand side. i.e. int + float = int,
902  * and float + int = float.
903  */
904  flexible_type operator/(const flexible_type& other) const;
905 
906 
907  /**
908  * Modulus operator.
909  * Equivalent to
910  * \code
911  * a = (*this);
912  * a %= otrer;
913  * return a;
914  * \endcode
915  *
916  * Note that unlike regular C++ typing rules, the resultant type is
917  * always the type of the left hand side. i.e. int + float = int,
918  * and float + int = float.
919  */
920  flexible_type operator%(const flexible_type& other) const;
921 
922 
923 
924  /**
925  * Compares if two flexible types are equivalent in value. i.e.
926  * permitting comparisons between integer and floating point types.
927  * Same as \ref flexible_type::approx_equal
928  */
929  bool operator==(const flexible_type& other) const;
930 
931 
932  /**
933  * Compares if two flexible types are not equivalent in value. i.e.
934  * permitting comparisons between integer and floating point types.
935  * Same as \ref flexible_type::approx_equal
936  */
937  bool operator!=(const flexible_type& other) const;
938 
939 
940  /**
941  * Compares if two flexible types are equivalent in value. i.e.
942  * permitting comparisons between integer and floating point types.
943  */
944  bool approx_equal(const flexible_type& other) const;
945 
946  /**
947  * Like operator== but requires also types to be equivalent.
948  */
949  bool identical(const flexible_type& other) const;
950 
951 
952 
953  /**
954  * Less than operator.
955  * - If both this and other are int / floats. this behaves as expected
956  * - All other cases will result in an assertion failure
957  */
958  bool operator<(const flexible_type& other) const;
959 
960  /**
961  * greater than operator.
962  * - If both this and other are int / floats. this behaves as expected
963  * - All other cases will result in an assertion failure
964  */
965  bool operator>(const flexible_type& other) const;
966 
967  /**
968  * less than or equal than operator.
969  * - If both this and other are int / floats. this behaves as expected
970  * - All other cases will result in an assertion failure
971  */
972  bool operator<=(const flexible_type& other) const;
973 
974  /**
975  * greater than or equal than operator.
976  * - If both this and other are int / floats. this behaves as expected
977  * - All other cases will result in an assertion failure
978  */
979  bool operator>=(const flexible_type& other) const;
980 
981  /// Preincrement. Equivalent to (*this)+=1
982  flexible_type& operator++();
983 
984 
985  /// Preincrement. Equivalent to (*this)+=1, returning a copy of the previous value
986  flexible_type operator++(int);
987 
988 
989 
990  /// Preincrement. Equivalent to (*this)-=1
991  flexible_type& operator--();
992 
993 
994  /// Preincrement. Equivalent to (*this)-=1, returning a copy of the previous value
995  flexible_type operator--(int);
996 
997 
998  // template versions of all the operators to compare against
999  // other types
1000  //
1001  /**
1002  * Subtract operator with arbitrary type.
1003  * Equivalent to (*this) - (flexible_type)(other);
1004  */
1005  template <typename T>
1006  flexible_type operator-(const T& other) const;
1007  /**
1008  * Addition operator with arbitrary type.
1009  * Equivalent to (*this) + (flexible_type)(other);
1010  */
1011  template <typename T>
1012  flexible_type operator+(const T& other) const;
1013  /**
1014  * Division operator with arbitrary type.
1015  * Equivalent to (*this) / (flexible_type)(other);
1016  */
1017  template <typename T>
1018  flexible_type operator/(const T& other) const;
1019  /**
1020  * Modulos operator with arbitrary type.
1021  * Equivalent to (*this) % (flexible_type)(other);
1022  */
1023  template <typename T>
1024  flexible_type operator%(const T& other) const;
1025  /**
1026  * Multiplication operator with arbitrary type.
1027  * Equivalent to (*this) * (flexible_type)(other);
1028  */
1029  template <typename T>
1030  flexible_type operator*(const T& other) const;
1031  /**
1032  * Equality comparison operator with arbitrary type.
1033  * Equivalent to (*this) == (flexible_type)(other);
1034  */
1035  template <typename T>
1036  bool operator==(const T& other) const;
1037  /**
1038  * Equality comparison operator with arbitrary type.
1039  * Equivalent to (*this) != (flexible_type)(other);
1040  */
1041  template <typename T>
1042  bool operator!=(const T& other) const;
1043  /**
1044  * Less than comparison operator with arbitrary type.
1045  * Equivalent to (*this) < (flexible_type)(other);
1046  */
1047  template <typename T>
1048  bool operator<(const T& other) const;
1049  /**
1050  * Greater than comparison operator with arbitrary type.
1051  * Equivalent to (*this) > (flexible_type)(other);
1052  */
1053  template <typename T>
1054  bool operator>(const T& other) const;
1055  /**
1056  * Less than or equal comparison operator with arbitrary type.
1057  * Equivalent to (*this) <= (flexible_type)(other);
1058  */
1059  template <typename T>
1060  bool operator<=(const T& other) const;
1061  /**
1062  * Greater than or equal comparison operator with arbitrary type.
1063  * Equivalent to (*this) >= (flexible_type)(other);
1064  */
1065  template <typename T>
1066  bool operator>=(const T& other) const;
1067 
1068 
1069  /**
1070  * Array indexing operator.
1071  * - When the contents of the flexible_type is a vector,
1072  * Returns a reference to the 'index' entry in the vector.
1073  * - When the contents is a float, returns a reference to the float
1074  * only if the index is 0. (i.e. letting the scalar float act
1075  * like a vector of size 1. All other indexes will fail with an
1076  * assertion failure.
1077  * - All other types will result in an assertion failure.
1078  */
1079  flex_float& operator[](size_t index);
1080 
1081  /**
1082  * Array indexing operator.
1083  * - When the contents of the flexible_type is a vector,
1084  * Returns a reference to the 'index' entry in the vector.
1085  * - When the contents is a float, returns a reference to the float
1086  * only if the index is 0. (i.e. letting the scalar float act
1087  * like a vector of size 1. All other indexes will fail with an
1088  * assertion failure.
1089  * - All other types will result in an assertion failure.
1090  */
1091  const flex_float& operator[](size_t index) const;
1092 
1093 
1094  /**
1095  * List indexing operator.
1096  * - When the contents of the flexible_type is a list.
1097  * Returns a reference to the 'index' entry in the vector.
1098  * - All other types will result in an assertion failure.
1099  */
1100  flexible_type& array_at(size_t index) ;
1101 
1102 
1103  /**
1104  * List indexing operator.
1105  * - When the contents of the flexible_type is a list.
1106  * Returns a reference to the 'index' entry in the vector.
1107  * - All other types will result in an assertion failure.
1108  */
1109  const flexible_type& array_at(size_t index) const ;
1110 
1111  /**
1112  * dict indexing operator.
1113  * - When the contents of the flexible_type is a dictionary,
1114  * Returns a reference to the 'index' entry in the dict array.
1115  * - All other types will result in an assertion failure.
1116  */
1117  flexible_type& dict_at(const flexible_type& index) ;
1118 
1119 
1120  /**
1121  * dict indexing operator.
1122  * - When the contents of the flexible_type is a dictionary,
1123  * Returns a reference to the 'index' entry in the dict array.
1124  * - All other types will result in an assertion failure.
1125  */
1126  const flexible_type& dict_at(const flexible_type& index) const ;
1127 
1128 
1129 
1130  /**
1131  * List indexing operator.
1132  * - When the contents of the flexible_type is a list or dict
1133  * Returns a reference to the 'index' entry in the vector.
1134  * - All other types will result in an assertion failure.
1135  */
1136  flexible_type& operator()(size_t index) ;
1137 
1138 
1139  /**
1140  * List indexing operator.
1141  * - When the contents of the flexible_type is a list or dict,
1142  * Returns a reference to the 'index' entry in the vector.
1143  * - All other types will result in an assertion failure.
1144  */
1145  const flexible_type& operator()(size_t index) const ;
1146 
1147  /**
1148  * DIct indexing operator.
1149  * - When the contents of the flexible_type is a dict,
1150  * Returns a reference to the 'index' entry in the dict array.
1151  * - All other types will result in an assertion failure.
1152  */
1153  flexible_type& operator()(const flexible_type& index) ;
1154 
1155 
1156  /**
1157  * Dict indexing operator.
1158  * - When the contents of the flexible_type is a dict,
1159  * Returns a reference to the 'index' entry in the dict array.
1160  * - All other types will result in an assertion failure.
1161  */
1162  const flexible_type& operator()(const flexible_type& index) const ;
1163 
1164 
1165  /**
1166  * Array length function.
1167  * - When the contents of the flexible_type is a vector or a recursive array
1168  * Returns the length of the vector.
1169  * - When the contents is a float, returns 1
1170  * (i.e. letting the scalar float act like a vector of size 1.)
1171  * - All other types will result in an assertion failure.
1172  */
1173  size_t size() const;
1174 
1175  /**
1176  * Array resize function
1177  * - When the contents of the flexible_type is a vector or a recursive array
1178  * resizes the array
1179  * - All other types will result in an assertion failure.
1180  */
1181  void resize(size_t s);
1182 
1183  /**
1184  * Array clear function.
1185  * - When the contents of the flexible_type is a vector, clears the vector.
1186  * - When the contents of the flexible_type is a recursive object,
1187  * clears the recursive array
1188  * - All other types will result in an assertion failure.
1189  */
1190  void clear();
1191 
1192  /**
1193  * Dict element erase function.
1194  * - When the contents of the flexible_type is a dict, erases
1195  * the element indexed by the index value.
1196  * - All other types will result in an assertion failure.
1197  */
1198  void erase(const flexible_type& index);
1199 
1200  /**
1201  * Array insertion function.
1202  * - When the contents of the flexible_type is a vector, inserts
1203  * the element to the end of the vector.
1204  * - When the contents of the flexible_type is a recursive array, inserts
1205  * a float to the end of the vector.
1206  * - All other types will result in an assertion failure.
1207  */
1208  void push_back(flex_float i);
1209 
1210 
1211  /**
1212  * Array / List insertion function.
1213  * - When the contents of the flexible_type is a vector, and the element
1214  * is a floating point number, inserts the element to the end of the vector.
1215  * - When the contents of the flexible_type is a list, inserts
1216  * a value to the end of the vector.
1217  * - All other types will result in an assertion failure.
1218  */
1219  void push_back(const flexible_type& i);
1220 
1221 
1222  /**
1223  * Serializer. Saves the flexible_type in an archive object.
1224  */
1225  void save(oarchive& oarc) const;
1226 
1227  /**
1228  * Deserializer. Loads the flexible_type from an archive object.
1229  * Note that the type of the flexible_type may change.
1230  */
1231  void load(iarchive& iarc);
1232 
1233  private:
1234  /*
1235  * union over the data types.
1236  * val holds the actual value.
1237  */
1238  union union_type {
1239  union_type(){};
1240  flex_int intval;
1241  flex_float dblval;
1242  std::pair<atomic<size_t>, flex_string>* strval;
1243  std::pair<atomic<size_t>, flex_vec>* vecval;
1244  std::pair<atomic<size_t>, flex_nd_vec>* ndvecval;
1245  std::pair<atomic<size_t>, flex_list>* recval;
1246  std::pair<atomic<size_t>, flex_dict>* dictval;
1247  std::pair<atomic<size_t>, flex_image>* imgval;
1248  flex_date_time dtval;
1249 
1250  struct {
1251  char padding[sizeof(flex_date_time)];
1252  flex_type_enum stored_type;
1253  };
1254  } val;
1255 
1256  void clear_memory_internal();
1257 
1258  inline FLEX_ALWAYS_INLINE_FLATTEN void ensure_unique() {
1259  switch(val.stored_type){
1261  if (val.strval->first.value == 1) return;
1262  else {
1263  union_type prev;
1264  prev = val;
1265  val.strval = new std::pair<atomic<size_t>, flex_string>(*(val.strval));
1266  val.strval->first.value = 1;
1267  decref(prev, flex_type_enum::STRING);
1268  }
1269  break;
1271  if (val.vecval->first.value == 1) return;
1272  else {
1273  union_type prev;
1274  prev = val;
1275  val.vecval = new std::pair<atomic<size_t>, flex_vec>(*(val.vecval));
1276  val.vecval->first.value = 1;
1277  decref(prev, flex_type_enum::VECTOR);
1278  }
1279  break;
1281  if (val.ndvecval->first.value == 1) return;
1282  else {
1283  union_type prev;
1284  prev = val;
1285  val.ndvecval = new std::pair<atomic<size_t>, flex_nd_vec>(*(val.ndvecval));
1286  val.ndvecval->first.value = 1;
1287  decref(prev, flex_type_enum::ND_VECTOR);
1288  }
1289  break;
1290  case flex_type_enum::LIST:
1291  if (val.recval->first.value == 1) return;
1292  else {
1293  union_type prev;
1294  prev = val;
1295  val.recval = new std::pair<atomic<size_t>, flex_list>(*(val.recval));
1296  val.recval->first.value = 1;
1297  decref(prev, flex_type_enum::LIST);
1298  }
1299  break;
1300  case flex_type_enum::DICT:
1301  if (val.dictval->first.value == 1) return;
1302  else {
1303  union_type prev;
1304  prev = val;
1305  val.dictval = new std::pair<atomic<size_t>, flex_dict>(*(val.dictval));
1306  val.dictval->first.value = 1;
1307  decref(prev, flex_type_enum::DICT);
1308  }
1309  break;
1310  case flex_type_enum::IMAGE:
1311  if (val.imgval->first.value == 1) return;
1312  else {
1313  union_type prev;
1314  prev = val;
1315  val.imgval = new std::pair<atomic<size_t>, flex_image>(*(val.imgval));
1316  val.imgval->first.value = 1;
1317  decref(prev, flex_type_enum::IMAGE);
1318  }
1319  break;
1320  default:
1321  break;
1322  // do nothing
1323  }
1324  }
1325 
1326  static inline FLEX_ALWAYS_INLINE_FLATTEN void decref(union_type& v, flex_type_enum type) noexcept {
1327  switch(type){
1329  if (v.strval->first.dec() == 0) {
1330  delete v.strval;
1331  v.strval = NULL;
1332  }
1333  break;
1335  if (v.vecval->first.dec() == 0) {
1336  delete v.vecval;
1337  v.vecval = NULL;
1338  }
1339  break;
1341  if (v.ndvecval->first.dec() == 0) {
1342  delete v.ndvecval;
1343  v.ndvecval = NULL;
1344  }
1345  break;
1346  case flex_type_enum::LIST:
1347  if (v.recval->first.dec() == 0) {
1348  delete v.recval;
1349  v.recval = NULL;
1350  }
1351  break;
1352  case flex_type_enum::DICT:
1353  if (v.dictval->first.dec() == 0) {
1354  delete v.dictval;
1355  v.dictval = NULL;
1356  }
1357  break;
1358  case flex_type_enum::IMAGE:
1359  if (v.imgval->first.dec() == 0) {
1360  delete v.imgval;
1361  v.imgval = NULL;
1362  }
1363  break;
1364  default:
1365  break;
1366  // do nothing
1367  }
1368  }
1369 
1370  static inline FLEX_ALWAYS_INLINE_FLATTEN void incref(union_type& v, flex_type_enum type) noexcept {
1371  switch(type){
1373  v.strval->first.inc();
1374  break;
1376  v.vecval->first.inc();
1377  break;
1379  v.ndvecval->first.inc();
1380  break;
1381  case flex_type_enum::LIST:
1382  v.recval->first.inc();
1383  break;
1384  case flex_type_enum::DICT:
1385  v.dictval->first.inc();
1386  break;
1387  case flex_type_enum::IMAGE:
1388  v.imgval->first.inc();
1389  default:
1390  break;
1391  // do nothing
1392  }
1393  }
1394 };
1395 
1396 /**
1397  * \ingroup group_gl_flexible_type
1398  *
1399  * A global static variable to be used when an undefined
1400  * value is needed. i.e.
1401  * \code
1402  * flexible_type f = FLEX_UNDEFINED;
1403  * \endcode
1404  */
1405 static flexible_type FLEX_UNDEFINED = flex_undefined();
1406 
1407 
1408 } // namespace turi
1409 
1410 
1411 
1412 namespace std {
1413 
1414 #ifdef __clang__
1415 #pragma clang diagnostic push
1416 #pragma clang diagnostic ignored "-Wmismatched-tags"
1417 #endif
1418 
1419 template<>
1420 struct hash<turi::flexible_type> {
1421  inline FLEX_ALWAYS_INLINE size_t operator()(const turi::flexible_type& s) const {
1422  return s.hash();
1423  }
1424 };
1425 
1426 #ifdef __clang__
1427 #pragma clang diagnostic pop
1428 #endif
1429 
1430 }
1431 
1432 
1433 namespace std {
1434 template<>
1435 inline void swap(turi::flexible_type& a, turi::flexible_type& b) noexcept {
1436  a.swap(b);
1437 }
1438 }
1439 
1440 /**************************************************************************/
1441 /* */
1442 /* Implementation Begins Here */
1443 /* */
1444 /**************************************************************************/
1445 
1446 
1447 #include <core/data/flexible_type/flexible_type_detail.hpp>
1448 
1449 
1450 namespace turi {
1451 
1452 inline FLEX_ALWAYS_INLINE std::pair<flex_int,int32_t> flexible_type::get_date_time_as_timestamp_and_offset() const {
1453  std::pair<flex_int,int32_t> ret;
1454  ret.first = val.dtval.posix_timestamp();
1455  ret.second = val.dtval.time_zone_offset();
1456  return ret;
1457 }
1458 
1459 inline FLEX_ALWAYS_INLINE int32_t flexible_type::get_date_time_microsecond() const {
1460  return val.dtval.microsecond();
1461 }
1462 
1463 
1464 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::set_date_time_from_timestamp_and_offset (const std::pair<flex_int,int32_t> & datetime, const int32_t microseconds) {
1466  val.dtval.set_posix_timestamp(datetime.first);
1467  val.dtval.set_time_zone_offset(datetime.second);
1468  val.dtval.set_microsecond(microseconds);
1469  return *this;
1470 }
1471 
1472 
1473 
1474 /**************************************************************************/
1475 /* */
1476 /* We Begin with Specializations of the getters */
1477 /* */
1478 /**************************************************************************/
1479 
1480 
1481 // flex_date_time
1482 template <>
1483 inline FLEX_ALWAYS_INLINE flex_date_time& flexible_type::mutable_get<flex_date_time>() {
1484  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::DATETIME);
1485  return val.dtval;
1486 }
1487 
1488 template <>
1489 inline FLEX_ALWAYS_INLINE const flex_date_time& flexible_type::get<flex_date_time>() const {
1490  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::DATETIME);
1491  return val.dtval;
1492 }
1493 
1494 // INTEGER
1495 template <>
1496 inline FLEX_ALWAYS_INLINE flex_int& flexible_type::mutable_get<flex_int>() {
1497  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::INTEGER);
1498  return val.intval;
1499 }
1500 
1501 template <>
1502 inline FLEX_ALWAYS_INLINE const flex_int& flexible_type::get<flex_int>() const {
1503  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::INTEGER);
1504  return val.intval;
1505 }
1506 
1507 template <>
1508 inline FLEX_ALWAYS_INLINE flex_int& flexible_type::reinterpret_mutable_get<flex_int>() {
1509  return val.intval;
1510 }
1511 
1512 template <>
1513 inline FLEX_ALWAYS_INLINE const flex_int& flexible_type::reinterpret_get<flex_int>() const {
1514  return val.intval;
1515 }
1516 
1517 // flex_float
1518 template <>
1519 inline FLEX_ALWAYS_INLINE flex_float& flexible_type::mutable_get<flex_float>() {
1520  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::FLOAT);
1521  return val.dblval;
1522 }
1523 
1524 
1525 template <>
1526 inline FLEX_ALWAYS_INLINE const flex_float& flexible_type::get<flex_float>() const {
1527  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::FLOAT);
1528  return val.dblval;
1529 }
1530 
1531 template <>
1532 inline FLEX_ALWAYS_INLINE flex_float& flexible_type::reinterpret_mutable_get<flex_float>() {
1533  return val.dblval;
1534 }
1535 
1536 template <>
1537 inline FLEX_ALWAYS_INLINE const flex_float& flexible_type::reinterpret_get<flex_float>() const {
1538  return val.dblval;
1539 }
1540 
1541 
1542 // STRING
1543 template <>
1544 inline FLEX_ALWAYS_INLINE flex_string& flexible_type::mutable_get<flex_string>() {
1545  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::STRING);
1546  ensure_unique();
1547  return val.strval->second;
1548 }
1549 
1550 template <>
1551 inline FLEX_ALWAYS_INLINE const flex_string& flexible_type::get<flex_string>() const {
1552  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::STRING);
1553  return val.strval->second;
1554 }
1555 
1556 
1557 // VECTOR
1558 template <>
1559 inline FLEX_ALWAYS_INLINE flex_vec& flexible_type::mutable_get<flex_vec>() {
1560  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::VECTOR);
1561  ensure_unique();
1562  return val.vecval->second;
1563 }
1564 
1565 
1566 template <>
1567 inline FLEX_ALWAYS_INLINE const flex_vec& flexible_type::get<flex_vec>() const {
1568  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::VECTOR);
1569  return val.vecval->second;
1570 }
1571 
1572 
1573 // ND_VECTOR
1574 template <>
1575 inline FLEX_ALWAYS_INLINE flex_nd_vec& flexible_type::mutable_get<flex_nd_vec>() {
1576  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::ND_VECTOR);
1577  ensure_unique();
1578  return val.ndvecval->second;
1579 }
1580 
1581 
1582 template <>
1583 inline FLEX_ALWAYS_INLINE const flex_nd_vec& flexible_type::get<flex_nd_vec>() const {
1584  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::ND_VECTOR);
1585  return val.ndvecval->second;
1586 }
1587 
1588 
1589 // DICT
1590 template <>
1591 inline FLEX_ALWAYS_INLINE flex_list& flexible_type::mutable_get<flex_list>() {
1592  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::LIST);
1593  ensure_unique();
1594  return val.recval->second;
1595 }
1596 
1597 
1598 template <>
1599 inline FLEX_ALWAYS_INLINE const flex_list& flexible_type::get<flex_list>() const {
1600  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::LIST);
1601  return val.recval->second;
1602 }
1603 
1604 
1605 // DICT
1606 template <>
1607 inline FLEX_ALWAYS_INLINE flex_dict& flexible_type::mutable_get<flex_dict>() {
1608  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::DICT);
1609  ensure_unique();
1610  return val.dictval->second;
1611 }
1612 
1613 
1614 template <>
1615 inline FLEX_ALWAYS_INLINE const flex_dict& flexible_type::get<flex_dict>() const {
1616  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::DICT);
1617  return val.dictval->second;
1618 }
1619 
1620 
1621 // IMAGE
1622 template <>
1623 inline FLEX_ALWAYS_INLINE flex_image& flexible_type::mutable_get<flex_image>() {
1624  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::IMAGE);
1625  ensure_unique();
1626  return val.imgval->second;
1627 }
1628 
1629 template <>
1630 inline FLEX_ALWAYS_INLINE const flex_image& flexible_type::get<flex_image>() const {
1631  FLEX_TYPE_DASSERT(get_type() == flex_type_enum::IMAGE);
1632  return val.imgval->second;
1633 }
1634 
1635 
1636 
1637 inline FLEX_ALWAYS_INLINE void flexible_type::clear_memory_internal() {
1638  static_assert(sizeof(flex_date_time) == 12, "sizeof(flex_date_time)");
1639  static_assert(sizeof(flexible_type::union_type) == sizeof(flex_date_time) + 4,
1640  "sizeof(flexible_type::union_type)");
1641  static_assert(static_cast<int>(flex_type_enum::INTEGER) == 0,
1642  "value of flex_type_enum::INTEGER");
1643 
1644  val.intval = 0;
1645  val.dtval.m_microsecond = 0;
1646  val.stored_type = flex_type_enum::INTEGER;
1647 }
1648 
1649 //constructors
1650 inline FLEX_ALWAYS_INLINE flexible_type::flexible_type() noexcept {
1651  clear_memory_internal();
1652 }
1653 
1654 template <typename T>
1655 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(std::initializer_list<T>&& list) :flexible_type() {
1657  // always unique after a reset
1658  val.vecval->second = flex_vec(list);
1659 }
1660 
1661 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::~flexible_type() {
1662  reset();
1663 }
1664 
1665 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(flex_type_enum start_type) noexcept:flexible_type() {
1666  reset(start_type);
1667 }
1668 
1669 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(const flexible_type& other) noexcept:flexible_type() {
1670  (*this) = other;
1671 }
1672 
1673 
1674 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(flexible_type& other) noexcept:flexible_type() {
1675  (*this) = other;
1676 }
1677 
1678 
1679 template <typename T>
1680 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(const T& other, typename std::enable_if<has_direct_conversion_to_flexible_type<T>::value>::type*) :flexible_type() {
1681  (*this) = other;
1682 }
1683 
1684 
1685 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(flexible_type&& other) noexcept: flexible_type() {
1686  val = other.val;
1687  val.stored_type = other.get_type();
1688  other.val.stored_type = flex_type_enum::INTEGER;
1689 }
1690 
1691 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(const flexible_type&& other) noexcept: flexible_type() {
1692  val = other.val;
1693  val.stored_type = other.get_type();
1694  incref(val, val.stored_type);
1695 }
1696 
1697 template <typename T>
1698 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::flexible_type(T&& other, typename std::enable_if<has_direct_conversion_to_flexible_type<typename std::remove_reference<T>::type>::value>::type*) :flexible_type() {
1699  this->operator=(std::forward<T>(other));
1700 }
1701 
1702 
1703 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::soft_assign(const flexible_type& other) {
1704  if (&other == this) return *this;
1706  return *this;
1707 }
1708 
1709 
1710 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator=(const flexible_type& other)noexcept {
1711  if (&other == this) return *this;
1712  decref(val, val.stored_type);
1713  val = other.val;
1714  val.stored_type = other.get_type();
1715  incref(val, val.stored_type);
1716  return *this;
1717 }
1718 
1719 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator=(flexible_type& other)noexcept {
1720  if (__builtin_expect(&other == this, 0)) return *this;
1721  decref(val, val.stored_type);
1722  val = other.val;
1723  val.stored_type = other.get_type();
1724  incref(val, val.stored_type);
1725  return *this;
1726 }
1727 
1728 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator=(const flexible_type&& other) noexcept{
1729  if (__builtin_expect(&other == this, 0)) return *this;
1730  decref(val, val.stored_type);
1731  val = other.val;
1732  val.stored_type = other.get_type();
1733  incref(val, val.stored_type);
1734  return *this;
1735 }
1736 
1737 
1738 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator=(flexible_type&& other) noexcept{
1739  if (__builtin_expect(&other == this, 0)) return *this;
1740  decref(val, val.stored_type);
1741  val = other.val;
1742  val.stored_type = other.get_type();
1743  other.val.stored_type = flex_type_enum::INTEGER;
1744  return *this;
1745 }
1746 
1747 template <typename T>
1748 inline FLEX_ALWAYS_INLINE_FLATTEN
1749 typename std::enable_if<has_direct_conversion_to_flexible_type<T>::value,
1750  flexible_type&>::type
1751 flexible_type::operator=(const T& other) {
1753 
1754  reset(desired_type);
1755 
1756  mutable_get<typename enum_to_type<desired_type>::type>() = other;
1757  return *this;
1758 }
1759 
1760 
1761 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator=(flex_undefined other) {
1763  return *this;
1764 }
1765 
1766 
1767 template <typename T>
1768 inline FLEX_ALWAYS_INLINE_FLATTEN
1769 typename std::enable_if<has_direct_conversion_to_flexible_type<
1770  typename std::remove_reference<T>::type>::value,
1771  flexible_type&>::type
1772 flexible_type::operator=(T&& other) {
1773  typedef typename std::remove_reference<T>::type BASE_T;
1775 
1776  reset(desired_type);
1777 
1778  mutable_get<typename enum_to_type<desired_type>::type>() = std::forward<T>(other);
1779  return *this;
1780 }
1781 
1782 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::reset(flex_type_enum target_type) {
1783  // delete old value
1784  decref(val, val.stored_type);
1785  clear_memory_internal();
1786 
1787  // switch types
1788  val.stored_type = target_type;
1789 
1790  // construct the new type
1791  switch(get_type()) {
1793  val.strval = new std::pair<atomic<size_t>, flex_string>;
1794  val.strval->first.value = 1;
1795  break;
1797  val.vecval = new std::pair<atomic<size_t>, flex_vec>;
1798  val.vecval->first.value = 1;
1799  break;
1801  val.ndvecval = new std::pair<atomic<size_t>, flex_nd_vec>;
1802  val.ndvecval->first.value = 1;
1803  break;
1804  case flex_type_enum::LIST:
1805  val.recval = new std::pair<atomic<size_t>, flex_list>;
1806  val.recval->first.value = 1;
1807  break;
1808  case flex_type_enum::DICT:
1809  val.dictval = new std::pair<atomic<size_t>, flex_dict>;
1810  val.dictval->first.value = 1;
1811  break;
1813  new (&val.dtval) flex_date_time(0,0); // placement new to create flex_date_time
1814  break;
1815  case flex_type_enum::IMAGE:
1816  val.imgval = new std::pair<atomic<size_t>, flex_image>;
1817  val.imgval->first.value = 1;
1818  break;
1819  default:
1820  break;
1821  }
1822 }
1823 
1824 
1825 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::reset() {
1826  decref(val, val.stored_type);
1827  clear_memory_internal();
1828  // switch types
1829  val.stored_type = flex_type_enum::INTEGER;
1830 }
1831 
1832 
1833 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::swap(flexible_type& b) {
1834  std::swap(val, b.val);
1835 }
1836 
1837 template <typename T>
1838 inline FLEX_ALWAYS_INLINE T& flexible_type::mutable_get() {
1839  __attribute__((unused))
1841  __builtin_unreachable();
1842 }
1843 
1844 template <typename T>
1845 inline FLEX_ALWAYS_INLINE const T& flexible_type::get() const {
1846  __attribute__((unused))
1848  __builtin_unreachable();
1849 }
1850 
1851 
1852 template <typename T>
1853 inline FLEX_ALWAYS_INLINE T& flexible_type::reinterpret_mutable_get() {
1854  __attribute__((unused))
1856  __builtin_unreachable();
1857 }
1858 
1859 template <typename T>
1860 inline FLEX_ALWAYS_INLINE const T& flexible_type::reinterpret_get() const {
1861  __attribute__((unused))
1863  __builtin_unreachable();
1864 }
1865 
1866 
1867 inline flex_type_enum FLEX_ALWAYS_INLINE flexible_type::get_type() const {
1868  return val.stored_type;
1869 }
1870 
1871 
1872 inline FLEX_ALWAYS_INLINE std::type_index flexible_type::type() const {
1874 }
1875 
1876 inline FLEX_ALWAYS_INLINE size_t flexible_type::which() const {
1877  return (size_t)(get_type());
1878 }
1879 
1880 inline FLEX_ALWAYS_INLINE size_t flexible_type::hash() const {
1882 }
1883 
1884 inline FLEX_ALWAYS_INLINE uint128_t flexible_type::hash128() const {
1886 }
1887 
1888 
1889 /**************************************************************************/
1890 /* */
1891 /* Visitor Functions */
1892 /* */
1893 /**************************************************************************/
1894 
1895 template <typename Visitor>
1896 inline FLEX_ALWAYS_INLINE_FLATTEN auto flexible_type::apply_mutating_visitor(Visitor visitor) -> decltype(visitor(prototype_flex_int)) {
1897  switch(get_type()) {
1899  return visitor(mutable_get<flex_int>());
1900  case flex_type_enum::FLOAT:
1901  return visitor(mutable_get<flex_float>());
1903  return visitor(mutable_get<flex_string>());
1905  return visitor(mutable_get<flex_vec>());
1907  return visitor(mutable_get<flex_nd_vec>());
1908  case flex_type_enum::LIST:
1909  return visitor(mutable_get<flex_list>());
1910  case flex_type_enum::DICT:
1911  return visitor(mutable_get<flex_dict>());
1913  return visitor(mutable_get<flex_date_time>());
1914  case flex_type_enum::IMAGE:
1915  return visitor(mutable_get<flex_image>());
1917  flex_undefined undef;
1918  return visitor(undef);
1919  default:
1920  FLEX_TYPE_ASSERT(false);
1921  }
1922  __builtin_unreachable();
1923 }
1924 
1925 
1926 /// \overload
1927 template <typename Visitor>
1928 inline FLEX_ALWAYS_INLINE_FLATTEN auto flexible_type::apply_visitor(Visitor visitor) const -> decltype(visitor(prototype_flex_int)) {
1929  switch(get_type()) {
1931  return visitor(get<flex_int>());
1932  case flex_type_enum::FLOAT:
1933  return visitor(get<flex_float>());
1935  return visitor(get<flex_string>());
1937  return visitor(get<flex_vec>());
1939  return visitor(get<flex_nd_vec>());
1940  case flex_type_enum::LIST:
1941  return visitor(get<flex_list>());
1942  case flex_type_enum::DICT:
1943  return visitor(get<flex_dict>());
1945  return visitor(get<flex_date_time>());
1946  case flex_type_enum::IMAGE:
1947  return visitor(get<flex_image>());
1949  flex_undefined undef;
1950  return visitor(undef);
1951  default:
1952  FLEX_TYPE_ASSERT(false);
1953  }
1954  __builtin_unreachable();
1955 }
1956 
1957 template <typename Visitor>
1958 inline FLEX_ALWAYS_INLINE_FLATTEN auto flexible_type::apply_mutating_visitor(Visitor visitor, const flexible_type& other) -> decltype(visitor(prototype_flex_int, flex_int())) {
1960  switch(other.get_type()) {
1961 
1963  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1964  flex_int>{visitor, other.get<flex_int>()});
1965  case flex_type_enum::FLOAT:
1966  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1967  flex_float>{visitor, other.get<flex_float>()});
1969  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1970  flex_string>{visitor, other.get<flex_string>()});
1972  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1973  flex_vec>{visitor, other.get<flex_vec>()});
1975  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1976  flex_nd_vec>{visitor, other.get<flex_nd_vec>()});
1977  case flex_type_enum::LIST:
1978  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1979  flex_list>{visitor, other.get<flex_list>()});
1980  case flex_type_enum::DICT:
1981  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1982  flex_dict>{visitor, other.get<flex_dict>()});
1984  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1985  flex_date_time>{visitor, other.get<flex_date_time>()});
1986  case flex_type_enum::IMAGE:
1987  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1988  flex_image>{visitor, other.get<flex_image>()});
1989 
1991  flex_undefined undef;
1992  return apply_mutating_visitor(const_visitor_wrapper<Visitor,
1993  flex_undefined>{visitor, undef});
1994  default:
1995  FLEX_TYPE_ASSERT(false);
1996  }
1997  __builtin_unreachable();
1998 }
1999 
2000 /// overload
2001 template <typename Visitor>
2002 inline FLEX_ALWAYS_INLINE_FLATTEN auto flexible_type::apply_visitor(Visitor visitor, const flexible_type& other) const -> decltype(visitor(prototype_flex_int, flex_int())) {
2004  switch(other.get_type()) {
2006  return apply_visitor(const_visitor_wrapper<Visitor,
2007  flex_int>{visitor, other.get<flex_int>()});
2008  case flex_type_enum::FLOAT:
2009  return apply_visitor(const_visitor_wrapper<Visitor,
2010  flex_float>{visitor, other.get<flex_float>()});
2012  return apply_visitor(const_visitor_wrapper<Visitor,
2013  flex_string>{visitor, other.get<flex_string>()});
2015  return apply_visitor(const_visitor_wrapper<Visitor,
2016  flex_vec>{visitor, other.get<flex_vec>()});
2018  return apply_visitor(const_visitor_wrapper<Visitor,
2019  flex_nd_vec>{visitor, other.get<flex_nd_vec>()});
2020  case flex_type_enum::LIST:
2021  return apply_visitor(const_visitor_wrapper<Visitor,
2022  flex_list>{visitor, other.get<flex_list>()});
2023  case flex_type_enum::DICT:
2024  return apply_visitor(const_visitor_wrapper<Visitor,
2025  flex_dict>{visitor, other.get<flex_dict>()});
2027  return apply_visitor(const_visitor_wrapper<Visitor,
2028  flex_date_time>{visitor, other.get<flex_date_time>()});
2029  case flex_type_enum::IMAGE:
2030  return apply_visitor(const_visitor_wrapper<Visitor,
2031  flex_image>{visitor, other.get<flex_image>()});
2033  flex_undefined undef;
2034  return apply_visitor(const_visitor_wrapper<Visitor,
2035  flex_undefined>{visitor, undef});
2036  default:
2037  FLEX_TYPE_ASSERT(false);
2038  }
2039  __builtin_unreachable();
2040 }
2041 /**************************************************************************/
2042 /* */
2043 /* Explicit type cast operator */
2044 /* */
2045 /**************************************************************************/
2046 template<typename T>
2047 inline FLEX_ALWAYS_INLINE_FLATTEN
2048 typename std::enable_if<std::is_integral<T>::value, T>::type
2049 flexible_type::to() const {
2050  return static_cast<T>(apply_visitor(flexible_type_impl::get_int_visitor()));
2051 }
2052 
2053 template<typename T>
2054 inline FLEX_ALWAYS_INLINE_FLATTEN
2055 typename std::enable_if<std::is_floating_point<T>::value, T>::type
2056 flexible_type::to() const {
2058 }
2059 
2060 template <>
2061 inline FLEX_ALWAYS_INLINE_FLATTEN flex_string flexible_type::to<flex_string>() const {
2063 }
2064 
2065 template <>
2066 inline FLEX_ALWAYS_INLINE_FLATTEN flex_vec flexible_type::to<flex_vec>() const {
2068 }
2069 
2070 template <>
2071 inline FLEX_ALWAYS_INLINE_FLATTEN flex_nd_vec flexible_type::to<flex_nd_vec>() const {
2073 }
2074 
2075 template <>
2076 inline FLEX_ALWAYS_INLINE_FLATTEN flex_list flexible_type::to<flex_list>() const {
2078 }
2079 
2080 template <>
2081 inline FLEX_ALWAYS_INLINE_FLATTEN flex_dict flexible_type::to<flex_dict>() const {
2083 }
2084 
2085 template <>
2086 inline FLEX_ALWAYS_INLINE_FLATTEN flex_date_time flexible_type::to<flex_date_time>() const {
2088 }
2089 
2090 template <>
2091 inline FLEX_ALWAYS_INLINE_FLATTEN flex_image flexible_type::to<flex_image>() const {
2093 }
2094 
2095 /**************************************************************************/
2096 /* */
2097 /* Convenience Operator Overloads */
2098 /* */
2099 /**************************************************************************/
2100 
2101 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_string() const {
2102  return to<flex_string>();
2103 }
2104 
2105 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_vec() const {
2106  return to<flex_vec>();
2107 }
2108 
2109 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_nd_vec() const {
2110  return to<flex_nd_vec>();
2111 }
2112 
2113 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_list() const {
2114  return to<flex_list>();
2115 }
2116 
2117 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_dict() const {
2118  return to<flex_dict>();
2119 }
2120 
2121 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_date_time() const {
2122  return to<flex_date_time>();
2123 }
2124 
2125 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type::operator flex_image() const {
2126  return to<flex_image>();
2127 }
2128 
2129 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator-() const {
2130  flexible_type copy(*this);
2132  return copy;
2133 }
2134 
2135 
2136 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator+=(const flexible_type& other) {
2138  return *this;
2139 }
2140 
2141 
2142 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator-=(const flexible_type& other) {
2144  return *this;
2145 }
2146 
2147 
2148 
2149 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator/=(const flexible_type& other) {
2151  return *this;
2152 }
2153 
2154 
2155 
2156 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator%=(const flexible_type& other) {
2158  return *this;
2159 }
2160 
2161 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator*=(const flexible_type& other) {
2163  return *this;
2164 }
2165 
2166 
2167 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator+(const flexible_type& other) const {
2168  flexible_type ret(*this);
2169  ret += other;
2170  return ret;
2171 }
2172 
2173 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator-(const flexible_type& other) const {
2174  flexible_type ret(*this);
2175  ret -= other;
2176  return ret;
2177 }
2178 
2179 
2180 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator*(const flexible_type& other) const {
2181  flexible_type ret(*this);
2182  ret *= other;
2183  return ret;
2184 }
2185 
2186 
2187 
2188 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator/(const flexible_type& other) const {
2189  flexible_type ret(*this);
2190  ret /= other;
2191  return ret;
2192 }
2193 
2194 
2195 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator%(const flexible_type& other) const {
2196  flexible_type ret(*this);
2197  ret %= other;
2198  return ret;
2199 }
2200 
2201 
2202 
2203 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator==(const flexible_type& other) const {
2204  return approx_equal(other);
2205 }
2206 
2207 
2208 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator!=(const flexible_type& other) const {
2209  return !approx_equal(other);
2210 }
2211 
2212 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::approx_equal(const flexible_type& other) const {
2214 }
2215 
2216 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::identical(const flexible_type& other) const {
2218 }
2219 
2220 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator<(const flexible_type& other) const {
2222 }
2223 
2224 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator>(const flexible_type& other) const {
2226 }
2227 
2228 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator<=(const flexible_type& other) const {
2229  return (*this) < other || this->approx_equal(other);
2230 }
2231 
2232 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator>=(const flexible_type& other) const {
2233  return (*this) > other || this->approx_equal(other);
2234 }
2235 
2236 /// Preincrement. Equivalent to (*this)+=1
2237 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator++() {
2239  return *this;
2240 }
2241 
2242 
2243 /// Preincrement. Equivalent to (*this)+=1, returning a copy of the previous value
2244 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator++(int) {
2245  flexible_type ret(*this);
2247  return ret;
2248 }
2249 
2250 
2251 
2252 /// Preincrement. Equivalent to (*this)-=1
2253 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator--() {
2255  return *this;
2256 }
2257 
2258 
2259 /// Preincrement. Equivalent to (*this)-=1, returning a copy of the previous value
2260 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator--(int) {
2261  flexible_type ret(*this);
2263  return ret;
2264 }
2265 
2266 
2267 // template versions of all the operators to compare against
2268 // other types
2269 //
2270 template <typename T>
2271 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator-(const T& other) const { return (*this) - (flexible_type)(other); }
2272 template <typename T>
2273 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator+(const T& other) const { return (*this) + (flexible_type)(other); }
2274 template <typename T>
2275 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator/(const T& other) const { return (*this) / (flexible_type)(other); }
2276 template <typename T>
2277 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator%(const T& other) const { return (*this) % (flexible_type)(other); }
2278 template <typename T>
2279 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type flexible_type::operator*(const T& other) const { return (*this) * (flexible_type)(other); }
2280 template <typename T>
2281 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator==(const T& other) const { return (*this) == (flexible_type)(other); }
2282 template <typename T>
2283 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator!=(const T& other) const { return (*this) != (flexible_type)(other); }
2284 template <typename T>
2285 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator<(const T& other) const { return (*this) < flexible_type(other); }
2286 template <typename T>
2287 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator>(const T& other) const { return (*this) > flexible_type(other); }
2288 template <typename T>
2289 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator<=(const T& other) const { return (*this) <= flexible_type(other); }
2290 template <typename T>
2291 inline FLEX_ALWAYS_INLINE_FLATTEN bool flexible_type::operator>=(const T& other) const { return (*this) >= flexible_type(other); }
2292 
2293 inline FLEX_ALWAYS_INLINE_FLATTEN flex_float& flexible_type::operator[](size_t index) {
2294  ensure_unique();
2295  switch(get_type()) {
2297  return val.vecval->second[index];
2299  return val.ndvecval->second[index];
2300  case flex_type_enum::FLOAT:
2301  if (index == 0) return val.dblval;
2302  default:
2303  FLEX_TYPE_ASSERT(false);
2304  }
2305  __builtin_unreachable();
2306 }
2307 
2308 inline FLEX_ALWAYS_INLINE_FLATTEN const flex_float& flexible_type::operator[](size_t index) const {
2309  switch(get_type()) {
2311  return val.vecval->second[index];
2313  return val.ndvecval->second[index];
2314  case flex_type_enum::FLOAT:
2315  if (index == 0) return val.dblval;
2316  default:
2317  FLEX_TYPE_ASSERT(false);
2318  }
2319  __builtin_unreachable();
2320 }
2321 
2322 
2323 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::array_at(size_t index) {
2324  ensure_unique();
2325  return val.recval->second[index];
2326 }
2327 
2328 
2329 inline FLEX_ALWAYS_INLINE_FLATTEN const flexible_type& flexible_type::array_at(size_t index) const {
2330  return val.recval->second[index];
2331 }
2332 
2333 
2334 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::dict_at(const flexible_type& s) {
2335  ensure_unique();
2336  flex_dict& value = val.dictval->second;
2337  for(auto& pair : value) {
2338  if (pair.first == s) {
2339  return pair.second;
2340  }
2341  }
2342 
2343  // not exist key
2344  log_and_throw("key does not exist in the dictionary");
2345  __builtin_unreachable();
2346 }
2347 
2348 
2349 inline FLEX_ALWAYS_INLINE_FLATTEN const flexible_type& flexible_type::dict_at(const flexible_type& s) const {
2350  const flex_dict& value = val.dictval->second;
2351  for(auto& pair : value) {
2352  if (pair.first == s) {
2353  return pair.second;
2354  }
2355  }
2356  FLEX_TYPE_ASSERT(false);
2357  __builtin_unreachable();
2358 }
2359 
2360 
2361 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator()(size_t index) {
2362  ensure_unique();
2363  switch(get_type()) {
2364  case flex_type_enum::LIST:
2365  return array_at(index);
2366  default:
2367  FLEX_TYPE_ASSERT(false);
2368  }
2369  __builtin_unreachable();
2370 }
2371 
2372 
2373 inline FLEX_ALWAYS_INLINE_FLATTEN const flexible_type& flexible_type::operator()(size_t index) const {
2374  switch(get_type()) {
2375  case flex_type_enum::LIST:
2376  return array_at(index);
2377  default:
2378  FLEX_TYPE_ASSERT(false);
2379  }
2380  __builtin_unreachable();
2381 }
2382 
2383 inline FLEX_ALWAYS_INLINE_FLATTEN flexible_type& flexible_type::operator()(const flexible_type& index) {
2384  ensure_unique();
2385  switch(get_type()) {
2386  case flex_type_enum::DICT:
2387  return dict_at(index);
2388  default:
2389  FLEX_TYPE_ASSERT(false);
2390  }
2391  __builtin_unreachable();
2392 }
2393 
2394 
2395 inline FLEX_ALWAYS_INLINE_FLATTEN const flexible_type& flexible_type::operator()(const flexible_type& index) const {
2396  switch(get_type()) {
2397  case flex_type_enum::DICT:
2398  return dict_at(index);
2399  default:
2400  FLEX_TYPE_ASSERT(false);
2401  }
2402  __builtin_unreachable();
2403 }
2404 
2405 
2406 inline FLEX_ALWAYS_INLINE_FLATTEN size_t flexible_type::size() const {
2407  switch(get_type()) {
2409  return val.vecval->second.size();
2411  return val.ndvecval->second.num_elem();
2412  case flex_type_enum::LIST:
2413  return val.recval->second.size();
2414  case flex_type_enum::DICT:
2415  return val.dictval->second.size();
2416  default:
2417  return 1;
2418  }
2419 }
2420 
2421 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::resize(size_t s) {
2422  ensure_unique();
2423  switch(get_type()) {
2425  val.vecval->second.resize(s);
2426  return;
2427  case flex_type_enum::LIST:
2428  val.recval->second.resize(s);
2429  return;
2430  default:
2431  FLEX_TYPE_ASSERT(false);
2432  }
2433 }
2434 
2435 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::clear() {
2436  switch(get_type()) {
2439  case flex_type_enum::LIST:
2440  case flex_type_enum::DICT:
2441  reset(get_type());
2442  return;
2443  default:
2444  FLEX_TYPE_ASSERT(false);
2445  }
2446 }
2447 
2448 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::push_back(flex_float i) {
2449  ensure_unique();
2450  switch(get_type()) {
2452  val.vecval->second.push_back(i);
2453  return;
2454  case flex_type_enum::LIST:
2455  val.recval->second.push_back(flexible_type(i));
2456  return;
2457  default:
2458  FLEX_TYPE_ASSERT(false);
2459  }
2460 }
2461 
2462 
2463 inline FLEX_ALWAYS_INLINE_FLATTEN void flexible_type::push_back(const flexible_type& i) {
2464  ensure_unique();
2465  switch(get_type()) {
2467  val.vecval->second.push_back((flex_float)i);
2468  return;
2469  case flex_type_enum::LIST:
2470  val.recval->second.push_back(i);
2471  return;
2472  default:
2473  FLEX_TYPE_ASSERT(false);
2474  }
2475 }
2476 
2477 
2478 
2479 inline FLEX_ALWAYS_INLINE void flexible_type::save(oarchive& oarc) const {
2480  // in earlier versions of the serializer, a 4 byte tag value was saved
2481  // together with the flexible_type. This has now been changed.
2482  // However, to continue correctly deserializing previously saved
2483  // flexible_types we identify it by shifting the type values by 128
2484  unsigned char c = (128 + (unsigned char)(get_type()));
2485  oarc << c;
2487 }
2488 
2489 inline FLEX_ALWAYS_INLINE void flexible_type::load(iarchive& iarc) {
2490  unsigned char c;
2491  // in earlier versions of the serializer, a 4 byte tag value was saved
2492  // together with the flexible_type. This has now been changed.
2493  // However, to continue correctly deserializing previously saved
2494  // flexible_types we identify it by shifting the type values by 128
2495  //
2496  // 12 Jan 2018: I suspect we can disable the old deserialization
2497  // code path now. "Earlier version" I think is at least 4 years old now.
2498  iarc >> c;
2499  if (c < 128) {
2500  int32_t tag_value;
2501  // old version of flexble_type saves the tag
2502  iarc >> tag_value;
2503  reset(flex_type_enum(c));
2504  } else {
2505  // new version does not
2506  reset(flex_type_enum(c - 128));
2507  }
2509 }
2510 
2511 
2512 /**************************************************************************/
2513 /* */
2514 /* External Operator Overloads */
2515 /* */
2516 /**************************************************************************/
2517 
2518 // Doxygen documentation is not generated for these functions
2519 
2520 #define EXT_ENABLE_IF(x) \
2521 typename std::enable_if<has_direct_conversion_to_flexible_type<T>::value && std::is_same<S, flexible_type>::value, x>::type
2522 
2523 
2524 /*
2525  * Prints the contents of the flexible type.
2526  * Equivalent to os << std::string(f);
2527  */
2528 template <typename T>
2529 inline FLEX_ALWAYS_INLINE
2530 typename std::enable_if<std::is_same<T, flexible_type>::value, std::ostream&>::type
2531  operator<<(std::ostream& os, const T& f) {
2532  os << (std::string)(f);
2533  return os;
2534 }
2535 
2536 /*
2537  * Reversed overload of the + operator,
2538  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2539  * The return type is that of the flexible_type on the right.
2540  * See \ref flexible_type::operator+
2541  */
2542 template <typename T, typename S>
2543 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(flexible_type) operator+(const T& other, const S& f) {
2544  return f + other;
2545 }
2546 
2547 /*
2548  * Reversed overload of the - operator,
2549  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2550  * The return type is that of the flexible_type on the right.
2551  * See \ref flexible_type::operator-
2552  */
2553 template <typename T, typename S>
2554 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(flexible_type) operator-(const T& other, const S& f) {
2555  return (-f) + flexible_type(other);
2556 }
2557 
2558 /*
2559  * Reversed overload of the * operator,
2560  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2561  * The return type is that of the flexible_type on the right.
2562  * See \ref flexible_type::operator*
2563  */
2564 template <typename T, typename S>
2565 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(flexible_type) operator*(const T& other, const S& f) {
2566  return f.operator*(other);
2567 }
2568 
2569 /*
2570  * Reversed overload of the / operator,
2571  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2572  * The return type is that of the flexible_type on the right.
2573  * See \ref flexible_type::operator/
2574  */
2575 template <typename T, typename S>
2576 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(flexible_type) operator/(const T& other, const S& f) {
2577  flexible_type ret(f.get_type());
2578  ret.soft_assign(flexible_type(other));
2579  ret /= f;
2580  return ret;
2581 }
2582 
2583 
2584 /*
2585  * Reversed overload of the / operator,
2586  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2587  * The return type is that of the flexible_type on the right.
2588  * See \ref flexible_type::operator/
2589  */
2590 template <typename T, typename S>
2591 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(flexible_type) operator%(const T& other, const S& f) {
2592  flexible_type ret(f.get_type());
2593  ret.soft_assign(flexible_type(other));
2594  ret %= f;
2595  return ret;
2596 }
2597 
2598 /*
2599  * Reversed overload of the == operator,
2600  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2601  * see \ref flexible_type::operator==
2602  */
2603 template <typename T, typename S>
2604 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(bool) operator==(const T& other, const S& f) {
2605  return f.operator==(flexible_type(other));
2606 }
2607 
2608 /*
2609  * Reversed overload of the < operator,
2610  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2611  * see \ref flexible_type::operator<
2612  */
2613 template <typename T, typename S>
2614 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(bool) operator<(const T& other, const S& f) { return (f > other); }
2615 
2616 /*
2617  * Reversed overload of the > operator,
2618  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2619  * see \ref flexible_type::operator>
2620  */
2621 template <typename T, typename S>
2622 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(bool) operator>(const T& other, const S& f) { return (f < other); }
2623 
2624 /*
2625  * Reversed overload of the <= operator,
2626  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2627  * see \ref flexible_type::operator<=
2628  */
2629 template <typename T, typename S>
2630 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(bool) operator<=(const T& other, const S& f) { return (f >= other); }
2631 /*
2632  * \ingroup unity
2633  * Reversed overload of the >= operator,
2634  * requiring flexible_type to be on the right side, and a non-flexible type on the left.
2635  * see \ref flexible_type::operator>=
2636  */
2637 template <typename T, typename S>
2638 inline FLEX_ALWAYS_INLINE_FLATTEN EXT_ENABLE_IF(bool) operator>=(const T& other, const S& f) { return (f <= other); }
2639 
2640 
2641 bool FLEX_ALWAYS_INLINE_FLATTEN flexible_type::is_na() const {
2642  auto the_type = get_type();
2643  return (the_type == flex_type_enum::UNDEFINED) ||
2644  (the_type == flex_type_enum::FLOAT && std::isnan(get<flex_float>()));
2645 }
2646 
2647 bool FLEX_ALWAYS_INLINE_FLATTEN flexible_type::is_zero() const {
2648  switch(get_type()) {
2650  return get<flex_int>() == 0;
2651  case flex_type_enum::FLOAT:
2652  return get<flex_float>() == 0.0;
2654  return get<flex_string>().empty();
2656  return get<flex_vec>().empty();
2657  case flex_type_enum::LIST:
2658  return get<flex_list>().empty();
2659  case flex_type_enum::DICT:
2660  return get<flex_dict>().empty();
2661  case flex_type_enum::IMAGE:
2662  return get<flex_image>().m_format == Format::UNDEFINED;
2664  return true;
2665  default:
2666  log_and_throw("Unexpected type!");
2667  };
2668  __builtin_unreachable();
2669 }
2670 
2671 
2672 } // namespace turi
2673 
2674 #undef EXT_ENABLE_IF
2675 #undef FLEX_ALWAYS_INLINE
2676 #undef FLEX_ALWAYS_INLINE_FLATTEN
2677 #endif
int32_t get_date_time_microsecond() const
std::vector< double > flex_vec
std::pair< flex_int, int32_t > get_date_time_as_timestamp_and_offset() const
flexible_type & operator=(const flexible_type &other) noexcept
The serialization input archive object which, provided with a reference to an istream, will read from the istream, providing deserialization capabilities.
Definition: iarchive.hpp:60
bool operator>=(const flexible_type &other) const
flexible_type & operator%=(const flexible_type &other)
void load(iarchive &iarc)
void resize(size_t s)
STL namespace.
bool approx_equal(const flexible_type &other) const
flexible_type & array_at(size_t index)
bool operator<=(const flexible_type &other) const
flex_float & operator[](size_t index)
auto apply_visitor(Visitor visitor) const -> decltype(visitor(prototype_flex_int))
flexible_type & soft_assign(const flexible_type &other)
flexible_type & operator/=(const flexible_type &other)
void erase(const flexible_type &index)
bool operator!=(const flexible_type &other) const
flexible_type_impl::ndarray< double > flex_nd_vec
std::enable_if<!std::is_integral< T >::value &&!std::is_floating_point< T >::value, T >::type to() const
const T & reinterpret_get() const
auto apply_mutating_visitor(Visitor visitor) -> decltype(visitor(prototype_flex_int))
void push_back(flex_float i)
flexible_type operator/(const flexible_type &other) const
const T & get() const
flexible_type & operator*=(const flexible_type &other)
flex_type_enum get_type() const
flexible_type operator%(const flexible_type &other) const
flexible_type & dict_at(const flexible_type &index)
bool operator<(const flexible_type &other) const
bool operator==(const flexible_type &other) const
flexible_type & operator+=(const flexible_type &other)
std::string flex_string
bool identical(const flexible_type &other) const
bool is_na() const
image_type flex_image
flexible_type & operator()(size_t index)
flexible_type operator+(const flexible_type &other) const
void copy(Iterator begin, Iterator end, SWriter &&writer)
Definition: algorithm.hpp:416
std::type_index type() const
flexible_type & operator--()
Preincrement. Equivalent to (*this)-=1.
flexible_type operator-() const
void save(oarchive &oarc) const
The serialization output archive object which, provided with a reference to an ostream, will write to the ostream, providing serialization capabilities.
Definition: oarchive.hpp:80
size_t which() const
uint128_t hash128() const
bool operator>(const flexible_type &other) const
bool contains_na() const
flexible_type operator*(const flexible_type &other) const
std::vector< std::pair< flexible_type, flexible_type > > flex_dict
flexible_type & operator-=(const flexible_type &other)
static flexible_type FLEX_UNDEFINED
flexible_type & set_date_time_from_timestamp_and_offset(const std::pair< flex_int, int32_t > &datetime, const int32_t microsecond=0)
std::vector< flexible_type > flex_list
bool is_zero() const
flexible_type & operator++()
Preincrement. Equivalent to (*this)+=1.
void swap(flexible_type &b)