TECA
teca_variant_array.h
1 #ifndef teca_variant_array_h
2 #define teca_variant_array_h
3 
4 #include <vector>
5 #include <string>
6 #include <sstream>
7 #include <exception>
8 #include <typeinfo>
9 #include <iterator>
10 #include <algorithm>
11 #include <type_traits>
12 #include <typeinfo>
13 #include <utility>
14 
15 #include "teca_common.h"
16 #include "teca_binary_stream.h"
17 #include "teca_variant_array_fwd.h"
18 #include "teca_bad_cast.h"
19 
20 // tag for ops on POD data
21 template <typename T>
22 struct pod_dispatch :
23  std::integral_constant<bool,
24  std::is_arithmetic<T>::value>
25 {};
26 
27 // tag for ops on classes
28 template <typename T>
30  std::integral_constant<bool,
31  !std::is_arithmetic<T>::value>
32 {};
33 
35 
38 class teca_variant_array : public std::enable_shared_from_this<teca_variant_array>
39 {
40 public:
41  // construct
42  teca_variant_array() noexcept = default;
43  virtual ~teca_variant_array() noexcept = default;
44 
45  // copy/move construct. can't copy/move construct from a base
46  // pointer. these require a downcast.
47  teca_variant_array(const teca_variant_array &other) = delete;
48  teca_variant_array(teca_variant_array &&other) = delete;
49 
50  // copy assign
51  teca_variant_array &operator=(const teca_variant_array &other)
52  { this->copy(other); return *this; }
53 
54  // move assign
55  teca_variant_array &operator=(teca_variant_array &&other)
56  { this->swap(other); return *this; }
57 
58  // virtual constructor. return a new'ly allocated
59  // empty object of the same type.
60  virtual p_teca_variant_array new_instance() const = 0;
61  virtual p_teca_variant_array new_instance(size_t n) const = 0;
62 
63  // virtual copy construct. return a new'ly allocated object,
64  // initialized copy from this. caller must delete.
65  virtual p_teca_variant_array new_copy() const = 0;
66  virtual p_teca_variant_array new_copy(size_t start, size_t end) const = 0;
67 
68  // return true if values are equal
69  bool operator==(const teca_variant_array &other) const
70  { return this->equal(other); }
71 
72  // return the name of the class in a human readable form
73  virtual std::string get_class_name() const = 0;
74 
75  // initialize contents with the native type initializer
76  virtual void initialize() = 0;
77 
78  // get methods. could throw std::bad_cast if the
79  // internal type is not castable to the return type.
80  template<typename T>
81  void get(unsigned long i, T &val) const
82  { this->get_dispatch<T>(i, val); }
83 
84  template<typename T>
85  void get(std::vector<T> &vals) const
86  { this->get_dispatch<T>(vals); }
87 
88  template<typename T>
89  void get(size_t start, size_t end, T *vals) const
90  { this->get_dispatch<T>(start, end, vals); }
91 
92  // set methods. could throw std::bad_cast if the
93  // passed in type is not castable to the internal type.
94  template<typename T>
95  void set(const std::vector<T> &vals)
96  { this->set_dispatch<T>(vals); }
97 
98  template<typename T>
99  void set(unsigned long i, const T &val)
100  { this->set_dispatch<T>(i, val); }
101 
102  template<typename T>
103  void set(size_t start, size_t end, const T *vals)
104  { this->set_dispatch<T>(start, end, vals); }
105 
106  // append methods. could throw std::bad_cast if the
107  // passed in type is not castable to the internal type.
108  template<typename T>
109  void append(const T &val)
110  { this->append_dispatch(val); }
111 
112  template<typename T>
113  void append(const std::vector<T> &vals)
114  { this->append_dispatch(vals); }
115 
116  // get the number of elements in the array
117  virtual unsigned long size() const noexcept = 0;
118 
119  // resize. allocates new storage and copies in existing values
120  virtual void resize(unsigned long i) = 0;
121 
122  // reserve. reserves the requested ammount of space with out
123  // constructing elements
124  virtual void reserve(unsigned long i) = 0;
125 
126  // free all the internal data
127  virtual void clear() noexcept = 0;
128 
129  // copy the contents from the other array.
130  // an excpetion is thrown when no conversion
131  // between the two types exists. This method
132  // is not virtual so that string can be handled
133  // as a special case in the base class.
134  void copy(const teca_variant_array &other);
135  void copy(const const_p_teca_variant_array &other)
136  { this->copy(*other.get()); }
137 
138  void append(const teca_variant_array &other);
139  void append(const const_p_teca_variant_array &other)
140  { this->append(*other.get()); }
141 
142  // swap the contents of this and the other object.
143  // an excpetion is thrown when no conversion
144  // between the two types exists.
145  virtual void swap(teca_variant_array &other) = 0;
146  void swap(const p_teca_variant_array &other)
147  { this->swap(*other.get()); }
148 
149  // compare the two objects for equality
150  virtual bool equal(const teca_variant_array &other) const = 0;
151  bool equal(const const_p_teca_variant_array &other) const
152  { return this->equal(*other.get()); }
153 
154  // serrialize to/from stream
155  virtual int to_stream(teca_binary_stream &s) const = 0;
156  virtual int from_stream(teca_binary_stream &s) = 0;
157 
158  virtual int to_stream(std::ostream &s) const = 0;
159  virtual int from_stream(std::ostream &s) = 0;
160 
161  // used for serialization
162  virtual unsigned int type_code() const noexcept = 0;
163 
164 private:
165  // dispatch methods, each set/get above has a pair
166  // one for POD and one for the rest. this allows us to
167  // seamlessly handle casting and conversion between POD
168  // types
169  template<typename T>
170  void append_dispatch(const std::vector<T> &vals,
171  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
172 
173  template<typename T>
174  void append_dispatch(const std::vector<T> &vals,
175  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
176 
177  template<typename T>
178  void append_dispatch(const T &val,
179  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
180 
181  template<typename T>
182  void append_dispatch(const T &val,
183  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
184  template<typename T>
185 
186  void set_dispatch(const std::vector<T> &vals,
187  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
188 
189  template<typename T>
190  void set_dispatch(const std::vector<T> &vals,
191  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
192 
193  template<typename T>
194  void set_dispatch(unsigned long i, const T &val,
195  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
196 
197  template<typename T>
198  void set_dispatch(unsigned long i, const T &val,
199  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
200 
201  template<typename T>
202  void set_dispatch(size_t start, size_t end, const T *vals,
203  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
204 
205  template<typename T>
206  void set_dispatch(size_t start, size_t end, const T *vals,
207  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
208 
209  template<typename T>
210  void get_dispatch(std::vector<T> &vals,
211  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
212 
213  template<typename T>
214  void get_dispatch(std::vector<T> &vals,
215  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
216 
217  template<typename T>
218  void get_dispatch(unsigned long i, T &val,
219  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
220 
221  template<typename T>
222  void get_dispatch(unsigned long i, T &val,
223  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
224 
225  template<typename T>
226  void get_dispatch(size_t start, size_t end, T *vals,
227  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
228 
229  template<typename T>
230  void get_dispatch(size_t start, size_t end, T *vals,
231  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
232 };
233 
234 
235 
236 // tag for contiguous arrays, and objects that have
237 // overrides in teca_binary_stream
238 template<typename T>
240  : std::integral_constant<bool,
241  std::is_arithmetic<T>::value ||
242  std::is_same<T, std::string>::value>
243 {};
244 
245 // tag for arrays of pointers of other objects
246 template<typename T>
248  : std::integral_constant<bool,
249  (std::is_pointer<T>::value ||
250  std::is_same<T, p_teca_variant_array>::value) &&
251  !pack_array<T>::value>
252 {};
253 
254 // tag for arrays of other objects
255 template<typename T>
257  : std::integral_constant<bool,
258  !pack_array<T>::value &&
259  !std::is_pointer<T>::value &&
260  !pack_object_ptr<T>::value>
261 {};
262 
263 
264 
265 // implementation of our type agnostic container
266 // for simple arrays
267 template<typename T>
269 {
270 public:
271  // construct
272  TECA_VARIANT_ARRAY_STATIC_NEW(teca_variant_array_impl, T)
273 
274  // destruct
275  virtual ~teca_variant_array_impl() noexcept;
276 
277  // virtual constructor
278  p_teca_variant_array new_copy() const override;
279  p_teca_variant_array new_copy(size_t start, size_t end) const override;
280  p_teca_variant_array new_instance() const override;
281  p_teca_variant_array new_instance(size_t n) const override;
282 
283  // return the name of the class in a human readable form
284  std::string get_class_name() const override;
285 
286  // intialize with T()
287  void initialize() override;
288 
289  // copy
291  operator=(const teca_variant_array_impl<T> &other);
292 
293  template<typename U>
295  operator=(const teca_variant_array_impl<U> &other);
296 
297  // move
299 
301  operator=(teca_variant_array_impl<T> &&other);
302 
303  // get the ith value
304  T &get(unsigned long i)
305  { return m_data[i]; }
306 
307  const T &get(unsigned long i) const
308  { return m_data[i]; }
309 
310  // get the ith value
311  template<typename U>
312  void get(unsigned long i, U &val) const;
313 
314  // get a range of values decribed by [start end]
315  // inclusive
316  template<typename U>
317  void get(size_t start, size_t end, U *vals) const;
318 
319  // copy the data out into the passed in vector
320  template<typename U>
321  void get(std::vector<U> &val) const;
322 
323  // pointer to the data
324  T *get(){ return &m_data[0]; }
325  const T *get() const { return &m_data[0]; }
326 
327  // set the ith value
328  template<typename U>
329  void set(unsigned long i, const U &val);
330 
331  // set a range opf values described by [start end]
332  // inclusive
333  template<typename U>
334  void set(size_t start, size_t end, const U *vals);
335 
336  // copy data, replacing contents with the passed in
337  // vector
338  template<typename U>
339  void set(const std::vector<U> &val);
340 
341  // insert from the passed in vector at the back
342  template<typename U>
343  void append(const std::vector<U> &val);
344 
345  // insert a single value at the back
346  template<typename U>
347  void append(const U &val);
348 
349  // get the current size of the data
350  virtual unsigned long size() const noexcept override;
351 
352  // resize the data
353  virtual void resize(unsigned long n) override;
354  void resize(unsigned long n, const T &val);
355 
356  // reserve space
357  virtual void reserve(unsigned long n) override;
358 
359  // clear the data
360  virtual void clear() noexcept override;
361 
362  // copy. This method is not virtual so that
363  // string can be handled as a special case in
364  // the base class.
365  void copy(const teca_variant_array &other);
366 
367  // append. This method is not virtual so that
368  // string can be handled as a special case in
369  // the base class.
370  void append(const teca_variant_array &other);
371 
372  // virtual swap
373  void swap(teca_variant_array &other) override;
374 
375  // virtual equavalince test
376  bool equal(const teca_variant_array &other) const override;
377 
378  // serialize to/from stream
379  int to_stream(teca_binary_stream &s) const override
380  {
381  this->to_binary<T>(s);
382  return 0;
383  }
384 
385  int from_stream(teca_binary_stream &s) override
386  {
387  this->from_binary<T>(s);
388  return 0;
389  }
390 
391  int to_stream(std::ostream &s) const override
392  {
393  this->to_ascii<T>(s);
394  return 0;
395  }
396 
397  int from_stream(std::ostream &s) override
398  {
399  this->from_ascii<T>(s);
400  return 0;
401  }
402 
403 protected:
404  // construct
405  teca_variant_array_impl() noexcept {}
406 
407  // construct with preallocated size
408  teca_variant_array_impl(unsigned long n)
409  : m_data(n) {}
410 
411  // construct with preallocated size and initialized
412  // to a specific value
413  teca_variant_array_impl(unsigned long n, const T &v)
414  : m_data(n, v) {}
415 
416  // construct from a c-array of length n
417  teca_variant_array_impl(const T *vals, unsigned long n)
418  : teca_variant_array(), m_data(vals, vals+n) {}
419 
420  // copy construct from an instance of different type
421  template<typename U>
423  : teca_variant_array(), m_data(other.m_data) {}
424 
425  // copy construct from an instance of same type
427  : teca_variant_array(), m_data(other.m_data) {}
428 
429 private:
430  // tag dispatch c style array, and types that have overrides in
431  // binary stream
432  template <typename U = T>
433  void to_binary(teca_binary_stream &s,
434  typename std::enable_if<pack_array<U>::value, U>::type* = 0)
435  const;
436 
437  template <typename U = T>
438  void from_binary(teca_binary_stream &s,
439  typename std::enable_if<pack_array<U>::value, U>::type* = 0);
440 
441  // tag dispatch array of other objects
442  template <typename U = T>
443  void to_binary(teca_binary_stream &s,
444  typename std::enable_if<pack_object<U>::value, U>::type* = 0)
445  const;
446 
447  template <typename U = T>
448  void from_binary(teca_binary_stream &s,
449  typename std::enable_if<pack_object<U>::value, U>::type* = 0);
450 
451  // tag dispatch array of poniter to other objects
452  template <typename U = T>
453  void to_binary(teca_binary_stream &s,
454  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0)
455  const;
456 
457  template <typename U = T>
458  void from_binary(teca_binary_stream &s,
459  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0);
460 
461  // ostream
462  template <typename U = T>
463  void to_ascii(std::ostream &s,
464  typename std::enable_if<pack_array<U>::value, U>::type* = 0)
465  const;
466 
467  template <typename U = T>
468  void from_ascii(std::ostream &s,
469  typename std::enable_if<pack_array<U>::value, U>::type* = 0);
470 
471  // tag dispatch array of other objects
472  template <typename U = T>
473  void to_ascii(std::ostream &s,
474  typename std::enable_if<pack_object<U>::value, U>::type* = 0)
475  const;
476 
477  template <typename U = T>
478  void from_ascii(std::ostream &s,
479  typename std::enable_if<pack_object<U>::value, U>::type* = 0);
480 
481  // tag dispatch array of pointer to other objects
482  template <typename U = T>
483  void to_ascii(std::ostream &s,
484  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0)
485  const;
486 
487  template <typename U = T>
488  void from_ascii(std::ostream &s,
489  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0);
490 
491  // for serializaztion
492  unsigned int type_code() const noexcept override;
493 private:
494  std::vector<T> m_data;
495 
496  friend class teca_variant_array;
497  template<typename U> friend class teca_variant_array_impl;
498 };
499 
500 
501 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
502 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
503 
504 // tt - derived container
505 // nt - contained type
506 // tt<nt> - complete derived type
507 // p - base class pointer
508 // body - code to execute
509 #define TEMPLATE_DISPATCH_CASE(tt, nt, p, body) \
510  if (dynamic_cast<tt<nt>*>(p)) \
511  { \
512  using TT = tt<nt>; \
513  using NT = nt; \
514  body \
515  }
516 
517 // tt - derived container
518 // nt - contained type
519 // tt<nt> - complete derived type
520 // p - base class pointer
521 // i - id suffix
522 // body - code to execute
523 #define NESTED_TEMPLATE_DISPATCH_CASE(tt, nt, p, i, body) \
524  if (dynamic_cast<tt<nt>*>(p)) \
525  { \
526  using TT##i = tt<nt>; \
527  using NT##i = nt; \
528  body \
529  }
530 
531 // variant that limits dispatch to floating point types
532 // for use in numerical compuatation where integer types
533 // are not supported (ie, math operations from std library)
534 #define TEMPLATE_DISPATCH_FP(t, p, body) \
535  TEMPLATE_DISPATCH_CASE(t, float, p, body) \
536  else TEMPLATE_DISPATCH_CASE(t, double, p, body)
537 
538 // variant that limits dispatch to signed integer types
539 // for use in numerical compuatation where signed integer types
540 // are not supported
541 #define TEMPLATE_DISPATCH_SI(t, p, body) \
542  TEMPLATE_DISPATCH_CASE(t, long long, p, body) \
543  else TEMPLATE_DISPATCH_CASE(t, long, p, body) \
544  else TEMPLATE_DISPATCH_CASE(t, int, p, body) \
545  else TEMPLATE_DISPATCH_CASE(t, short int, p, body) \
546  else TEMPLATE_DISPATCH_CASE(t, char, p, body)
547 
548 // variant that limits dispatch to floating point types
549 // for use in numerical compuatation where integer types
550 // are not supported (ie, math operations from std library)
551 #define TEMPLATE_DISPATCH_FP_SI(t, p, body) \
552  TEMPLATE_DISPATCH_CASE(t, float, p, body) \
553  else TEMPLATE_DISPATCH_CASE(t, double, p, body) \
554  else TEMPLATE_DISPATCH_SI(t, p, body)
555 
556 // variant that limits dispatch to integer types
557 // for use in numerical compuatation where floating point types
558 // are not supported
559 #define TEMPLATE_DISPATCH_I(t, p, body) \
560  TEMPLATE_DISPATCH_CASE(t, long long, p, body) \
561  else TEMPLATE_DISPATCH_CASE(t, unsigned long long, p, body) \
562  else TEMPLATE_DISPATCH_CASE(t, long, p, body) \
563  else TEMPLATE_DISPATCH_CASE(t, int, p, body) \
564  else TEMPLATE_DISPATCH_CASE(t, unsigned int, p, body) \
565  else TEMPLATE_DISPATCH_CASE(t, unsigned long, p, body) \
566  else TEMPLATE_DISPATCH_CASE(t, short int, p, body) \
567  else TEMPLATE_DISPATCH_CASE(t, short unsigned int, p, body) \
568  else TEMPLATE_DISPATCH_CASE(t, char, p, body) \
569  else TEMPLATE_DISPATCH_CASE(t, unsigned char, p, body)
570 
571 // macro for helping downcast to POD types
572 // don't add classes to this.
573 // t - derived container type
574 // p - pointer to base class
575 // body - code to execute on match
576 #define TEMPLATE_DISPATCH(t, p, body) \
577  TEMPLATE_DISPATCH_FP(t, p, body) \
578  else TEMPLATE_DISPATCH_I(t, p, body)
579 
580 // variant that limits dispatch to floating point types
581 // for use in numerical compuatation where integer types
582 // are not supported (ie, math operations from std library)
583 #define NESTED_TEMPLATE_DISPATCH_FP(t, p, i, body) \
584  NESTED_TEMPLATE_DISPATCH_CASE(t, float, p, i, body) \
585  else NESTED_TEMPLATE_DISPATCH_CASE(t, double, p, i, body)
586 
587 // variant that limits dispatch to integer types
588 // for use in numerical compuatation where integer types
589 // are not supported (ie, math operations from std library)
590 #define NESTED_TEMPLATE_DISPATCH_I(t, p, i, body) \
591  NESTED_TEMPLATE_DISPATCH_CASE(t, long long, p, i, body) \
592  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned long long, p, i, body) \
593  else NESTED_TEMPLATE_DISPATCH_CASE(t, long, p, i, body) \
594  else NESTED_TEMPLATE_DISPATCH_CASE(t, int, p, i, body) \
595  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned int, p, i, body) \
596  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned long, p, i, body) \
597  else NESTED_TEMPLATE_DISPATCH_CASE(t, short int, p, i, body) \
598  else NESTED_TEMPLATE_DISPATCH_CASE(t, short unsigned int, p, i, body) \
599  else NESTED_TEMPLATE_DISPATCH_CASE(t, char, p, i, body) \
600  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned char, p, i, body)
601 
602 // macro for helping downcast to POD types
603 // don't add classes to this.
604 // t - templated derived type
605 // p - base class pointer
606 // i - id for nesting
607 // body - code to execute on match
608 #define NESTED_TEMPLATE_DISPATCH(t, p, i, body) \
609  NESTED_TEMPLATE_DISPATCH_FP(t, p, i, body) \
610  else NESTED_TEMPLATE_DISPATCH_I(t, p, i, body)
611 
612 
613 // --------------------------------------------------------------------------
614 template<typename T>
615 void teca_variant_array::get_dispatch(std::vector<T> &vals,
616  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
617 {
618  TEMPLATE_DISPATCH(const teca_variant_array_impl, this,
619  TT *this_t = static_cast<TT*>(this);
620  this_t->get(vals);
621  return;
622  )
623  throw std::bad_cast();
624 }
625 
626 // --------------------------------------------------------------------------
627 template<typename T>
628 void teca_variant_array::get_dispatch(std::vector<T> &vals,
629  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
630 {
631  TEMPLATE_DISPATCH_CASE(const teca_variant_array_impl, T, this,
632  TT *this_t = static_cast<TT*>(this);
633  this_t->get(vals);
634  return;
635  )
636  throw std::bad_cast();
637 }
638 
639 // --------------------------------------------------------------------------
640 template<typename T>
641 void teca_variant_array::get_dispatch(unsigned long i, T &val,
642  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
643 {
644  TEMPLATE_DISPATCH(const teca_variant_array_impl, this,
645  TT *this_t = static_cast<TT*>(this);
646  this_t->get(i, val);
647  return;
648  )
649  throw std::bad_cast();
650 }
651 
652 // --------------------------------------------------------------------------
653 template<typename T>
654 void teca_variant_array::get_dispatch(unsigned long i, T &val,
655  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
656 {
657  TEMPLATE_DISPATCH_CASE(const teca_variant_array_impl, T, this,
658  TT *this_t = static_cast<TT*>(this);
659  this_t->get(i, val);
660  return;
661  )
662  throw std::bad_cast();
663 }
664 
665 // --------------------------------------------------------------------------
666 template<typename T>
667 void teca_variant_array::get_dispatch(size_t start, size_t end, T *vals,
668  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
669 {
670  TEMPLATE_DISPATCH(const teca_variant_array_impl, this,
671  TT *this_t = static_cast<TT*>(this);
672  this_t->get(start, end, vals);
673  return;
674  )
675  throw std::bad_cast();
676 }
677 
678 // --------------------------------------------------------------------------
679 template<typename T>
680 void teca_variant_array::get_dispatch(size_t start, size_t end, T *vals,
681  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
682 {
683  TEMPLATE_DISPATCH_CASE(const teca_variant_array_impl, T, this,
684  TT *this_t = static_cast<TT*>(this);
685  this_t->get(start, end, vals);
686  return;
687  )
688  throw std::bad_cast();
689 }
690 
691 // --------------------------------------------------------------------------
692 template<typename T>
693 void teca_variant_array::set_dispatch(const std::vector<T> &vals,
694  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
695 {
696  TEMPLATE_DISPATCH(teca_variant_array_impl, this,
697  TT *this_t = static_cast<TT*>(this);
698  this_t->set(vals);
699  return;
700  )
701  throw std::bad_cast();
702 }
703 
704 // --------------------------------------------------------------------------
705 template<typename T>
706 void teca_variant_array::set_dispatch(const std::vector<T> &vals,
707  typename std::enable_if<object_dispatch<T>::value, T>::type*)
708 {
709  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, T, this,
710  TT *this_t = static_cast<TT*>(this);
711  this_t->set(vals);
712  return;
713  )
714  throw std::bad_cast();
715 }
716 
717 // --------------------------------------------------------------------------
718 template<typename T>
719 void teca_variant_array::set_dispatch(unsigned long i, const T &val,
720  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
721 {
722  TEMPLATE_DISPATCH(teca_variant_array_impl, this,
723  TT *this_t = static_cast<TT*>(this);
724  this_t->set(i, val);
725  return;
726  )
727  throw std::bad_cast();
728 }
729 
730 // --------------------------------------------------------------------------
731 template<typename T>
732 void teca_variant_array::set_dispatch(unsigned long i, const T &val,
733  typename std::enable_if<object_dispatch<T>::value, T>::type*)
734 {
735  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, T, this,
736  TT *this_t = static_cast<TT*>(this);
737  this_t->set(i, val);
738  return;
739  )
740  throw std::bad_cast();
741 }
742 
743 // --------------------------------------------------------------------------
744 template<typename T>
745 void teca_variant_array::set_dispatch(size_t start, size_t end, const T *vals,
746  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
747 {
748  TEMPLATE_DISPATCH(teca_variant_array_impl, this,
749  TT *this_t = static_cast<TT*>(this);
750  this_t->set(start, end, vals);
751  return;
752  )
753  throw std::bad_cast();
754 }
755 
756 // --------------------------------------------------------------------------
757 template<typename T>
758 void teca_variant_array::set_dispatch(size_t start, size_t end, const T *vals,
759  typename std::enable_if<object_dispatch<T>::value, T>::type*)
760 {
761  TEMPLATE_DISPATCH_CASE(const teca_variant_array_impl, T, this,
762  TT *this_t = static_cast<TT*>(this);
763  this_t->set(start, end, vals);
764  return;
765  )
766  throw std::bad_cast();
767 }
768 
769 // --------------------------------------------------------------------------
770 template<typename T>
771 void teca_variant_array::append_dispatch(const std::vector<T> &vals,
772  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
773 {
774  TEMPLATE_DISPATCH(teca_variant_array_impl, this,
775  TT *this_t = static_cast<TT*>(this);
776  this_t->append(vals);
777  return;
778  )
779  throw std::bad_cast();
780 }
781 
782 // --------------------------------------------------------------------------
783 template<typename T>
784 void teca_variant_array::append_dispatch(const std::vector<T> &vals,
785  typename std::enable_if<object_dispatch<T>::value, T>::type*)
786 {
787  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, T, this,
788  TT *this_t = static_cast<TT*>(this);
789  this_t->append(vals);
790  return;
791  )
792  throw std::bad_cast();
793 }
794 
795 // --------------------------------------------------------------------------
796 template<typename T>
797 void teca_variant_array::append_dispatch(const T &val,
798  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
799 {
800  TEMPLATE_DISPATCH(teca_variant_array_impl, this,
801  TT *this_t = static_cast<TT*>(this);
802  this_t->append(val);
803  return;
804  )
805  throw std::bad_cast();
806 }
807 
808 // --------------------------------------------------------------------------
809 template<typename T>
810 void teca_variant_array::append_dispatch(const T &val,
811  typename std::enable_if<object_dispatch<T>::value, T>::type*)
812 {
813  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, T, this,
814  TT *this_t = static_cast<TT*>(this);
815  this_t->append(val);
816  return;
817  )
818  throw std::bad_cast();
819 }
820 
821 
822 
823 
824 
825 // --------------------------------------------------------------------------
826 template<typename T>
828 {
829  this->clear();
830 }
831 
832 // --------------------------------------------------------------------------
833 template<typename T>
834 p_teca_variant_array teca_variant_array_impl<T>::new_copy() const
835 {
836  return p_teca_variant_array(new teca_variant_array_impl<T>(*this));
837 }
838 
839 // --------------------------------------------------------------------------
840 template<typename T>
841 p_teca_variant_array teca_variant_array_impl<T>::new_copy(
842  size_t start, size_t end) const
843 {
844  p_teca_variant_array_impl<T> c = teca_variant_array_impl<T>::New(end-start+1);
845  this->get(start, end, c->get());
846  return c;
847 }
848 
849 // --------------------------------------------------------------------------
850 template<typename T>
851 p_teca_variant_array teca_variant_array_impl<T>::new_instance() const
852 {
853  return p_teca_variant_array(new teca_variant_array_impl<T>());
854 }
855 
856 // --------------------------------------------------------------------------
857 template<typename T>
858 p_teca_variant_array teca_variant_array_impl<T>::new_instance(size_t n) const
859 {
860  return p_teca_variant_array(new teca_variant_array_impl<T>(n));
861 }
862 
863 // --------------------------------------------------------------------------
864 template<typename T>
867 {
868  m_data.assign(other.m_data.begin(), other.m_data.end());
869  return *this;
870 }
871 
872 // copy assignment from different type
873 // --------------------------------------------------------------------------
874 template<typename T>
875 template<typename U>
878 {
879  m_data.assign(other.m_data.begin(), other.m_data.end());
880  return *this;
881 }
882 
883 // --------------------------------------------------------------------------
884 template<typename T>
887  : m_data(std::move(other.m_data))
888 {}
889 
890 // --------------------------------------------------------------------------
891 template<typename T>
894 {
895  m_data = std::move(other.m_data);
896  return *this;
897 }
898 
899 // --------------------------------------------------------------------------
900 template<typename T>
902 {
903  const char *element_name = typeid(T).name();
904  size_t element_size = sizeof(T);
905  std::ostringstream oss;
906  oss << "teca_variant_array_impl<" << element_name
907  << element_size << ">";
908  return oss.str();
909 }
910 
911 // --------------------------------------------------------------------------
912 template<typename T>
914 {
915  m_data.assign(m_data.size(), T());
916 }
917 
918 // --------------------------------------------------------------------------
919 template<typename T>
920 template<typename U>
921 void teca_variant_array_impl<T>::get(unsigned long i, U &val) const
922 {
923  val = m_data[i];
924 }
925 
926 // --------------------------------------------------------------------------
927 template<typename T>
928 template<typename U>
929 void teca_variant_array_impl<T>::get(size_t start, size_t end, U *vals) const
930 {
931  for (size_t i = start, ii = 0; i <= end; ++i, ++ii)
932  vals[ii] = m_data[i];
933 }
934 
935 // --------------------------------------------------------------------------
936 template<typename T>
937 template<typename U>
938 void teca_variant_array_impl<T>::get(std::vector<U> &val) const
939 {
940  val.assign(m_data.begin(), m_data.end());
941 }
942 
943 // --------------------------------------------------------------------------
944 template<typename T>
945 template<typename U>
946 void teca_variant_array_impl<T>::set(unsigned long i, const U &val)
947 {
948  m_data[i] = val;
949 }
950 
951 // --------------------------------------------------------------------------
952 template<typename T>
953 template<typename U>
954 void teca_variant_array_impl<T>::set(size_t start, size_t end, const U *vals)
955 {
956  for (size_t i = start, ii = 0; i <= end; ++i, ++ii)
957  m_data[i] = vals[ii];
958 }
959 
960 // --------------------------------------------------------------------------
961 template<typename T>
962 template<typename U>
963 void teca_variant_array_impl<T>::set(const std::vector<U> &val)
964 {
965  size_t n = val.size();
966  m_data.resize(n);
967  for (size_t i = 0; i < n; ++i)
968  m_data[i] = static_cast<T>(val[i]);
969 }
970 
971 // --------------------------------------------------------------------------
972 template<typename T>
973 template<typename U>
974 void teca_variant_array_impl<T>::append(const std::vector<U> &val)
975 {
976  std::copy(val.begin(), val.end(), std::back_inserter(m_data));
977 }
978 
979 // --------------------------------------------------------------------------
980 template<typename T>
981 template<typename U>
982 void teca_variant_array_impl<T>::append(const U &val)
983 {
984  m_data.push_back(val);
985 }
986 
987 // --------------------------------------------------------------------------
988 template<typename T>
989 unsigned long teca_variant_array_impl<T>::size() const noexcept
990 { return m_data.size(); }
991 
992 // --------------------------------------------------------------------------
993 template<typename T>
994 void teca_variant_array_impl<T>::resize(unsigned long n)
995 {
996  m_data.resize(n);
997 }
998 
999 // --------------------------------------------------------------------------
1000 template<typename T>
1001 void teca_variant_array_impl<T>::resize(unsigned long n, const T &val)
1002 {
1003  m_data.resize(n, val);
1004 }
1005 
1006 // --------------------------------------------------------------------------
1007 template<typename T>
1008 void teca_variant_array_impl<T>::reserve(unsigned long n)
1009 {
1010  m_data.reserve(n);
1011 }
1012 
1013 // --------------------------------------------------------------------------
1014 template<typename T>
1015 void teca_variant_array_impl<T>::clear() noexcept
1016 {
1017  m_data.clear();
1018 }
1019 
1020 // --------------------------------------------------------------------------
1021 template<typename T>
1023 {
1024  TEMPLATE_DISPATCH(const teca_variant_array_impl, &other,
1025  TT *other_t = static_cast<TT*>(&other);
1026  *this = *other_t;
1027  return;
1028  )
1029  throw teca_bad_cast(safe_class_name(&other), safe_class_name(this));
1030 }
1031 
1032 // --------------------------------------------------------------------------
1033 template<typename T>
1035 {
1036  TEMPLATE_DISPATCH(const teca_variant_array_impl, &other,
1037  TT *other_t = static_cast<TT*>(&other);
1038  std::copy(
1039  other_t->m_data.begin(),
1040  other_t->m_data.end(),
1041  std::back_inserter(this->m_data));
1042  return;
1043  )
1044  throw teca_bad_cast(safe_class_name(&other), safe_class_name(this));
1045 }
1046 
1047 // --------------------------------------------------------------------------
1048 template<typename T>
1050 {
1051  using TT = teca_variant_array_impl<T>;
1052  TT *other_t = dynamic_cast<TT*>(&other);
1053  if (other_t)
1054  {
1055  this->m_data.swap(other_t->m_data);
1056  return;
1057  }
1058  throw teca_bad_cast(safe_class_name(&other), safe_class_name(this));
1059 }
1060 
1061 // --------------------------------------------------------------------------
1062 template<typename T>
1064 {
1065  using TT = teca_variant_array_impl<T>;
1066  const TT *other_t = dynamic_cast<const TT*>(&other);
1067  if (other_t)
1068  {
1069  return this->m_data == other_t->m_data;
1070  }
1071  throw teca_bad_cast(safe_class_name(&other), safe_class_name(this));
1072  return false;
1073 }
1074 
1075 // --------------------------------------------------------------------------
1076 template<typename T>
1077  template <typename U>
1079  teca_binary_stream &s,
1080  typename std::enable_if<pack_array<U>::value, U>::type*) const
1081 {
1082  s.pack(this->m_data);
1083 }
1084 
1085 // --------------------------------------------------------------------------
1086 template<typename T>
1087  template <typename U>
1089  teca_binary_stream &s,
1090  typename std::enable_if<pack_array<U>::value, U>::type*)
1091 {
1092  s.unpack(this->m_data);
1093 }
1094 
1095 // --------------------------------------------------------------------------
1096 template<typename T>
1097  template <typename U>
1099  teca_binary_stream &s,
1100  typename std::enable_if<pack_object<U>::value, U>::type*) const
1101 {
1102  unsigned long long n = this->size();
1103  s.pack(n);
1104  for (unsigned long long i=0; i<n; ++i)
1105  this->m_data[i].to_stream(s);
1106 }
1107 
1108 // --------------------------------------------------------------------------
1109 template<typename T>
1110  template <typename U>
1112  teca_binary_stream &s,
1113  typename std::enable_if<pack_object<U>::value, U>::type*)
1114 {
1115  unsigned long long n;
1116  s.unpack(n);
1117  this->resize(n);
1118  for (unsigned long long i=0; i<n; ++i)
1119  this->m_data[i].from_stream(s);
1120 }
1121 
1122 // --------------------------------------------------------------------------
1123 template<typename T>
1124  template <typename U>
1126  teca_binary_stream &s,
1127  typename std::enable_if<pack_object_ptr<U>::value, U>::type*) const
1128 {
1129  unsigned long long n = this->size();
1130  s.pack(n);
1131  for (unsigned long long i=0; i<n; ++i)
1132  this->m_data[i]->to_stream(s);
1133 }
1134 
1135 // --------------------------------------------------------------------------
1136 template<typename T>
1137  template <typename U>
1139  teca_binary_stream &s,
1140  typename std::enable_if<pack_object_ptr<U>::value, U>::type*)
1141 {
1142  unsigned long long n;
1143  s.unpack(n);
1144  this->resize(n);
1145  for (unsigned long long i=0; i<n; ++i)
1146  this->m_data[i]->from_stream(s);
1147 }
1148 
1149 #define STR_DELIM(_a, _b) \
1150  (std::is_same<T, std::string>::value ? _a : _b)
1151 
1152 // --------------------------------------------------------------------------
1153 template<typename T>
1154  template <typename U>
1156  std::ostream &s,
1157  typename std::enable_if<pack_array<U>::value, U>::type*) const
1158 {
1159  size_t n = this->m_data.size();
1160  if (n)
1161  {
1162  s << STR_DELIM("\"", "")
1163  << this->m_data[0] << STR_DELIM("\"", "");
1164  for (size_t i = 1; i < n; ++i)
1165  {
1166  s << STR_DELIM(", \"", ", ")
1167  << this->m_data[i] << STR_DELIM("\"", "");
1168  }
1169  }
1170 }
1171 
1172 // --------------------------------------------------------------------------
1173 template<typename T>
1174  template <typename U>
1176  std::ostream &,
1177  typename std::enable_if<pack_array<U>::value, U>::type*)
1178 {
1179  // TODO
1180 }
1181 
1182 // --------------------------------------------------------------------------
1183 template<typename T>
1184  template <typename U>
1186  std::ostream &s,
1187  typename std::enable_if<pack_object<U>::value, U>::type*) const
1188 {
1189  size_t n = this->m_data.size();
1190  if (n)
1191  {
1192  s << "{";
1193  this->m_data[0].to_stream(s);
1194  s << "}";
1195  for (size_t i = 1; i < n; ++i)
1196  {
1197  s << ", {";
1198  this->m_data[i].to_stream(s);
1199  s << "}";
1200  }
1201  }
1202 }
1203 
1204 // --------------------------------------------------------------------------
1205 template<typename T>
1206  template <typename U>
1208  std::ostream &,
1209  typename std::enable_if<pack_object<U>::value, U>::type*)
1210 {
1211  // TODO
1212 }
1213 
1214 // --------------------------------------------------------------------------
1215 template<typename T>
1216  template <typename U>
1218  std::ostream &s,
1219  typename std::enable_if<pack_object_ptr<U>::value, U>::type*) const
1220 {
1221  size_t n = this->m_data.size();
1222  if (n)
1223  {
1224  s << "{";
1225  this->m_data[0]->to_stream(s);
1226  s << "}";
1227  for (size_t i = 1; i < n; ++i)
1228  {
1229  s << ", {";
1230  this->m_data[i]->to_stream(s);
1231  s << "}";
1232  }
1233  }
1234 }
1235 
1236 // --------------------------------------------------------------------------
1237 template<typename T>
1238  template <typename U>
1240  std::ostream &,
1241  typename std::enable_if<pack_object_ptr<U>::value, U>::type*)
1242 {
1243  // TODO
1244 }
1245 
1246 template <typename T>
1248 
1249 template <unsigned int I>
1251 
1252 template <unsigned int I>
1254 
1255 #define TECA_VARIANT_ARRAY_TT_SPEC(T, v) \
1256 template <> \
1257 struct teca_variant_array_code<T> \
1258 { \
1259  static constexpr unsigned int get() \
1260  { return v; } \
1261 }; \
1262 template <> \
1263 struct teca_variant_array_new<v> \
1264 { \
1265  static p_teca_variant_array_impl<T> New() \
1266  { return teca_variant_array_impl<T>::New(); } \
1267 }; \
1268 template <> \
1269 struct teca_variant_array_type<v> \
1270 { \
1271  using type = T; \
1272  \
1273  static constexpr const char *name() \
1274  { return #T; } \
1275 };
1276 
1277 #define TECA_VARIANT_ARRAY_FACTORY_NEW(_v) \
1278  case _v: \
1279  return teca_variant_array_new<_v>::New();
1280 
1281 #include "teca_metadata.h"
1282 class teca_metadata;
1283 
1284 TECA_VARIANT_ARRAY_TT_SPEC(char, 1)
1285 TECA_VARIANT_ARRAY_TT_SPEC(unsigned char, 2)
1286 TECA_VARIANT_ARRAY_TT_SPEC(int, 3)
1287 TECA_VARIANT_ARRAY_TT_SPEC(unsigned int, 4)
1288 TECA_VARIANT_ARRAY_TT_SPEC(short int, 5)
1289 TECA_VARIANT_ARRAY_TT_SPEC(short unsigned int, 6)
1290 TECA_VARIANT_ARRAY_TT_SPEC(long, 7)
1291 TECA_VARIANT_ARRAY_TT_SPEC(unsigned long, 8)
1292 TECA_VARIANT_ARRAY_TT_SPEC(long long, 9)
1293 TECA_VARIANT_ARRAY_TT_SPEC(unsigned long long, 10)
1294 TECA_VARIANT_ARRAY_TT_SPEC(float, 11)
1295 TECA_VARIANT_ARRAY_TT_SPEC(double, 12)
1296 TECA_VARIANT_ARRAY_TT_SPEC(std::string, 13)
1297 TECA_VARIANT_ARRAY_TT_SPEC(teca_metadata, 14)
1298 TECA_VARIANT_ARRAY_TT_SPEC(p_teca_variant_array, 15)
1299 
1301 {
1302  static p_teca_variant_array New(unsigned int type_code)
1303  {
1304  switch (type_code)
1305  {
1306  TECA_VARIANT_ARRAY_FACTORY_NEW(1)
1307  TECA_VARIANT_ARRAY_FACTORY_NEW(2)
1308  TECA_VARIANT_ARRAY_FACTORY_NEW(3)
1309  TECA_VARIANT_ARRAY_FACTORY_NEW(4)
1310  TECA_VARIANT_ARRAY_FACTORY_NEW(5)
1311  TECA_VARIANT_ARRAY_FACTORY_NEW(6)
1312  TECA_VARIANT_ARRAY_FACTORY_NEW(7)
1313  TECA_VARIANT_ARRAY_FACTORY_NEW(8)
1314  TECA_VARIANT_ARRAY_FACTORY_NEW(9)
1315  TECA_VARIANT_ARRAY_FACTORY_NEW(10)
1316  TECA_VARIANT_ARRAY_FACTORY_NEW(11)
1317  TECA_VARIANT_ARRAY_FACTORY_NEW(12)
1318  TECA_VARIANT_ARRAY_FACTORY_NEW(13)
1319  TECA_VARIANT_ARRAY_FACTORY_NEW(14)
1320  TECA_VARIANT_ARRAY_FACTORY_NEW(15)
1321  default:
1322  TECA_ERROR(
1323  << "Failed to create from "
1324  << type_code)
1325  }
1326  return nullptr;
1327  }
1328 };
1329 
1330 #define CODE_DISPATCH_CASE(_v, _c, _code) \
1331  if (_v == _c) \
1332  { \
1333  using NT = teca_variant_array_type<_c>::type; \
1334  using TT = teca_variant_array_impl<NT>; \
1335  _code \
1336  }
1337 
1338 #define CODE_DISPATCH_I(_v, _code) \
1339  CODE_DISPATCH_CASE(_v, 1, _code) \
1340  else CODE_DISPATCH_CASE(_v, 2, _code) \
1341  else CODE_DISPATCH_CASE(_v, 3, _code) \
1342  else CODE_DISPATCH_CASE(_v, 4, _code) \
1343  else CODE_DISPATCH_CASE(_v, 5, _code) \
1344  else CODE_DISPATCH_CASE(_v, 6, _code) \
1345  else CODE_DISPATCH_CASE(_v, 7, _code) \
1346  else CODE_DISPATCH_CASE(_v, 8, _code) \
1347  else CODE_DISPATCH_CASE(_v, 9, _code) \
1348  else CODE_DISPATCH_CASE(_v, 10, _code)
1349 
1350 #define CODE_DISPATCH_FP(_v, _code) \
1351  CODE_DISPATCH_CASE(_v, 11, _code) \
1352  else CODE_DISPATCH_CASE(_v, 12, _code)
1353 
1354 #define CODE_DISPATCH_CLASS(_v, _code) \
1355  CODE_DISPATCH_CASE(_v, 13, _code) \
1356  else CODE_DISPATCH_CASE(_v, 14, _code) \
1357  else CODE_DISPATCH_CASE(_v, 15, _code)
1358 
1359 #define CODE_DISPATCH(_v, _code) \
1360  CODE_DISPATCH_I(_v, _code) \
1361  else CODE_DISPATCH_FP(_v, _code)
1362 
1363 
1364 // --------------------------------------------------------------------------
1365 template<typename T>
1366 unsigned int teca_variant_array_impl<T>::type_code() const noexcept
1367 {
1369 }
1370 
1371 // **************************************************************************
1372 template <typename num_t>
1373 num_t min(const const_p_teca_variant_array_impl<num_t> &a)
1374 {
1375  num_t mn = std::numeric_limits<num_t>::max();
1376  TEMPLATE_DISPATCH(const teca_variant_array_impl,
1377  a.get(),
1378  const NT *pa = std::dynamic_pointer_cast<TT>(a)->get();
1379  size_t n = a->size();
1380  for (size_t i = 0; i < n; ++i)
1381  mn = mn > pa[i] ? pa[i] : mn;
1382  )
1383  return mn;
1384 }
1385 
1386 // **************************************************************************
1387 template <typename num_t>
1388 num_t min(const p_teca_variant_array_impl<num_t> &a)
1389 {
1390  return min(const_p_teca_variant_array_impl<num_t>(a));
1391 }
1392 
1393 // **************************************************************************
1394 template <typename num_t>
1395 num_t max(const const_p_teca_variant_array_impl<num_t> &a)
1396 {
1397  num_t mx = std::numeric_limits<num_t>::lowest();
1398  TEMPLATE_DISPATCH(const teca_variant_array_impl,
1399  a.get(),
1400  const NT *pa = std::dynamic_pointer_cast<TT>(a)->get();
1401  size_t n = a->size();
1402  for (size_t i = 0; i < n; ++i)
1403  mx = mx < pa[i] ? pa[i] : mx;
1404  )
1405  return mx;
1406 }
1407 
1408 // **************************************************************************
1409 template <typename num_t>
1410 num_t max(const p_teca_variant_array_impl<num_t> &a)
1411 {
1412  return max(const_p_teca_variant_array_impl<num_t>(a));
1413 }
1414 
1415 #endif
pack_array
Definition: teca_variant_array.h:243
teca_binary_stream
Definition: teca_binary_stream.h:16
teca_metadata
Definition: teca_metadata.h:17
teca_variant_array
type agnostic container for array based data
Definition: teca_variant_array.h:39
teca_variant_array_impl
Definition: teca_variant_array.h:269
object_dispatch
Definition: teca_variant_array.h:32
teca_variant_array_code
Definition: teca_variant_array.h:1247
teca_variant_array_new
Definition: teca_variant_array.h:1250
pack_object
Definition: teca_variant_array.h:261
teca_bad_cast
Definition: teca_bad_cast.h:8
teca_variant_array_type
Definition: teca_variant_array.h:1253
pod_dispatch
Definition: teca_variant_array.h:25
pack_object_ptr
Definition: teca_variant_array.h:252
teca_variant_array_factory
Definition: teca_variant_array.h:1301