TECA
The Toolkit for Extreme Climate Analysis
teca_variant_array_impl.h
Go to the documentation of this file.
1 #ifndef teca_variant_array_impl_h
2 #define teca_variant_array_impl_h
3 
4 /// @file
5 
6 #if defined(__CUDACC__)
7 #pragma nv_diag_suppress = partial_override
8 #endif
9 
10 #include "teca_config.h"
11 #include "teca_variant_array.h"
12 #include "teca_common.h"
13 #include "teca_binary_stream.h"
14 #include "teca_bad_cast.h"
15 #include "teca_shared_object.h"
17 
18 #include <hamr_buffer.h>
19 
20 #include <vector>
21 #include <string>
22 #include <sstream>
23 #include <exception>
24 #include <typeinfo>
25 #include <iterator>
26 #include <algorithm>
27 #include <type_traits>
28 #include <typeinfo>
29 #include <utility>
30 #include <limits>
31 
32 #if defined(TECA_HAS_CUDA)
33 #include <thrust/device_ptr.h>
34 #include <thrust/functional.h>
35 #include <thrust/reduce.h>
36 #endif
37 
38 #if !defined(SWIG)
39 using namespace teca_variant_array_util;
40 #endif
41 
42 class teca_metadata;
43 
44 TECA_SHARED_OBJECT_TEMPLATE_FORWARD_DECL(teca_variant_array_impl)
45 
46 #if !defined(SWIG)
47 template<typename T>
48 using p_teca_variant_array_impl = std::shared_ptr<teca_variant_array_impl<T>>;
49 
50 template<typename T>
51 using const_p_teca_variant_array_impl = std::shared_ptr<const teca_variant_array_impl<T>>;
52 
54 using p_teca_string_array = std::shared_ptr<teca_variant_array_impl<std::string>>;
55 using const_p_teca_string_array = std::shared_ptr<const teca_variant_array_impl<std::string>>;
56 
58 using p_teca_float_array = std::shared_ptr<teca_variant_array_impl<float>>;
59 using const_p_teca_float_array = std::shared_ptr<const teca_variant_array_impl<float>>;
60 
62 using p_teca_double_array = std::shared_ptr<teca_variant_array_impl<double>>;
63 using const_p_teca_double_array = std::shared_ptr<const teca_variant_array_impl<double>>;
64 
66 using p_teca_char_array = std::shared_ptr<teca_variant_array_impl<char>>;
67 using const_p_teca_char_array = std::shared_ptr<const teca_variant_array_impl<char>>;
68 
70 using p_teca_unsigned_char_array = std::shared_ptr<teca_variant_array_impl<unsigned char>>;
71 using const_p_teca_unsigned_char_array = std::shared_ptr<const teca_variant_array_impl<unsigned char>>;
72 
74 using p_teca_short_array = std::shared_ptr<teca_variant_array_impl<short>>;
75 using const_p_teca_short_array = std::shared_ptr<const teca_variant_array_impl<short>>;
76 
78 using p_teca_unsigned_short_array = std::shared_ptr<teca_variant_array_impl<unsigned short>>;
79 using const_p_teca_unsigned_short_array = std::shared_ptr<const teca_variant_array_impl<unsigned short>>;
80 
82 using p_teca_int_array = std::shared_ptr<teca_variant_array_impl<int>>;
83 using const_p_teca_int_array = std::shared_ptr<const teca_variant_array_impl<int>>;
84 
86 using p_teca_unsigned_int_array = std::shared_ptr<teca_variant_array_impl<unsigned int>>;
87 using const_p_teca_unsigned_int_array = std::shared_ptr<const teca_variant_array_impl<unsigned int>>;
88 
90 using p_teca_long_array = std::shared_ptr<teca_variant_array_impl<long>>;
91 using const_p_teca_long_array = std::shared_ptr<const teca_variant_array_impl<long>>;
92 
94 using p_teca_unsigned_long_array = std::shared_ptr<teca_variant_array_impl<unsigned long>>;
95 using const_p_teca_unsigned_long_array = std::shared_ptr<const teca_variant_array_impl<unsigned long>>;
96 
98 using p_teca_long_long_array = std::shared_ptr<teca_variant_array_impl<long long>>;
99 using const_p_teca_long_long_array = std::shared_ptr<const teca_variant_array_impl<long long>>;
100 
102 using p_teca_unsigned_long_long_array = std::shared_ptr<teca_variant_array_impl<unsigned long long>>;
103 using const_p_teca_unsigned_long_long_array = std::shared_ptr<const teca_variant_array_impl<unsigned long long>>;
104 
106 using p_teca_size_t_array = std::shared_ptr<teca_variant_array_impl<size_t>>;
107 using const_p_teca_size_t_array = std::shared_ptr<const teca_variant_array_impl<size_t>>;
108 #endif
109 
110 
111 /** convert from a pointer to a non-const type to a pointer to a const type.
112  * this is used to help with template deduction, which occurs before implicit
113  * conversions are considered.
114  */
115 template <typename T>
117 {
119 }
120 
121 
122 /// @cond
123 /// A tag for dispatching operations on POD data
124 template <typename T>
125 struct pod_dispatch :
126  std::integral_constant<bool,
127  std::is_arithmetic<T>::value>
128 {};
129 
130 /// A tag for disp[atching operations on classes
131 template <typename T>
132 struct object_dispatch :
133  std::integral_constant<bool,
134  !std::is_arithmetic<T>::value>
135 {};
136 /// @endcond
137 
138 /** Executes the code in body if p is a tt<nt>
139  * @param tt derived container
140  * @param nt contained type
141  * @param p base class pointer
142  * @param body the code to execute if the type matches
143  *
144  * The following aliases are provided to know the type within the code to execute.
145  *
146  * using NT = nt;
147  * using CNT = const nt;
148  * using TT = tt<nt>;
149  * using CTT = const tt<nt>;
150  * using PT = std::shared_ptr<tt<nt>>;
151  * using CPT = std::shared_ptr<const tt<nt>>;
152  * using SP = std::shared_ptr<nt>;
153  * using CSP = std::shared_ptr<const nt>;
154  *
155  */
156 #define TEMPLATE_DISPATCH_CASE(tt, nt, p, ...) \
157  if (dynamic_cast<const tt<nt>*>(p)) \
158  { \
159  using NT = nt; \
160  using CNT = const nt; \
161  using TT = tt<nt>; \
162  using CTT = const tt<nt>; \
163  using PT = std::shared_ptr<tt<nt>>; \
164  using CPT = std::shared_ptr<const tt<nt>>; \
165  using SP = std::shared_ptr<nt>; \
166  using CSP = std::shared_ptr<const nt>; \
167  __VA_ARGS__ \
168  }
169 
170 /** Executes the code in body if p is a tt<nt> an idnetifier disambiguates type
171  * aliases when nested
172  *
173  * @param tt derived container
174  * @param nt contained type
175  * @param p base class pointer
176  * @param i identifier
177  * @param body the code to execute if the type matches
178  *
179  * The following aliases are provided to know the type within the code to execute.
180  *
181  * using NT##i = nt;
182  * using CNT##i = const nt;
183  * using TT##i = tt<nt>;
184  * using CTT##i = const tt<nt>;
185  * using PT##i = std::shared_ptr<tt<nt>>;
186  * using CPT##i = std::shared_ptr<const tt<nt>>;
187  * using SP##i = std::shared_ptr<nt>;
188  * using CSP##i = std::shared_ptr<const nt>;
189  *
190  */
191 #define NESTED_TEMPLATE_DISPATCH_CASE(tt, nt, p, i, ...) \
192  if (dynamic_cast<const tt<nt>*>(p)) \
193  { \
194  using NT##i = nt; \
195  using CNT##i = const nt; \
196  using TT##i = tt<nt>; \
197  using CTT##i = const tt<nt>; \
198  using PT##i = std::shared_ptr<tt<nt>>; \
199  using CPT##i = std::shared_ptr<const tt<nt>>; \
200  using SP##i = std::shared_ptr<nt>; \
201  using CSP##i = std::shared_ptr<const nt>; \
202  __VA_ARGS__ \
203  }
204 
205 /// Executes the code in body if p is a t<nt> where nt is a floating point type
206 #define TEMPLATE_DISPATCH_FP(t, p, ...) \
207  TEMPLATE_DISPATCH_CASE(t, float, p, __VA_ARGS__) \
208  else TEMPLATE_DISPATCH_CASE(t, double, p, __VA_ARGS__)
209 
210 /// Executes the code in body if p is a t<nt> where nt is a signed inetegral type
211 #define TEMPLATE_DISPATCH_SI(t, p, ...) \
212  TEMPLATE_DISPATCH_CASE(t, long long, p, __VA_ARGS__) \
213  else TEMPLATE_DISPATCH_CASE(t, long, p, __VA_ARGS__) \
214  else TEMPLATE_DISPATCH_CASE(t, int, p, __VA_ARGS__) \
215  else TEMPLATE_DISPATCH_CASE(t, short int, p, __VA_ARGS__) \
216  else TEMPLATE_DISPATCH_CASE(t, char, p, __VA_ARGS__)
217 
218 /// Executes the code in body if p is a t<nt> where nt is either a signed integral or floating point type
219 #define TEMPLATE_DISPATCH_FP_SI(t, p, ...) \
220  TEMPLATE_DISPATCH_CASE(t, float, p, __VA_ARGS__) \
221  else TEMPLATE_DISPATCH_CASE(t, double, p, __VA_ARGS__) \
222  else TEMPLATE_DISPATCH_SI(t, p, __VA_ARGS__)
223 
224 /// Executes the code in body if p is a t<nt> where nt is an integral type
225 #define TEMPLATE_DISPATCH_I(t, p, ...) \
226  TEMPLATE_DISPATCH_CASE(t, long long, p, __VA_ARGS__) \
227  else TEMPLATE_DISPATCH_CASE(t, unsigned long long, p, __VA_ARGS__) \
228  else TEMPLATE_DISPATCH_CASE(t, long, p, __VA_ARGS__) \
229  else TEMPLATE_DISPATCH_CASE(t, int, p, __VA_ARGS__) \
230  else TEMPLATE_DISPATCH_CASE(t, unsigned int, p, __VA_ARGS__) \
231  else TEMPLATE_DISPATCH_CASE(t, unsigned long, p, __VA_ARGS__) \
232  else TEMPLATE_DISPATCH_CASE(t, short int, p, __VA_ARGS__) \
233  else TEMPLATE_DISPATCH_CASE(t, short unsigned int, p, __VA_ARGS__) \
234  else TEMPLATE_DISPATCH_CASE(t, char, p, __VA_ARGS__) \
235  else TEMPLATE_DISPATCH_CASE(t, unsigned char, p, __VA_ARGS__)
236 
237 /** A macro for accessing the typed contents of a teca_variant_array
238  * @param t container type
239  * @param p pointer to an instance to match on
240  * @param body code to execute on match
241  *
242  * See #TEMPLATE_DISPATCH_CASE for details.
243  */
244 #define TEMPLATE_DISPATCH(t, p, ...) \
245  TEMPLATE_DISPATCH_FP(t, p, __VA_ARGS__) \
246  else TEMPLATE_DISPATCH_I(t, p, __VA_ARGS__)
247 
248 /** A macro for accessing the typed contents of a teca_variant_array
249  * @param t container type
250  * @param p pointer to an instance to match on
251  * @param body code to execute on match
252  *
253  * See #TEMPLATE_DISPATCH_CASE for details.
254  */
255 #define TEMPLATE_DISPATCH_OBJ(t, p, ...) \
256  TEMPLATE_DISPATCH_CASE(t, std::string, p, __VA_ARGS__) \
257  else TEMPLATE_DISPATCH_CASE(t, teca_metadata, p, __VA_ARGS__)
258 
259 /** A macro for accessing the typed contents of a teca_variant_array
260  * @param t container type
261  * @param p pointer to an instance to match on
262  * @param body code to execute on match
263  *
264  * See #TEMPLATE_DISPATCH_CASE for details.
265  */
266 #define TEMPLATE_DISPATCH_PTR(t, p, ...) \
267  TEMPLATE_DISPATCH_CASE(t, const_p_teca_variant_array, p, __VA_ARGS__) \
268  else TEMPLATE_DISPATCH_CASE(t, p_teca_variant_array, p, __VA_ARGS__)
269 
270 /** A macro for accessing the floating point typed contents of a teca_variant_array
271  * @param t container type
272  * @param p pointer to an instance to match on
273  * @param i an indentifier to use with type aliases
274  * @param body code to execute on match
275  *
276  * See #NESTED_TEMPLATE_DISPATCH_CASE for details.
277  */
278 #define NESTED_TEMPLATE_DISPATCH_FP(t, p, i, ...) \
279  NESTED_TEMPLATE_DISPATCH_CASE(t, float, p, i, __VA_ARGS__) \
280  else NESTED_TEMPLATE_DISPATCH_CASE(t, double, p, i, __VA_ARGS__)
281 
282 /** A macro for accessing the inetgral typed contents of a teca_variant_array
283  * @param t container type
284  * @param p pointer to an instance to match on
285  * @param i an indentifier to use with type aliases
286  * @param body code to execute on match
287  *
288  * See #NESTED_TEMPLATE_DISPATCH_CASE for details.
289  */
290 #define NESTED_TEMPLATE_DISPATCH_I(t, p, i, ...) \
291  NESTED_TEMPLATE_DISPATCH_CASE(t, long long, p, i, __VA_ARGS__) \
292  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned long long, p, i, __VA_ARGS__) \
293  else NESTED_TEMPLATE_DISPATCH_CASE(t, long, p, i, __VA_ARGS__) \
294  else NESTED_TEMPLATE_DISPATCH_CASE(t, int, p, i, __VA_ARGS__) \
295  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned int, p, i, __VA_ARGS__) \
296  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned long, p, i, __VA_ARGS__) \
297  else NESTED_TEMPLATE_DISPATCH_CASE(t, short int, p, i, __VA_ARGS__) \
298  else NESTED_TEMPLATE_DISPATCH_CASE(t, short unsigned int, p, i, __VA_ARGS__) \
299  else NESTED_TEMPLATE_DISPATCH_CASE(t, char, p, i, __VA_ARGS__) \
300  else NESTED_TEMPLATE_DISPATCH_CASE(t, unsigned char, p, i, __VA_ARGS__)
301 
302 /** \def NESTED_TEMPLATE_DISPATCH(t, p, i, body)
303  * A macro for accessing the typed contents of a teca_variant_array
304  * @param t container type
305  * @param p pointer to an instance to match on
306  * @param i an indentifier to use with type aliases
307  * @param body code to execute on match
308  *
309  * See #NESTED_TEMPLATE_DISPATCH_CASE for details.
310  */
311 #define NESTED_TEMPLATE_DISPATCH(t, p, i, ...) \
312  NESTED_TEMPLATE_DISPATCH_FP(t, p, i, __VA_ARGS__) \
313  else NESTED_TEMPLATE_DISPATCH_I(t, p, i, __VA_ARGS__)
314 
315 /** shortcuts for NESTED_TEMPLATE_DISPATCH macros */
316 #define NESTED_VARIANT_ARRAY_DISPATCH(p, i, ...) \
317  NESTED_TEMPLATE_DISPATCH(teca_variant_array_impl, p, i, __VA_ARGS__)
318 
319 #define NESTED_VARIANT_ARRAY_DISPATCH_FP(p, i, ...) \
320  NESTED_TEMPLATE_DISPATCH_FP(teca_variant_array_impl, p, i, __VA_ARGS__)
321 
322 #define NESTED_VARIANT_ARRAY_DISPATCH_I(p, i, ...) \
323  NESTED_TEMPLATE_DISPATCH_I(teca_variant_array_impl, p, i, __VA_ARGS__)
324 
325 #define NESTED_VARIANT_ARRAY_DISPATCH_CASE(nt, p, i, ...) \
326  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, nt, p, i, __VA_ARGS__)
327 
328 /** shortcuts for TEMPLATE_DISPATCH macros */
329 #define VARIANT_ARRAY_DISPATCH(p, ...) \
330  TEMPLATE_DISPATCH(teca_variant_array_impl, p, __VA_ARGS__)
331 
332 #define VARIANT_ARRAY_DISPATCH_FP(p, ...) \
333  TEMPLATE_DISPATCH_FP(teca_variant_array_impl, p, __VA_ARGS__)
334 
335 #define VARIANT_ARRAY_DISPATCH_I(p, ...) \
336  TEMPLATE_DISPATCH_I(teca_variant_array_impl, p, __VA_ARGS__)
337 
338 #define VARIANT_ARRAY_DISPATCH_FP_SI(p, ...) \
339  TEMPLATE_DISPATCH_FP_SI(teca_variant_array_impl, p, __VA_ARGS__)
340 
341 #define VARIANT_ARRAY_DISPATCH_CASE(nt, p, ...) \
342  TEMPLATE_DISPATCH_CASE(teca_variant_array_impl, nt, p, __VA_ARGS__)
343 
344 /// @cond
345 // tag for contiguous arrays, and objects that have
346 // overrides in teca_binary_stream
347 template<typename T>
348 struct pack_array
349  : std::integral_constant<bool,
350  std::is_arithmetic<T>::value ||
351  std::is_same<T, std::string>::value>
352 {};
353 
354 // tag for arrays of pointers of other objects
355 template<typename T>
356 struct pack_object_ptr
357  : std::integral_constant<bool,
358  (std::is_pointer<T>::value ||
359  std::is_same<T, p_teca_variant_array>::value) &&
360  !pack_array<T>::value>
361 {};
362 
363 // tag for arrays of other objects
364 template<typename T>
365 struct pack_object
366  : std::integral_constant<bool,
367  !pack_array<T>::value &&
368  !std::is_pointer<T>::value &&
369  !pack_object_ptr<T>::value>
370 {};
371 /// @endcond
372 
373 
374 /** @brief
375  * The concrete implementation of our type agnostic container for contiguous
376  * arrays.
377  */
378 template<typename T>
380 {
381 public:
382  using element_type = T;
383  using pointer_type = std::shared_ptr<T>;
384 
385  /** @name Array constructors
386  * Constructs a new instance containing the templated type.
387  */
388  ///@{
389  /** Allocate an array. The default value of alloc sets the array up for
390  * use on the CPU using C++ new to allocate memory to hold the contents.
391  */
392  static std::shared_ptr<teca_variant_array_impl<T>>
393  New() { return New(allocator::malloc); }
394 
395  /** Allocate an array. The default value of alloc sets the array up for
396  * use on the CPU using C++ new to allocate memory to hold the contents.
397  */
398  static std::shared_ptr<teca_variant_array_impl<T>>
399  New(allocator alloc);
400 
401  /** Allocates an array with space for n elements. The default value of
402  * alloc sets the array up for use on the CPU using C++ new to allocate
403  * memory to hold the contents.
404  */
405  static std::shared_ptr<teca_variant_array_impl<T>>
406  New(size_t n) { return New(n, allocator::malloc); }
407 
408  /** Allocates an array with space for n elements. The default value of
409  * alloc sets the array up for use on the CPU using C++ new to allocate
410  * memory to hold the contents.
411  */
412  static std::shared_ptr<teca_variant_array_impl<T>>
413  New(size_t n, allocator alloc);
414 
415  /** Allocate an array with space for n elements initialized with v. The default
416  * value of alloc sets the array up for use on the CPU using C++ new to
417  * allocate memory to hold the contents.
418  */
419  template <typename U>
420  static std::shared_ptr<teca_variant_array_impl<T>>
421  New(size_t n, const U &v) { return New(n, v, allocator::malloc); }
422 
423  /** Allocate an array with space for n elements initialized with v. The default
424  * value of alloc sets the array up for use on the CPU using C++ new to
425  * allocate memory to hold the contents.
426  */
427  template <typename U>
428  static std::shared_ptr<teca_variant_array_impl<T>>
429  New(size_t n, const U &v, allocator alloc);
430 
431  /** Allocate an array with space for n elements initialized with v. The default
432  * value of alloc sets the array up for use on the CPU using C++ new to
433  * allocate memory to hold the contents.
434  */
435  template <typename U>
436  static std::shared_ptr<teca_variant_array_impl<T>>
437  New(size_t n, const U *v) { return New(n, v, allocator::malloc); }
438 
439  /** Allocate an array with space for n elements initialized with v. The default
440  * value of alloc sets the array up for use on the CPU using C++ new to
441  * allocate memory to hold the contents.
442  */
443  template <typename U>
444  static std::shared_ptr<teca_variant_array_impl<T>>
445  New(size_t n, const U *v, allocator alloc);
446 
447  /** construct by directly providing the buffer contents. This can be used
448  * for zero-copy transfer of data. One must also name the allocator type
449  * and device owning the data. In addition for new allocations the
450  * allocator type and owner are used internally to know how to
451  * automatically move data during inter technology transfers.
452  *
453  * @param[in] alloc an ::allocator indicating the technology backing the
454  * pointer
455  * @param[in] size the number of elements in the array pointed to by ptr
456  * @param[in] owner the device owning the memory, -1 for CPU. if the
457  * allocator is a GPU allocator and -1 is passed the
458  * driver API is used to determine the device that
459  * allocated the memory.
460  * @param[in] ptr a pointer to the data
461  * @param[in] df a function `void df(void*ptr)` used to delete the data
462  * when this instance is finished using it.
463  */
464  template <typename delete_func_t>
465  static std::shared_ptr<teca_variant_array_impl<T>>
466  New(size_t n, T *ptr, allocator alloc, int owner, delete_func_t df);
467 
468  /// Returns a new instance initialized with a deep copy of this one.
469  p_teca_variant_array new_copy(allocator alloc = allocator::malloc) const override;
470 
471  /** virtual copy construct. return a newly allocated object, initialized
472  * copy from a subset of this.
473  */
474  p_teca_variant_array new_copy(size_t src_start, size_t n_elem, allocator alloc) const override;
475 
476  /// Returns a new instance of the same type.
477  p_teca_variant_array new_instance(allocator alloc) const override;
478 
479  /// Returns a new instance of the same type sized to hold n elements.
480  p_teca_variant_array new_instance(size_t n, allocator alloc) const override;
481  ///@}
482 
483  virtual ~teca_variant_array_impl() noexcept;
484 
485  /// @copydoc teca_variant_array::set_allocator(allocator)
486  int set_allocator(allocator alloc) override;
487 
488  /// Returns the name of the class in a human readable form
489  std::string get_class_name() const override;
490 
491  /// Initialize all elements with T()
492  void initialize() override
493  {
494  TECA_ERROR("Not implemented")
495  }
496 
497  // silence some warning from nvcc
503 
504  /** @name get
505  * Copy the content of this array. The desitination must be large enough to
506  * hold the results. These calls could throw teca_bad_cast if the passed
507  * in type is not castable to the internal type.
508  */
509  ///@{
510  /// get a single value
511  template<typename U>
512  void get(size_t i, U &val) const
513  {
514  this->get(i, &val, 0, 1);
515  }
516 
517  /// get a single value
518  T get(size_t i) const
519  {
520  T val = T();
521  this->get(i, &val, 0, 1);
522  return val;
523  }
524 
525  /// get a vector of values
526  template<typename U>
527  void get(std::vector<U> &dest) const
528  {
529  size_t n_elem = this->size();
530  dest.resize(n_elem);
531  this->get(0, dest.data(), 0, n_elem);
532  }
533 
534  /// get a range of values
535  template<typename U>
536  void get(size_t src_start, U *dest, size_t dest_start, size_t n_elem) const
537  {
538  assert(this->size() >= (src_start + n_elem));
539  this->get_dispatch(src_start, dest, dest_start, n_elem);
540  }
541 
542  /// get the contents into the other array.
543  void get(const p_teca_variant_array &dest) const override
544  {
545  this->get(0, dest, 0, this->size());
546  }
547 
548  /** get a subset of the contents into a subset of the other array
549  *
550  * @param[in] dest_start the first location to assign to
551  * @param[in] src the array to copy values from
552  * @param[in] src_start the first location to copy from
553  * @param[in] n_elem the number of elements to copy
554  */
555  void get(size_t src_start, const p_teca_variant_array &dest,
556  size_t dest_start, size_t n_elem) const override
557  {
558  assert(this->size() >= (src_start + n_elem));
559  this->get_dispatch<T>(src_start, dest, dest_start, n_elem);
560  }
561 
562  /// get the contents into the other array.
563  template <typename U>
564  void get(const p_teca_variant_array_impl<U> &dest) const
565  {
566  this->get(0, dest, 0, this->size());
567  }
568 
569  /** get a subset of the contents into a subset of the other array
570  *
571  * @param[in] dest_start the first location to assign to
572  * @param[in] src the array to copy values from
573  * @param[in] src_start the first location to copy from
574  * @param[in] n_elem the number of elements to copy
575  */
576  template <typename U>
577  void get(size_t src_start, const p_teca_variant_array_impl<U> &dest,
578  size_t dest_start, size_t n_elem) const
579  {
580  assert(this->size() >= (src_start + n_elem));
581  this->get_dispatch<T>(src_start, dest, dest_start, n_elem);
582  }
583  ///@}
584 
585  /** @name set
586  * Assign values to this array. This array must already be large enough to
587  * hold the result. If automatic resizing is desired use copy instead.
588  * These calls could throw teca_bad_cast if the passed in type is not
589  * castable to the internal type.
590  */
591  ///@{
592  /// set a single value
593  template<typename U>
594  void set(size_t i, const U &val)
595  {
596  this->set(i, &val, 0, 1);
597  }
598 
599  /// set from a vector of values
600  template<typename U>
601  void set(const std::vector<U> &src)
602  {
603  this->set(0, src.data(), 0, src.size());
604  }
605 
606  /** set from a subset of the other array
607  *
608  * @param[in] dest_start the first location to assign to
609  * @param[in] src the array to copy values from
610  * @param[in] src_start the first location to copy from
611  * @param[in] n_elem the number of elements to copy
612  */
613  template<typename U>
614  void set(size_t dest_start, const U *src, size_t src_start, size_t n_elem)
615  {
616  assert(this->size() >= (dest_start + n_elem));
617  this->set_dispatch(dest_start, src, src_start, n_elem);
618  }
619 
620  /// Set from the other array
621  void set(const const_p_teca_variant_array &src) override
622  {
623  this->set(0, src, 0, src->size());
624  }
625 
626  /** Set a subset of this array from a subset of the other array.
627  *
628  * @param[in] dest_start the first location to assign to
629  * @param[in] src the array to copy values from
630  * @param[in] src_start the first location to copy from
631  * @param[in] n_elem the number of elements to copy
632  */
633  void set(size_t dest_start, const const_p_teca_variant_array &src,
634  size_t src_start, size_t n_elem) override
635  {
636  assert(this->size() >= (dest_start + n_elem));
637  this->set_dispatch(dest_start, src, src_start, n_elem);
638  }
639 
640  /// Set from the other array
641  template <typename U>
643  {
644  this->set(0, src, 0, src->size());
645  }
646 
647  /** Set a subset of this array from a subset of the other array.
648  *
649  * @param[in] dest_start the first location to assign to
650  * @param[in] src the array to copy values from
651  * @param[in] src_start the first location to copy from
652  * @param[in] n_elem the number of elements to copy
653  */
654  template <typename U>
655  void set(size_t dest_start, const const_p_teca_variant_array_impl<U> &src,
656  size_t src_start, size_t n_elem)
657  {
658  assert(this->size() >= (dest_start + n_elem));
659  this->set_dispatch(dest_start, src, src_start, n_elem);
660  }
661  ///@}
662 
663  /** @name assign
664  * assign the contents of the passed array to this array. This array will be
665  * resized to hold the results. These calls could throw teca_bad_cast if
666  * the passed in type is not castable to the internal type.
667  */
668  ///@{
669  /// assign the contents from a vector of values
670  template<typename U>
671  void assign(const std::vector<U> &src)
672  {
673  this->assign(src.data(), 0, src.size());
674  }
675 
676  /// assign a subset from the other array
677  template<typename U>
678  void assign(const U *src, size_t src_start, size_t n_elem)
679  {
680  this->assign_dispatch(src, src_start, n_elem);
681  }
682 
683  /// assign the contents from the other array.
684  void assign(const const_p_teca_variant_array &src) override
685  {
686  this->assign(src, 0, src->size());
687  }
688 
689  /// assign a subset of the other array
691  size_t src_start, size_t n_elem) override
692  {
693  this->assign_dispatch(src, src_start, n_elem);
694  }
695 
696  /// assign the contents from the other array.
697  template <typename U>
699  {
700  this->assign(src, 0, src->size());
701  }
702 
703  /// assign the contents from the other array.
704  template <typename U>
706  {
707  // forward to the const implementation
708  this->assign(const_p_teca_variant_array_impl<U>(src), 0, src->size());
709  }
710 
711  /// assign a subset of the other array
712  template <typename U>
714  size_t src_start, size_t n_elem)
715  {
716  this->assign_dispatch(src, src_start, n_elem);
717  }
718 
719  /// copy the contents from the other array.
720  template <typename U>
722  {
723  this->assign(src, 0, src->size());
724  }
725 
726  /// copy a subset of the other array
727  template <typename U>
729  size_t src_start, size_t n_elem)
730  {
731  this->assign_dispatch(src, src_start, n_elem);
732  }
733  ///@}
734 
735  /** @name append
736  * Append data at the back of the array. These calls could throw
737  * teca_bad_cast if the passed in type is not castable to the internal
738  * type.
739  */
740  ///@{
741  /// append a single value
742  template<typename U>
743  void append(const U &val)
744  {
745  this->append(&val, 0, 1);
746  }
747 
748  /// append a vector of values
749  template<typename U>
750  void append(const std::vector<U> &vals)
751  {
752  this->append(vals.data(), 0, vals.size());
753  }
754 
755  /// append a range of values
756  template<typename U>
757  void append(const U *src, size_t src_start, size_t n_elem)
758  {
759  this->append_dispatch(src, src_start, n_elem);
760  }
761 
762  // Append the contents from the other array
763  void append(const const_p_teca_variant_array &src) override
764  {
765  this->append(src, 0, src->size());
766  }
767 
768  // Append a subset of the contents from the other array
770  size_t src_start, size_t n_elem) override
771  {
772  this->append_dispatch(src, src_start, n_elem);
773  }
774 
775  // Append the contents from the other array
776  template <typename U>
778  {
779  this->append(src, 0, src->size());
780  }
781 
782  // Append the contents from the other array
783  template <typename U>
784  void append(const p_teca_variant_array_impl<U> &src)
785  {
786  // forward to const implementation
787  this->append(const_p_teca_variant_array_impl<U>(src), 0, src->size());
788  }
789 
790  // Append a subset of the contents from the other array
791  template <typename U>
793  size_t src_start, size_t n_elem)
794  {
795  this->append_dispatch(src, src_start, n_elem);
796  }
797  ///@}
798 
799 #if !defined(SWIG)
800  /** @name get_accessible
801  * get's a pointer to the raw data that is accessible on the named
802  * accelerator device or technology.
803  */
804  ///@{
805  /// Get a pointer to the data accessible on the CPU
806  const std::shared_ptr<const T> get_host_accessible() const
807  { return m_data.get_host_accessible(); }
808 
809  /// Get a pointer to the data accessible within CUDA
810  const std::shared_ptr<const T> get_cuda_accessible() const
811  { return m_data.get_cuda_accessible(); }
812  ///@}
813 #endif
814 
815  /// Sycnhronize the stream used for data movement
816  void synchronize() const override { m_data.synchronize(); }
817 
818  /** direct access to the internal memory. Use this when you are certain
819  * that the data is already accessible in the location where you will
820  * access it to save the cost of the std::shared_ptr copy constructor.
821  */
822  const T *data() const { return m_data.data(); }
823 
824  /** direct access to the internal memory. Use this when you are certain
825  * that the data is already accessible in the location where you will
826  * access it to save the cost of the std::shared_ptr copy constructor.
827  */
828  T *data() { return m_data.data(); }
829 
830  /** direct access to the internal memory. Use this when you are certain
831  * that the data is already accessible in the location where you will
832  * access it.
833  */
834  const std::shared_ptr<T> &pointer() const { return m_data.pointer(); }
835 
836  /** direct access to the internal memory. Use this when you are certain
837  * that the data is already accessible in the location where you will
838  * access it.
839  */
840  std::shared_ptr<T> &pointer() { return m_data.pointer(); }
841 
842  /// returns true if the data is accessible from CUDA codes
843  int cuda_accessible() const noexcept override { return m_data.cuda_accessible(); }
844 
845  /// returns true if the data is accessible from codes running on the CPU
846  int host_accessible() const noexcept override { return m_data.host_accessible(); }
847 
848  /// Get the current size of the data
849  unsigned long size() const noexcept override;
850 
851  /// Resize the data
852  void resize(unsigned long n) override;
853  void resize(unsigned long n, const T &val);
854 
855  /// Reserve space
856  void reserve(unsigned long n) override;
857 
858  /// Clear the data
859  void clear() noexcept override;
860 
861  /// virtual swap
862  void swap(const p_teca_variant_array &other) override;
863 
864  /// virtual equivalence test
865  bool equal(const const_p_teca_variant_array &other) const override;
866 
867  /// Serialize to the stream
868  int to_stream(teca_binary_stream &s) const override
869  {
870  this->to_binary<T>(s);
871  return 0;
872  }
873 
874  /// Deserialize from the stream
876  {
877  this->from_binary<T>(s);
878  return 0;
879  }
880 
881  /// Serialize to the stream
882  int to_stream(std::ostream &s) const override
883  {
884  this->to_ascii<T>(s);
885  return 0;
886  }
887 
888  /// Deserialize from the stream
889  int from_stream(std::ostream &s) override
890  {
891  this->from_ascii<T>(s);
892  return 0;
893  }
894 
895  /// Print the contents of the buffer for debugging
896  template <typename U = T>
897  void debug_print(typename std::enable_if< std::is_arithmetic<U>::value >::type* = 0) const
898  { m_data.print(); }
899 
900  /// Print the contents of the buffer for debugging
901  template <typename U = T>
902  void debug_print(typename std::enable_if<!std::is_arithmetic<U>::value>::type* = 0) const
903  {
904  TECA_WARNING("Failed to print the buffer for T=" << typeid(T).name() << sizeof(T))
905  }
906 
907  teca_variant_array::allocator get_allocator() const
908  {
909  return teca_variant_array::allocator(m_data.get_allocator());
910  }
911 
912 #if defined(SWIG)
913 protected:
914 #else
915 public:
916 #endif
917  // NOTE: constructors are public to enable std::make_shared. DO NOT USE.
918 
919  /// default construct (the object is unusable)
921 
922  /// construct with a specific allocator
924  m_data(alloc) {}
925 
926  /// construct with preallocated size
927  teca_variant_array_impl(allocator alloc, size_t n_elem) :
928  m_data(alloc, n_elem) {}
929 
930  /// construct with preallocated size and initialized to a specific value
931  teca_variant_array_impl(allocator alloc, size_t n_elem, const T &val) :
932  m_data(alloc, n_elem, val) {}
933 
934  /// construct with preallocated size and initialized to a specific value
935  template <typename U>
936  teca_variant_array_impl(allocator alloc, size_t n_elem, const U *vals) :
937  m_data(alloc, n_elem, vals) {}
938 
939  /// copy construct from an instance of different type
940  template<typename U>
942  const const_p_teca_variant_array_impl<U> &other) :
943  m_data(alloc, other->m_data) {}
944 
945  /// zero-copy construct by setting buffer contents directly
946  template <typename delete_func_t>
947  teca_variant_array_impl(allocator alloc, size_t size, int owner,
948  T *ptr, delete_func_t df) : m_data(alloc, size, owner, ptr, df) {}
949 
950 private:
951  /// get from objects.
952  template <typename U = T>
953  void get_dispatch(size_t src_start,
954  const p_teca_variant_array_impl<U> &dest, size_t dest_start, size_t n_elem,
955  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0) const;
956 
957  /// get from POD types
958  template <typename U = T>
959  void get_dispatch(size_t src_start,
960  const p_teca_variant_array_impl<U> &dest, size_t dest_start, size_t n_elem,
961  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0) const;
962 
963  /// set from objects.
964  template <typename U = T>
965  void set_dispatch(size_t dest_start,
966  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
967  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
968 
969  /// set from POD types
970  template <typename U = T>
971  void set_dispatch(size_t dest_start,
972  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
973  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
974 
975  /// copy from objects.
976  template <typename U = T>
977  void assign_dispatch(const const_p_teca_variant_array_impl<U> &src,
978  size_t src_start, size_t n_elem,
979  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
980 
981  /// copy from POD types
982  template <typename U = T>
983  void assign_dispatch(const const_p_teca_variant_array_impl<U> &src,
984  size_t src_start, size_t n_elem,
985  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
986 
987  /// append from objects.
988  template <typename U = T>
989  void append_dispatch(const const_p_teca_variant_array_impl<U> &src,
990  size_t src_start, size_t n_elem,
991  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
992 
993  /// append from POD types
994  template <typename U = T>
995  void append_dispatch(const const_p_teca_variant_array_impl<U> &src,
996  size_t src_start, size_t n_elem,
997  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
998 
999  /// get from objects.
1000  template <typename U = T>
1001  void get_dispatch(size_t src_start,
1002  const p_teca_variant_array &dest, size_t dest_start, size_t n_elem,
1003  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0) const;
1004 
1005  /// get from POD types
1006  template <typename U = T>
1007  void get_dispatch(size_t src_start,
1008  const p_teca_variant_array &dest, size_t dest_start, size_t n_elem,
1009  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0) const;
1010 
1011  /// set from objects.
1012  template <typename U = T>
1013  void set_dispatch(size_t dest_start,
1014  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
1015  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1016 
1017  /// set from POD types
1018  template <typename U = T>
1019  void set_dispatch(size_t dest_start,
1020  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
1021  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1022 
1023  /// copy from objects.
1024  template <typename U = T>
1025  void assign_dispatch(const const_p_teca_variant_array &src,
1026  size_t src_start, size_t n_elem,
1027  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1028 
1029  /// copy from POD types
1030  template <typename U = T>
1031  void assign_dispatch(const const_p_teca_variant_array &src,
1032  size_t src_start, size_t n_elem,
1033  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1034 
1035  /// append from objects.
1036  template <typename U = T>
1037  void append_dispatch(const const_p_teca_variant_array &src,
1038  size_t src_start, size_t n_elem,
1039  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1040 
1041  /// append from POD types
1042  template <typename U = T>
1043  void append_dispatch(const const_p_teca_variant_array &src,
1044  size_t src_start, size_t n_elem,
1045  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1046 
1047  /// get from objects.
1048  template <typename U = T>
1049  void get_dispatch(size_t src_start,
1050  U *dest, size_t dest_start, size_t n_elem,
1051  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0) const;
1052 
1053  /// get from POD types
1054  template <typename U = T>
1055  void get_dispatch(size_t src_start,
1056  U *dest, size_t dest_start, size_t n_elem,
1057  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0) const;
1058 
1059  /// set from objects.
1060  template <typename U = T>
1061  void set_dispatch(size_t dest_start,
1062  const U *src, size_t src_start, size_t n_elem,
1063  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1064 
1065  /// set from POD types
1066  template <typename U = T>
1067  void set_dispatch(size_t dest_start,
1068  const U *src, size_t src_start, size_t n_elem,
1069  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1070 
1071  /// copy from objects.
1072  template <typename U = T>
1073  void assign_dispatch(const U *src,
1074  size_t src_start, size_t n_elem,
1075  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1076 
1077  /// copy from POD types
1078  template <typename U = T>
1079  void assign_dispatch(const U *src,
1080  size_t src_start, size_t n_elem,
1081  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1082 
1083  /// append from objects.
1084  template <typename U = T>
1085  void append_dispatch(const U *src,
1086  size_t src_start, size_t n_elem,
1087  typename std::enable_if<object_dispatch<U>::value, U>::type* = 0);
1088 
1089  /// append from POD types
1090  template <typename U = T>
1091  void append_dispatch(const U *src,
1092  size_t src_start, size_t n_elem,
1093  typename std::enable_if<pod_dispatch<U>::value, U>::type* = 0);
1094 
1095 
1096  // tag dispatch c style array, and types that have overrides in
1097  // binary stream
1098  template <typename U = T>
1099  void to_binary(teca_binary_stream &s,
1100  typename std::enable_if<pack_array<U>::value, U>::type* = 0)
1101  const;
1102 
1103  template <typename U = T>
1104  void from_binary(teca_binary_stream &s,
1105  typename std::enable_if<pack_array<U>::value, U>::type* = 0);
1106 
1107  // tag dispatch array of other objects
1108  template <typename U = T>
1109  void to_binary(teca_binary_stream &s,
1110  typename std::enable_if<pack_object<U>::value, U>::type* = 0)
1111  const;
1112 
1113  template <typename U = T>
1114  void from_binary(teca_binary_stream &s,
1115  typename std::enable_if<pack_object<U>::value, U>::type* = 0);
1116 
1117  // tag dispatch array of pointer to other objects
1118  template <typename U = T>
1119  void to_binary(teca_binary_stream &s,
1120  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0)
1121  const;
1122 
1123  template <typename U = T>
1124  void from_binary(teca_binary_stream &s,
1125  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0);
1126 
1127  // ostream
1128  template <typename U = T>
1129  void to_ascii(std::ostream &s,
1130  typename std::enable_if<pack_array<U>::value, U>::type* = 0)
1131  const;
1132 
1133  template <typename U = T>
1134  void from_ascii(std::ostream &s,
1135  typename std::enable_if<pack_array<U>::value, U>::type* = 0);
1136 
1137  // tag dispatch array of other objects
1138  template <typename U = T>
1139  void to_ascii(std::ostream &s,
1140  typename std::enable_if<pack_object<U>::value, U>::type* = 0)
1141  const;
1142 
1143  template <typename U = T>
1144  void from_ascii(std::ostream &s,
1145  typename std::enable_if<pack_object<U>::value, U>::type* = 0);
1146 
1147  // tag dispatch array of pointer to other objects
1148  template <typename U = T>
1149  void to_ascii(std::ostream &s,
1150  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0)
1151  const;
1152 
1153  template <typename U = T>
1154  void from_ascii(std::ostream &s,
1155  typename std::enable_if<pack_object_ptr<U>::value, U>::type* = 0);
1156 
1157  /// returns a code used to identify the contained type during serialization
1158  unsigned int type_code() const noexcept override;
1159 
1160  /// gets a shared pointer to this
1161  p_teca_variant_array_impl<T> shared_from_this()
1162  {
1163  return std::static_pointer_cast
1165  (teca_variant_array::shared_from_this());
1166  }
1167 
1168  /// gets a const shared pointer to this
1169  const_p_teca_variant_array_impl<T> shared_from_this() const
1170  {
1171  return std::static_pointer_cast
1173  (teca_variant_array::shared_from_this());
1174  }
1175 
1176 private:
1177  hamr::buffer<T> m_data;
1178 
1179  friend class teca_variant_array;
1180  template<typename U> friend class teca_variant_array_impl;
1181 };
1182 
1183 
1184 
1185 
1186 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
1187 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
1188 
1189 // --------------------------------------------------------------------------
1190 template<typename T>
1191 void teca_variant_array::get(unsigned long i, T &val) const
1192 {
1193  this->get_dispatch(i, val);
1194 }
1195 
1196 // --------------------------------------------------------------------------
1197 template<typename T>
1198 T teca_variant_array::get(unsigned long i) const
1199 {
1200  T val = T();
1201  this->get_dispatch(i, val);
1202  return val;
1203 }
1204 
1205 // --------------------------------------------------------------------------
1206 template<typename T>
1207 void teca_variant_array::get(std::vector<T> &vals) const
1208 {
1209  this->get_dispatch(vals);
1210 }
1211 
1212 // --------------------------------------------------------------------------
1213 template<typename T>
1214 void teca_variant_array::get(size_t src_start, T *dest, size_t dest_start, size_t n_elem) const
1215 {
1216  this->get_dispatch(src_start, dest, dest_start, n_elem);
1217 }
1218 
1219 // --------------------------------------------------------------------------
1220 template<typename T>
1221 void teca_variant_array::set(unsigned long i, const T &val)
1222 {
1223  this->set_dispatch(i, val);
1224 }
1225 
1226 // --------------------------------------------------------------------------
1227 template<typename T>
1228 void teca_variant_array::set(const std::vector<T> &src)
1229 {
1230  this->set_dispatch(src);
1231 }
1232 
1233 // --------------------------------------------------------------------------
1234 template<typename T>
1235 void teca_variant_array::set(size_t dest_start, const T *src, size_t src_start, size_t n_elem)
1236 {
1237  this->set_dispatch(dest_start, src, src_start, n_elem);
1238 }
1239 
1240 // --------------------------------------------------------------------------
1241 template<typename T>
1242 void teca_variant_array::assign(const std::vector<T> &src)
1243 {
1244  this->assign_dispatch(src);
1245 }
1246 
1247 // --------------------------------------------------------------------------
1248 template<typename T>
1249 void teca_variant_array::assign(const T *src, size_t src_start, size_t n_elem)
1250 {
1251  this->assign(src, src_start, n_elem);
1252 }
1253 
1254 // --------------------------------------------------------------------------
1255 template<typename T>
1256 void teca_variant_array::append(const T &val)
1257 {
1258  this->append_dispatch(val);
1259 }
1260 
1261 // --------------------------------------------------------------------------
1262 template<typename T>
1263 void teca_variant_array::append(const std::vector<T> &src)
1264 {
1265  this->append_dispatch(src);
1266 }
1267 
1268 // --------------------------------------------------------------------------
1269 template<typename T>
1270 void teca_variant_array::append(const T *src, size_t src_start, size_t n_elem)
1271 {
1272  this->append_dispatch(src, src_start, n_elem);
1273 }
1274 
1275 // --------------------------------------------------------------------------
1276 template<typename T>
1277 void teca_variant_array::get_dispatch(unsigned long i, T &val,
1278  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
1279 {
1280  // only apply when types match
1281  const teca_variant_array_impl<T> *ptthis =
1282  dynamic_cast<const teca_variant_array_impl<T>*>(this);
1283 
1284  if (ptthis)
1285  {
1286  // safe. the types match
1287  ptthis->get(i, val);
1288  return;
1289  }
1290 
1291  // types do not match
1292  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1293  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1294  << " failed")
1295 }
1296 
1297 // --------------------------------------------------------------------------
1298 template<typename T>
1299 void teca_variant_array::get_dispatch(unsigned long i, T &val,
1300  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
1301 {
1302  // apply on POD types
1304  this,
1305  const TT *ptthis = dynamic_cast<const TT*>(this);
1306  ptthis->get(i, val);
1307  return;
1308  )
1309 
1310  // unssuported type
1311  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1312  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1313  << " failed")
1314 }
1315 
1316 // --------------------------------------------------------------------------
1317 template<typename T>
1318 void teca_variant_array::get_dispatch(std::vector<T> &vals,
1319  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
1320 {
1321  // only apply when types match
1322  const teca_variant_array_impl<T> *ptthis =
1323  dynamic_cast<const teca_variant_array_impl<T>*>(this);
1324 
1325  if (ptthis)
1326  {
1327  // safe. the types match
1328  ptthis->get(vals);
1329  return;
1330  }
1331 
1332  // types do not match
1333  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1334  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1335  << " failed")
1336 }
1337 
1338 // --------------------------------------------------------------------------
1339 template<typename T>
1340 void teca_variant_array::get_dispatch(std::vector<T> &vals,
1341  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
1342 {
1343  // apply on POD types
1345  this,
1346  const TT *ptthis = dynamic_cast<const TT*>(this);
1347  ptthis->get(vals);
1348  return;
1349  )
1350 
1351  // unssuported type
1352  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1353  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1354  << " failed")
1355 }
1356 
1357 // --------------------------------------------------------------------------
1358 template<typename T>
1359 void teca_variant_array::get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
1360  typename std::enable_if<object_dispatch<T>::value, T>::type*) const
1361 {
1362  // only apply when types match
1363  const teca_variant_array_impl<T> *ptthis =
1364  dynamic_cast<const teca_variant_array_impl<T>*>(this);
1365 
1366  if (ptthis)
1367  {
1368  // safe. the types match
1369  ptthis->get(src_start, dest, dest_start, n_elem);
1370  return;
1371  }
1372 
1373  // types do not match
1374  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1375  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1376  << " failed")
1377 }
1378 
1379 // --------------------------------------------------------------------------
1380 template<typename T>
1381 void teca_variant_array::get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
1382  typename std::enable_if<pod_dispatch<T>::value, T>::type*) const
1383 {
1384  // apply on POD types
1386  this,
1387  const TT *ptthis = dynamic_cast<const TT*>(this);
1388  ptthis->get(src_start, dest, dest_start, n_elem);
1389  return;
1390  )
1391 
1392  // unssuported type
1393  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1394  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1395  << " failed")
1396 }
1397 
1398 // --------------------------------------------------------------------------
1399 template<typename T>
1400 void teca_variant_array::set_dispatch(unsigned long i, const T &val,
1401  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1402 {
1403  // only apply when types match
1404  teca_variant_array_impl<T> *ptthis =
1405  dynamic_cast<teca_variant_array_impl<T>*>(this);
1406 
1407  if (ptthis)
1408  {
1409  // safe. the types match
1410  ptthis->set(i, val);
1411  return;
1412  }
1413 
1414  // types do not match
1415  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1416  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1417  << " failed")
1418 }
1419 
1420 // --------------------------------------------------------------------------
1421 template<typename T>
1422 void teca_variant_array::set_dispatch(unsigned long i, const T &val,
1423  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1424 {
1425  // apply on POD types
1427  this,
1428  TT *ptthis = dynamic_cast<TT*>(this);
1429  ptthis->set(i, val);
1430  return;
1431  )
1432 
1433  // unssuported type
1434  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1435  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1436  << " failed")
1437 }
1438 
1439 // --------------------------------------------------------------------------
1440 template<typename T>
1441 void teca_variant_array::set_dispatch(const std::vector<T> &src,
1442  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1443 {
1444  // only apply when types match
1445  teca_variant_array_impl<T> *ptthis =
1446  dynamic_cast<teca_variant_array_impl<T>*>(this);
1447 
1448  if (ptthis)
1449  {
1450  // safe. the types match
1451  ptthis->set(src);
1452  return;
1453  }
1454 
1455  // types do not match
1456  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1457  << typeid(T).name() <<sizeof(T) << " to " << this->get_class_name()
1458  << " failed")
1459 }
1460 
1461 // --------------------------------------------------------------------------
1462 template<typename T>
1463 void teca_variant_array::set_dispatch(const std::vector<T> &src,
1464  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1465 {
1466  // apply on POD types
1468  this,
1469  TT *ptthis = dynamic_cast<TT*>(this);
1470  ptthis->set(src);
1471  return;
1472  )
1473 
1474  // unssuported type
1475  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1476  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1477  << " failed")
1478 }
1479 
1480 // --------------------------------------------------------------------------
1481 template<typename T>
1482 void teca_variant_array::set_dispatch(size_t dest_start,
1483  const T *src, size_t src_start, size_t n_elem,
1484  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1485 {
1486  // only apply when types match
1487  teca_variant_array_impl<T> *ptthis =
1488  dynamic_cast<teca_variant_array_impl<T>*>(this);
1489 
1490  if (ptthis)
1491  {
1492  // safe. the types match
1493  ptthis->set(dest_start, src, src_start, n_elem);
1494  return;
1495  }
1496 
1497  // types do not match
1498  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1499  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1500  << " failed")
1501 }
1502 
1503 // --------------------------------------------------------------------------
1504 template<typename T>
1505 void teca_variant_array::set_dispatch(size_t dest_start,
1506  const T *src, size_t src_start, size_t n_elem,
1507  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1508 {
1509  // apply on POD types
1511  this,
1512  TT *ptthis = dynamic_cast<TT*>(this);
1513  ptthis->set(dest_start, src, src_start, n_elem);
1514  return;
1515  )
1516 
1517  // unssuported type
1518  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1519  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1520  << " failed")
1521 }
1522 
1523 // --------------------------------------------------------------------------
1524 template<typename T>
1525 void teca_variant_array::assign_dispatch(const std::vector<T> &src,
1526  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1527 {
1528  // only apply when types match
1529  teca_variant_array_impl<T> *ptthis =
1530  dynamic_cast<teca_variant_array_impl<T>*>(this);
1531 
1532  if (ptthis)
1533  {
1534  // safe. the types match
1535  ptthis->assign(src);
1536  return;
1537  }
1538 
1539  // types do not match
1540  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1541  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1542  << " failed")
1543 }
1544 
1545 // --------------------------------------------------------------------------
1546 template<typename T>
1547 void teca_variant_array::assign_dispatch(const std::vector<T> &src,
1548  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1549 {
1550  // apply on POD types
1552  this,
1553  TT *ptthis = dynamic_cast<TT*>(this);
1554  ptthis->assign(src);
1555  return;
1556  )
1557 
1558  // unssuported type
1559  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1560  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1561  << " failed")
1562 }
1563 
1564 // --------------------------------------------------------------------------
1565 template<typename T>
1566 void teca_variant_array::assign_dispatch(const T *src, size_t src_start,
1567  size_t n_elem, typename std::enable_if<object_dispatch<T>::value, T>::type*)
1568 {
1569  // only apply when types match
1570  teca_variant_array_impl<T> *ptthis =
1571  dynamic_cast<teca_variant_array_impl<T>*>(this);
1572 
1573  if (ptthis)
1574  {
1575  // safe. the types match
1576  ptthis->assign(src, src_start, n_elem);
1577  return;
1578  }
1579 
1580  // types do not match
1581  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1582  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1583  << " failed")
1584 }
1585 
1586 // --------------------------------------------------------------------------
1587 template<typename T>
1588 void teca_variant_array::assign_dispatch(const T *src, size_t src_start, size_t n_elem,
1589  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1590 {
1591  // apply on POD types
1593  this,
1594  TT *ptthis = dynamic_cast<TT*>(this);
1595  ptthis->assign(src, src_start, n_elem);
1596  return;
1597  )
1598 
1599  // unssuported type
1600  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1601  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1602  << " failed")
1603 }
1604 
1605 // --------------------------------------------------------------------------
1606 template<typename T>
1607 void teca_variant_array::append_dispatch(const T &val,
1608  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1609 {
1610  // only apply when types match
1611  teca_variant_array_impl<T> *ptthis =
1612  dynamic_cast<teca_variant_array_impl<T>*>(this);
1613 
1614  if (ptthis)
1615  {
1616  // safe. the types match
1617  ptthis->append(val);
1618  return;
1619  }
1620 
1621  // types do not match
1622  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1623  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1624  << " failed")
1625 }
1626 
1627 // --------------------------------------------------------------------------
1628 template<typename T>
1629 void teca_variant_array::append_dispatch(const T &val,
1630  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1631 {
1632  // apply on POD types
1634  this,
1635  TT *ptthis = dynamic_cast<TT*>(this);
1636  ptthis->append(val);
1637  return;
1638  )
1639 
1640  // unssuported type
1641  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1642  << typeid(T).name() <<sizeof(T) << " to " << this->get_class_name()
1643  << " failed")
1644 }
1645 
1646 // --------------------------------------------------------------------------
1647 template<typename T>
1648 void teca_variant_array::append_dispatch(const std::vector<T> &src,
1649  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1650 {
1651  // only apply when types match
1652  teca_variant_array_impl<T> *ptthis =
1653  dynamic_cast<teca_variant_array_impl<T>*>(this);
1654 
1655  if (ptthis)
1656  {
1657  // safe. the types match
1658  ptthis->append(src);
1659  return;
1660  }
1661 
1662  // types do not match
1663  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1664  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1665  << " failed")
1666 }
1667 
1668 // --------------------------------------------------------------------------
1669 template<typename T>
1670 void teca_variant_array::append_dispatch(const std::vector<T> &src,
1671  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1672 {
1673  // apply on POD types
1675  this,
1676  TT *ptthis = dynamic_cast<TT*>(this);
1677  ptthis->append(src);
1678  return;
1679  )
1680 
1681  // unssuported type
1682  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1683  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1684  << " failed")
1685 }
1686 
1687 // --------------------------------------------------------------------------
1688 template<typename T>
1689 void teca_variant_array::append_dispatch(const T *src, size_t src_start, size_t n_elem,
1690  typename std::enable_if<object_dispatch<T>::value, T>::type*)
1691 {
1692  // only apply when types match
1693  teca_variant_array_impl<T> *ptthis =
1694  dynamic_cast<teca_variant_array_impl<T>*>(this);
1695 
1696  if (ptthis)
1697  {
1698  // safe. the types match
1699  ptthis->append(src, src_start, n_elem);
1700  return;
1701  }
1702 
1703  // types do not match
1704  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1705  << typeid(T).name() << sizeof(T) << " to " << this->get_class_name()
1706  << " failed")
1707 }
1708 
1709 // --------------------------------------------------------------------------
1710 template<typename T>
1711 void teca_variant_array::append_dispatch(const T *src, size_t src_start, size_t n_elem,
1712  typename std::enable_if<pod_dispatch<T>::value, T>::type*)
1713 {
1714  // apply on POD types
1716  this,
1717  TT *ptthis = dynamic_cast<TT*>(this);
1718  ptthis->append(src, src_start, n_elem);
1719  return;
1720  )
1721 
1722  // unssuported type
1723  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1724  << typeid(T).name() <<sizeof(T) << " to " << this->get_class_name()
1725  << " failed")
1726 }
1727 
1728 
1729 
1730 
1731 // --------------------------------------------------------------------------
1732 template<typename T>
1734 {
1735  this->clear();
1736 }
1737 
1738 // --------------------------------------------------------------------------
1739 template<typename T>
1741 {
1742  return std::make_shared<teca_variant_array_impl<T>>(alloc);
1743 }
1744 
1745 // --------------------------------------------------------------------------
1746 template<typename T>
1748 {
1749  return std::make_shared<teca_variant_array_impl<T>>(alloc, n);
1750 }
1751 
1752 // --------------------------------------------------------------------------
1753 template<typename T>
1754 template<typename U>
1756  const U &v, allocator alloc)
1757 {
1758  return std::make_shared<teca_variant_array_impl<T>>(alloc, n, v);
1759 }
1760 
1761 // --------------------------------------------------------------------------
1762 template<typename T>
1763 template<typename U>
1765  const U *v, allocator alloc)
1766 {
1767  return std::make_shared<teca_variant_array_impl<T>>(alloc, n, v);
1768 }
1769 
1770 // --------------------------------------------------------------------------
1771 template<typename T>
1772 template <typename delete_func_t>
1774  T *ptr, allocator alloc, int owner, delete_func_t df)
1775 {
1776  return std::make_shared<teca_variant_array_impl<T>>
1777  (alloc, n, owner, ptr, df);
1778 }
1779 
1780 // --------------------------------------------------------------------------
1781 template<typename T>
1783 {
1784  if (alloc == allocator::same)
1785  alloc = static_cast<allocator>(m_data.get_allocator());
1786 
1787  return std::make_shared<teca_variant_array_impl<T>>
1788  (alloc, this->shared_from_this());
1789 }
1790 
1791 // --------------------------------------------------------------------------
1792 template<typename T>
1794  size_t n_elem, allocator alloc) const
1795 {
1796  if (alloc == allocator::same)
1797  alloc = static_cast<allocator>(m_data.get_allocator());
1798 
1800  std::make_shared<teca_variant_array_impl<T>>
1801  (alloc, n_elem);
1802 
1803  this->get(src_start, dest, 0, n_elem);
1804 
1805  return dest;
1806 }
1807 
1808 // --------------------------------------------------------------------------
1809 template<typename T>
1811 {
1812  if (alloc == allocator::same)
1813  alloc = static_cast<allocator>(m_data.get_allocator());
1814 
1815  return std::make_shared<teca_variant_array_impl<T>>(alloc);
1816 }
1817 
1818 // --------------------------------------------------------------------------
1819 template<typename T>
1821  allocator alloc) const
1822 {
1823  if (alloc == allocator::same)
1824  alloc = static_cast<allocator>(m_data.get_allocator());
1825 
1826  return std::make_shared<teca_variant_array_impl<T>>(alloc, n);
1827 }
1828 
1829 // --------------------------------------------------------------------------
1830 template<typename T>
1832 {
1833  // if the allocator is already in use do nothing
1834  if (this->m_data.get_allocator() == alloc)
1835  return 0;
1836 
1837  // move the data using the specified allocator
1838  hamr::buffer<T> tmp(alloc, m_data);
1839  m_data = std::move(tmp);
1840 
1841  return 0;
1842 }
1843 
1844 // --------------------------------------------------------------------------
1845 template<typename T>
1847 {
1848  p_teca_variant_array_impl<T> pt_other =
1849  std::dynamic_pointer_cast<teca_variant_array_impl<T>>(other);
1850 
1851  if (pt_other)
1852  {
1853  m_data.swap(pt_other->m_data);
1854  }
1855 
1856  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1857  << other->get_class_name() << sizeof(T) << " to " << this->get_class_name()
1858  << " failed")
1859 }
1860 
1861 // --------------------------------------------------------------------------
1862 template<typename T>
1864 {
1865  const char *element_name = typeid(T).name();
1866  size_t element_size = sizeof(T);
1867  std::ostringstream oss;
1868  oss << "teca_variant_array_impl<" << element_name
1869  << element_size << ">";
1870  return oss.str();
1871 }
1872 
1873 // --------------------------------------------------------------------------
1874 template<typename T>
1875 unsigned long teca_variant_array_impl<T>::size() const noexcept
1876 {
1877  return m_data.size();
1878 }
1879 
1880 // --------------------------------------------------------------------------
1881 template<typename T>
1883 {
1884  m_data.resize(n);
1885 }
1886 
1887 // --------------------------------------------------------------------------
1888 template<typename T>
1889 void teca_variant_array_impl<T>::resize(unsigned long n, const T &val)
1890 {
1891  m_data.resize(n, val);
1892 }
1893 
1894 // --------------------------------------------------------------------------
1895 template<typename T>
1897 {
1898  m_data.reserve(n);
1899 }
1900 
1901 // --------------------------------------------------------------------------
1902 template<typename T>
1904 {
1905  m_data.free();
1906 }
1907 
1908 // --------------------------------------------------------------------------
1909 template <typename T>
1910 template <typename U>
1911 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
1912  const p_teca_variant_array_impl<U> &dest, size_t dest_start, size_t n_elem,
1913  typename std::enable_if<object_dispatch<U>::value, U>::type*) const
1914 {
1915  // only act on arrays of the same type
1917  std::dynamic_pointer_cast<teca_variant_array_impl<T>>(dest);
1918 
1919  if (tp_dest)
1920  {
1921  m_data.get(src_start, tp_dest->m_data, dest_start, n_elem);
1922  return;
1923  }
1924 
1925  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1926  << dest->get_class_name() << " to " << this->get_class_name()
1927  << " failed")
1928 }
1929 
1930 // --------------------------------------------------------------------------
1931 template <typename T>
1932 template <typename U>
1933 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
1934  const p_teca_variant_array_impl<U> &dest, size_t dest_start, size_t n_elem,
1935  typename std::enable_if<pod_dispatch<U>::value, U>::type*) const
1936 {
1937  assert(dest->size() >= dest_start + n_elem);
1938  assert(this->size() >= src_start + n_elem);
1939  m_data.get(src_start, dest->m_data, dest_start, n_elem);
1940 }
1941 
1942 // --------------------------------------------------------------------------
1943 template <typename T>
1944 template <typename U>
1945 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
1946  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
1947  typename std::enable_if<object_dispatch<U>::value, U>::type*)
1948 {
1949  // only act on arrays of the same type
1951  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
1952 
1953  if (tp_src)
1954  {
1955  m_data.set(dest_start, tp_src->m_data, src_start, n_elem);
1956 
1957  return;
1958  }
1959 
1960  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1961  << src->get_class_name() << " to " << this->get_class_name()
1962  << " failed")
1963 }
1964 
1965 // --------------------------------------------------------------------------
1966 template <typename T>
1967 template <typename U>
1968 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
1969  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
1970  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
1971 {
1972  m_data.set(dest_start, src->m_data, src_start, n_elem);
1973 }
1974 
1975 // --------------------------------------------------------------------------
1976 template <typename T>
1977 template <typename U>
1979  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
1980  typename std::enable_if<object_dispatch<U>::value, U>::type*)
1981 {
1982  // only act on arrays of the same type
1984  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
1985 
1986  if (tp_src)
1987  {
1988  m_data.assign(tp_src->m_data, src_start, n_elem);
1989  return;
1990  }
1991 
1992  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
1993  << src->get_class_name() << " to " << this->get_class_name()
1994  << " failed")
1995 }
1996 
1997 // --------------------------------------------------------------------------
1998 template <typename T>
1999 template <typename U>
2001  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
2002  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2003 {
2004  m_data.assign(src->m_data, src_start, n_elem);
2005 }
2006 
2007 // --------------------------------------------------------------------------
2008 template <typename T>
2009 template <typename U>
2011  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
2012  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2013 {
2014  // only act on arrays of the same type
2016  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
2017 
2018  if (tp_src)
2019  {
2020  m_data.append(tp_src->m_data, src_start, n_elem);
2021  return;
2022  }
2023 
2024  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2025  << src->get_class_name() << " to " << this->get_class_name()
2026  << " failed")
2027 }
2028 
2029 // --------------------------------------------------------------------------
2030 template <typename T>
2031 template <typename U>
2033  const const_p_teca_variant_array_impl<U> &src, size_t src_start, size_t n_elem,
2034  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2035 {
2036  m_data.append(src->m_data, src_start, n_elem);
2037 }
2038 
2039 // --------------------------------------------------------------------------
2040 template <typename T>
2041 template <typename U>
2042 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
2043  const p_teca_variant_array &dest, size_t dest_start, size_t n_elem,
2044  typename std::enable_if<object_dispatch<U>::value, U>::type*) const
2045 {
2046  // only act on arrays of the same type
2048  std::dynamic_pointer_cast<teca_variant_array_impl<T>>(dest);
2049 
2050  if (tp_dest)
2051  {
2052  this->get_dispatch(src_start, tp_dest, dest_start, n_elem);
2053  return;
2054  }
2055 
2056  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2057  << dest->get_class_name() << " to " << this->get_class_name()
2058  << " failed")
2059 }
2060 
2061 // --------------------------------------------------------------------------
2062 template <typename T>
2063 template <typename U>
2064 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
2065  const p_teca_variant_array &dest, size_t dest_start, size_t n_elem,
2066  typename std::enable_if<pod_dispatch<U>::value, U>::type*) const
2067 {
2069  dest.get(),
2070  std::shared_ptr<TT> tp_dest = std::static_pointer_cast<TT>(dest);
2071  this->get_dispatch(src_start, tp_dest, dest_start, n_elem);
2072  return;
2073  )
2074 
2075  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2076  << dest->get_class_name() << " to " << this->get_class_name()
2077  << " failed")
2078 }
2079 
2080 // --------------------------------------------------------------------------
2081 template <typename T>
2082 template <typename U>
2083 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
2084  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2085  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2086 {
2087  // only act on arrays of the same type
2089  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
2090 
2091  if (tp_src)
2092  {
2093  this->set_dispatch(dest_start, tp_src, src_start, n_elem);
2094  return;
2095  }
2096 
2097  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2098  << src->get_class_name() << " to " << this->get_class_name()
2099  << " failed")
2100 }
2101 
2102 // --------------------------------------------------------------------------
2103 template <typename T>
2104 template <typename U>
2105 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
2106  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2107  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2108 {
2110  src.get(),
2112  std::static_pointer_cast<const teca_variant_array_impl<NT>>(src);
2113  //std::shared_ptr<TT> tp_src = std::static_pointer_cast<TT>(src);
2114  this->set_dispatch(dest_start, tp_src, src_start, n_elem);
2115  return;
2116  )
2117 
2118  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2119  << src->get_class_name() << " to " << this->get_class_name()
2120  << " failed")
2121 }
2122 
2123 // --------------------------------------------------------------------------
2124 template <typename T>
2125 template <typename U>
2127  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2128  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2129 {
2130  // only act on arrays of the same type
2132  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
2133 
2134  if (tp_src)
2135  {
2136  this->assign_dispatch(tp_src, src_start, n_elem);
2137  return;
2138  }
2139 
2140  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2141  << src->get_class_name() << " to " << this->get_class_name()
2142  << " failed")
2143 }
2144 
2145 // --------------------------------------------------------------------------
2146 template <typename T>
2147 template <typename U>
2149  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2150  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2151 {
2153  src.get(),
2154  std::shared_ptr<const TT> tp_src = std::static_pointer_cast<const TT>(src);
2155  this->assign_dispatch(tp_src, src_start, n_elem);
2156  return;
2157  )
2158 
2159  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2160  << src->get_class_name() << " to " << this->get_class_name()
2161  << " failed")
2162 }
2163 
2164 // --------------------------------------------------------------------------
2165 template <typename T>
2166 template <typename U>
2168  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2169  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2170 {
2171  // only act on arrays of the same type
2173  std::dynamic_pointer_cast<const teca_variant_array_impl<T>>(src);
2174 
2175  if (tp_src)
2176  {
2177  this->append_dispatch(tp_src, src_start, n_elem);
2178  return;
2179  }
2180 
2181  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2182  << src->get_class_name() << " to " << this->get_class_name()
2183  << " failed")
2184 }
2185 
2186 // --------------------------------------------------------------------------
2187 template <typename T>
2188 template <typename U>
2190  const const_p_teca_variant_array &src, size_t src_start, size_t n_elem,
2191  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2192 {
2194  src.get(),
2195  std::shared_ptr<const TT> tp_src = std::static_pointer_cast<const TT>(src);
2196  this->append_dispatch(tp_src, src_start, n_elem);
2197  return;
2198  )
2199 
2200  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2201  << src->get_class_name() << " to " << this->get_class_name()
2202  << " failed")
2203 }
2204 
2205 // --------------------------------------------------------------------------
2206 template <typename T>
2207 template <typename U>
2208 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
2209  U *dest, size_t dest_start, size_t n_elem,
2210  typename std::enable_if<object_dispatch<U>::value, U>::type*) const
2211 {
2212  // only act on arrays of the same type
2213  const teca_variant_array_impl<U> *thisu =
2214  dynamic_cast<const teca_variant_array_impl<U>*>(this);
2215 
2216  if (thisu)
2217  {
2218  thisu->m_data.get(src_start, dest, dest_start, n_elem);
2219  return;
2220  }
2221 
2222  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2223  << safe_class_name(this) << " to " << safe_pointer_name(dest)
2224  << " failed")
2225 }
2226 
2227 // --------------------------------------------------------------------------
2228 template <typename T>
2229 template <typename U>
2230 void teca_variant_array_impl<T>::get_dispatch(size_t src_start,
2231  U *dest, size_t dest_start, size_t n_elem,
2232  typename std::enable_if<pod_dispatch<U>::value, U>::type*) const
2233 {
2234  m_data.get(src_start, dest, dest_start, n_elem);
2235 }
2236 
2237 // --------------------------------------------------------------------------
2238 template <typename T>
2239 template <typename U>
2240 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
2241  const U *src, size_t src_start, size_t n_elem,
2242  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2243 {
2244  // only act on arrays of the same type
2246  dynamic_cast<teca_variant_array_impl<U>*>(this);
2247 
2248  if (thisu)
2249  {
2250  thisu->m_data.set(dest_start, src, src_start, n_elem);
2251  return;
2252  }
2253 
2254  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2255  << safe_class_name(this) << " to " << safe_pointer_name(src)
2256  << " failed")
2257 }
2258 
2259 // --------------------------------------------------------------------------
2260 template <typename T>
2261 template <typename U>
2262 void teca_variant_array_impl<T>::set_dispatch(size_t dest_start,
2263  const U *src, size_t src_start, size_t n_elem,
2264  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2265 {
2266  m_data.set(dest_start, src, src_start, n_elem);
2267 }
2268 
2269 // --------------------------------------------------------------------------
2270 template <typename T>
2271 template <typename U>
2273  const U *src, size_t src_start, size_t n_elem,
2274  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2275 {
2276  // only act on arrays of the same type
2278  dynamic_cast<teca_variant_array_impl<U>*>(this);
2279 
2280  if (thisu)
2281  {
2282  thisu->m_data.assign(src, src_start, n_elem);
2283  return;
2284  }
2285 
2286  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2287  << safe_class_name(this) << " to " << safe_pointer_name(src)
2288  << " failed")
2289 }
2290 
2291 // --------------------------------------------------------------------------
2292 template <typename T>
2293 template <typename U>
2295  const U *src, size_t src_start, size_t n_elem,
2296  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2297 {
2298  m_data.assign(src, src_start, n_elem);
2299 }
2300 
2301 // --------------------------------------------------------------------------
2302 template <typename T>
2303 template <typename U>
2305  const U *src, size_t src_start, size_t n_elem,
2306  typename std::enable_if<object_dispatch<U>::value, U>::type*)
2307 {
2308  // only act on arrays of the same type
2310  dynamic_cast<teca_variant_array_impl<U>*>(this);
2311 
2312  if (thisu)
2313  {
2314  thisu->m_data.append(src, src_start, n_elem);
2315  return;
2316  }
2317 
2318  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2319  << safe_class_name(this) << " to " << safe_pointer_name(src)
2320  << " failed")
2321 }
2322 
2323 // --------------------------------------------------------------------------
2324 template <typename T>
2325 template <typename U>
2327  const U *src, size_t src_start, size_t n_elem,
2328  typename std::enable_if<pod_dispatch<U>::value, U>::type*)
2329 {
2330  m_data.append(src, src_start, n_elem);
2331 }
2332 
2333 
2334 
2335 
2336 // --------------------------------------------------------------------------
2337 template<typename T>
2339 {
2340  using NT = T;
2341  using TT = teca_variant_array_impl<T>;
2342  const TT *other_t = dynamic_cast<const TT*>(other.get());
2343  if (other_t)
2344  {
2345  size_t n_elem = this->size();
2346 
2347  if (n_elem != other_t->size())
2348  return false;
2349 
2350  auto spthis = this->get_host_accessible();
2351  const NT *pthis = spthis.get();
2352 
2353  auto spother = other_t->get_host_accessible();
2354  const NT *pother = spother.get();
2355 
2356  sync_host_access_any(this, other);
2357 
2358  for (size_t i = 0; i < n_elem; ++i)
2359  {
2360  if (pthis[i] != pother[i])
2361  return false;
2362  }
2363 
2364  return true;
2365  }
2366  TECA_FATAL_ERROR("Operation on incompatible types. The cast from "
2367  << safe_class_name(other.get()) << " to " << safe_class_name(this)
2368  << " failed")
2369  return false;
2370 }
2371 
2372 // --------------------------------------------------------------------------
2373 template<typename T>
2374  template <typename U>
2376  typename std::enable_if<pack_array<U>::value, U>::type*) const
2377 {
2378  // access the data on the host
2379  std::shared_ptr<const T> pdata = this->get_host_accessible();
2380  sync_host_access_any(this);
2381 
2382  // pack the size
2383  unsigned long long n_elem = this->size();
2384  s.pack(n_elem);
2385 
2386  // pack the data
2387  s.pack(pdata.get(), n_elem);
2388 }
2389 
2390 // --------------------------------------------------------------------------
2391 template<typename T>
2392  template <typename U>
2394  typename std::enable_if<pack_array<U>::value, U>::type*)
2395 {
2396  // unpack the size
2397  unsigned long long n_elem = 0;
2398  s.unpack(n_elem);
2399 
2400  // allocate a buffer
2401  hamr::buffer<T> tmp(allocator::malloc, n_elem);
2402  std::shared_ptr<T> sptmp = tmp.pointer();
2403 
2404  // unpack the elements into the buffer
2405  s.unpack(sptmp.get(), n_elem);
2406 
2407  // update the array
2408  m_data = std::move(tmp);
2409 }
2410 
2411 // --------------------------------------------------------------------------
2412 template<typename T>
2413  template <typename U>
2415  typename std::enable_if<pack_object<U>::value, U>::type*) const
2416 {
2417  // pack the size
2418  unsigned long long n_elem = this->size();
2419  s.pack(n_elem);
2420 
2421  // pack the data from the CPU
2422  std::shared_ptr<const T> data = this->get_host_accessible();
2423  const T *pdata = data.get();
2424 
2425  sync_host_access_any(this);
2426 
2427  for (unsigned long long i = 0; i < n_elem; ++i)
2428  {
2429  pdata[i].to_stream(s);
2430  }
2431 }
2432 
2433 // --------------------------------------------------------------------------
2434 template<typename T>
2435  template <typename U>
2437  teca_binary_stream &s,
2438  typename std::enable_if<pack_object<U>::value, U>::type*)
2439 {
2440  // unpack the size
2441  unsigned long long n_elem = 0;
2442  s.unpack(n_elem);
2443 
2444  // always unpack the data to the CPU
2445  std::vector<T> tmp(n_elem);
2446  for (unsigned long long i = 0; i < n_elem; ++i)
2447  {
2448  tmp[i].from_stream(s);
2449  }
2450 
2451  // copy to the active device
2452  m_data.assign(tmp.data(), 0, n_elem);
2453 }
2454 
2455 // --------------------------------------------------------------------------
2456 template<typename T>
2457  template <typename U>
2459  teca_binary_stream &s,
2460  typename std::enable_if<pack_object_ptr<U>::value, U>::type*) const
2461 {
2462  // pack the size
2463  unsigned long long n_elem = this->size();
2464  s.pack(n_elem);
2465 
2466  // pack the data from the CPU
2467  std::shared_ptr<const T> data = this->get_host_accessible();
2468  const T *pdata = data.get();
2469 
2470  sync_host_access_any(this);
2471 
2472  for (unsigned long long i = 0; i < n_elem; ++i)
2473  {
2474  pdata[i]->to_stream(s);
2475  }
2476 }
2477 
2478 // --------------------------------------------------------------------------
2479 template<typename T>
2480  template <typename U>
2482  teca_binary_stream &s,
2483  typename std::enable_if<pack_object_ptr<U>::value, U>::type*)
2484 {
2485  // unpack the size
2486  unsigned long long n_elem = 0;
2487  s.unpack(n_elem);
2488 
2489  // unpack to the CPU
2490  std::vector<T> tmp(n_elem);
2491  for (unsigned long long i=0; i < n_elem; ++i)
2492  {
2493  tmp[i]->from_stream(s);
2494  }
2495 
2496  // copy to the active device
2497  m_data.assign(tmp.data(), 0, n_elem);
2498 }
2499 
2500 #define STR_DELIM(_a, _b) \
2501  (std::is_same<T, std::string>::value ? _a : _b)
2502 
2503 // --------------------------------------------------------------------------
2504 template<typename T>
2505  template <typename U>
2507  std::ostream &s,
2508  typename std::enable_if<pack_array<U>::value, U>::type*) const
2509 {
2510  size_t n_elem = this->size();
2511  if (n_elem)
2512  {
2513  // serialize from the CPU
2514  std::shared_ptr<const T> data = this->get_host_accessible();
2515  const T *pdata = data.get();
2516 
2517  sync_host_access_any(this);
2518 
2519  s << STR_DELIM("\"", "") << pdata[0] << STR_DELIM("\"", "");
2520 
2521  for (size_t i = 1; i < n_elem; ++i)
2522  {
2523  s << STR_DELIM(", \"", ", ") << pdata[i] << STR_DELIM("\"", "");
2524  }
2525  }
2526 }
2527 
2528 // --------------------------------------------------------------------------
2529 template<typename T>
2530  template <typename U>
2532  std::ostream &,
2533  typename std::enable_if<pack_array<U>::value, U>::type*)
2534 {
2535  // TODO
2536 }
2537 
2538 // --------------------------------------------------------------------------
2539 template<typename T>
2540  template <typename U>
2542  std::ostream &s,
2543  typename std::enable_if<pack_object<U>::value, U>::type*) const
2544 {
2545  size_t n_elem = this->m_data.size();
2546  if (n_elem)
2547  {
2548  // serialize from the CPU
2549  std::shared_ptr<const T> data = this->get_host_accessible();
2550  const T *pdata = data.get();
2551 
2552  sync_host_access_any(this);
2553 
2554  s << "{";
2555  pdata[0].to_stream(s);
2556  s << "}";
2557  for (size_t i = 1; i < n_elem; ++i)
2558  {
2559  s << ", {";
2560  pdata[i].to_stream(s);
2561  s << "}";
2562  }
2563  }
2564 }
2565 
2566 // --------------------------------------------------------------------------
2567 template<typename T>
2568  template <typename U>
2570  std::ostream &,
2571  typename std::enable_if<pack_object<U>::value, U>::type*)
2572 {
2573  // TODO
2574 }
2575 
2576 // --------------------------------------------------------------------------
2577 template<typename T>
2578  template <typename U>
2580  std::ostream &s,
2581  typename std::enable_if<pack_object_ptr<U>::value, U>::type*) const
2582 {
2583  size_t n_elem = this->m_data.size();
2584  if (n_elem)
2585  {
2586  // serialize from the CPU
2587  std::shared_ptr<const T> data = this->get_host_accessible();
2588  const T *pdata = data.get();
2589 
2590  sync_host_access_any(this);
2591 
2592  s << "{";
2593  pdata[0]->to_stream(s);
2594  s << "}";
2595  for (size_t i = 1; i < n_elem; ++i)
2596  {
2597  s << ", {";
2598  pdata[i]->to_stream(s);
2599  s << "}";
2600  }
2601  }
2602 }
2603 
2604 // --------------------------------------------------------------------------
2605 template<typename T>
2606  template <typename U>
2608  std::ostream &,
2609  typename std::enable_if<pack_object_ptr<U>::value, U>::type*)
2610 {
2611  // TODO
2612 }
2613 
2614 /// @cond
2615 template <typename T>
2616 struct TECA_EXPORT teca_variant_array_code {};
2617 
2618 template <unsigned int I>
2619 struct TECA_EXPORT teca_variant_array_new {};
2620 
2621 template <unsigned int I>
2622 struct TECA_EXPORT teca_variant_array_type {};
2623 
2624 #define TECA_VARIANT_ARRAY_TT_SPEC(T, v) \
2625 template <> \
2626 struct teca_variant_array_code<T> \
2627 { \
2628  static constexpr unsigned int get() \
2629  { return v; } \
2630 }; \
2631 template <> \
2632 struct teca_variant_array_new<v> \
2633 { \
2634  using allocator = teca_variant_array::allocator; \
2635  \
2636  static p_teca_variant_array_impl<T> New(allocator alloc) \
2637  { return teca_variant_array_impl<T>::New(alloc); } \
2638 }; \
2639 template <> \
2640 struct teca_variant_array_type<v> \
2641 { \
2642  using type = T; \
2643  \
2644  static constexpr const char *name() \
2645  { return #T; } \
2646 };
2647 
2648 #define TECA_VARIANT_ARRAY_FACTORY_NEW(_v) \
2649  case _v: \
2650  return teca_variant_array_new<_v>::New(alloc);
2651 
2652 #include "teca_metadata.h"
2653 class teca_metadata;
2654 
2655 TECA_VARIANT_ARRAY_TT_SPEC(char, 1)
2656 TECA_VARIANT_ARRAY_TT_SPEC(unsigned char, 2)
2657 TECA_VARIANT_ARRAY_TT_SPEC(int, 3)
2658 TECA_VARIANT_ARRAY_TT_SPEC(unsigned int, 4)
2659 TECA_VARIANT_ARRAY_TT_SPEC(short int, 5)
2660 TECA_VARIANT_ARRAY_TT_SPEC(short unsigned int, 6)
2661 TECA_VARIANT_ARRAY_TT_SPEC(long, 7)
2662 TECA_VARIANT_ARRAY_TT_SPEC(unsigned long, 8)
2663 TECA_VARIANT_ARRAY_TT_SPEC(long long, 9)
2664 TECA_VARIANT_ARRAY_TT_SPEC(unsigned long long, 10)
2665 TECA_VARIANT_ARRAY_TT_SPEC(float, 11)
2666 TECA_VARIANT_ARRAY_TT_SPEC(double, 12)
2667 TECA_VARIANT_ARRAY_TT_SPEC(std::string, 13)
2668 TECA_VARIANT_ARRAY_TT_SPEC(teca_metadata, 14)
2669 TECA_VARIANT_ARRAY_TT_SPEC(p_teca_variant_array, 15)
2670 /// @endcond
2671 
2672 /** @brief Creates an instance of teca_variant_array_impl<T> where T is
2673  * determined from the type code.
2674  */
2676 {
2677  using allocator = teca_variant_array::allocator;
2678 
2679  /** Construct a new variant array.
2680  * @param[in] type_code the type of array to construct
2681  * @param[in] alloc the allocator to use
2682  * @returns a new variant array or a nullptr if the type_code was invalid.
2683  */
2684  static p_teca_variant_array New(unsigned int type_code,
2685  allocator alloc = allocator::malloc)
2686  {
2687  switch (type_code)
2688  {
2689  TECA_VARIANT_ARRAY_FACTORY_NEW(1)
2690  TECA_VARIANT_ARRAY_FACTORY_NEW(2)
2691  TECA_VARIANT_ARRAY_FACTORY_NEW(3)
2692  TECA_VARIANT_ARRAY_FACTORY_NEW(4)
2693  TECA_VARIANT_ARRAY_FACTORY_NEW(5)
2694  TECA_VARIANT_ARRAY_FACTORY_NEW(6)
2695  TECA_VARIANT_ARRAY_FACTORY_NEW(7)
2696  TECA_VARIANT_ARRAY_FACTORY_NEW(8)
2697  TECA_VARIANT_ARRAY_FACTORY_NEW(9)
2698  TECA_VARIANT_ARRAY_FACTORY_NEW(10)
2699  TECA_VARIANT_ARRAY_FACTORY_NEW(11)
2700  TECA_VARIANT_ARRAY_FACTORY_NEW(12)
2701  TECA_VARIANT_ARRAY_FACTORY_NEW(13)
2702  TECA_VARIANT_ARRAY_FACTORY_NEW(14)
2703  TECA_VARIANT_ARRAY_FACTORY_NEW(15)
2704  default:
2705  TECA_ERROR("Failed to create a teca_variant_array,"
2706  " unknown code " << type_code)
2707  }
2708  return nullptr;
2709  }
2710 };
2711 
2712 /// @cond
2713 #define CODE_DISPATCH_CASE(_v, _c, _code) \
2714  if (_v == _c) \
2715  { \
2716  using NT = teca_variant_array_type<_c>::type; \
2717  using TT = teca_variant_array_impl<NT>; \
2718  _code \
2719  }
2720 
2721 #define CODE_DISPATCH_I(_v, _code) \
2722  CODE_DISPATCH_CASE(_v, 1, _code) \
2723  else CODE_DISPATCH_CASE(_v, 2, _code) \
2724  else CODE_DISPATCH_CASE(_v, 3, _code) \
2725  else CODE_DISPATCH_CASE(_v, 4, _code) \
2726  else CODE_DISPATCH_CASE(_v, 5, _code) \
2727  else CODE_DISPATCH_CASE(_v, 6, _code) \
2728  else CODE_DISPATCH_CASE(_v, 7, _code) \
2729  else CODE_DISPATCH_CASE(_v, 8, _code) \
2730  else CODE_DISPATCH_CASE(_v, 9, _code) \
2731  else CODE_DISPATCH_CASE(_v, 10, _code)
2732 
2733 #define CODE_DISPATCH_FP(_v, _code) \
2734  CODE_DISPATCH_CASE(_v, 11, _code) \
2735  else CODE_DISPATCH_CASE(_v, 12, _code)
2736 
2737 #define CODE_DISPATCH_CLASS(_v, _code) \
2738  CODE_DISPATCH_CASE(_v, 13, _code) \
2739  else CODE_DISPATCH_CASE(_v, 14, _code) \
2740  else CODE_DISPATCH_CASE(_v, 15, _code)
2741 
2742 #define CODE_DISPATCH(_v, _code) \
2743  CODE_DISPATCH_I(_v, _code) \
2744  else CODE_DISPATCH_FP(_v, _code)
2745 
2746 /// @endcond
2747 
2748 // --------------------------------------------------------------------------
2749 template <typename T>
2750 unsigned int teca_variant_array_impl<T>::type_code() const noexcept
2751 {
2752  return teca_variant_array_code<T>::get();
2753 }
2754 
2755 // **************************************************************************
2756 template <typename T>
2758 T min(const const_p_teca_variant_array_impl<T> &a)
2759 {
2760  size_t n_elem = a->size();
2761  T mn = std::numeric_limits<T>::max();
2762 #if defined(TECA_HAS_CUDA)
2763  if (a->cuda_accessible())
2764  {
2765  std::shared_ptr<const T> data = a->get_cuda_accessible();
2766  thrust::device_ptr<const T> pdata(data.get());
2767  mn = thrust::reduce(pdata, pdata + n_elem, mn, thrust::minimum<T>());
2768  }
2769  else
2770  {
2771 #endif
2772  std::shared_ptr<const T> data = a->get_cuda_accessible();
2773  const T *pdata = data.get();
2774  for (size_t i = 0; i < n_elem; ++i)
2775  mn = mn > pdata[i] ? pdata[i] : mn;
2776 #if defined(TECA_HAS_CUDA)
2777  }
2778 #endif
2779  return mn;
2780 }
2781 
2782 // **************************************************************************
2783 template <typename T>
2785 T min(const p_teca_variant_array_impl<T> &a)
2786 {
2787  return min(const_p_teca_variant_array_impl<T>(a));
2788 }
2789 
2790 // **************************************************************************
2791 template <typename T>
2793 T max(const const_p_teca_variant_array_impl<T> &a)
2794 {
2795  size_t n_elem = a->size();
2796  T mx = std::numeric_limits<T>::lowest();
2797 #if defined(TECA_HAS_CUDA)
2798  if (a->cuda_accessible())
2799  {
2800  std::shared_ptr<const T> data = a->get_cuda_accessible();
2801  thrust::device_ptr<const T> pdata(data.get());
2802  mx = thrust::reduce(pdata, pdata + n_elem, mx, thrust::maximum<T>());
2803  }
2804  else
2805  {
2806 #endif
2807  std::shared_ptr<const T> data = a->get_cuda_accessible();
2808  const T *pdata = data.get();
2809  for (size_t i = 0; i < n_elem; ++i)
2810  mx = mx < pdata[i] ? pdata[i] : mx;
2811 #if defined(TECA_HAS_CUDA)
2812  }
2813 #endif
2814  return mx;
2815 }
2816 
2817 // **************************************************************************
2818 template <typename T>
2820 T max(const p_teca_variant_array_impl<T> &a)
2821 {
2822  return max(const_p_teca_variant_array_impl<T>(a));
2823 }
2824 
2825 #if defined(__CUDACC__)
2826 #pragma nv_diag_default = partial_override
2827 #endif
2828 #endif
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:17
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:22
The concrete implementation of our type agnostic container for contiguous arrays.
Definition: teca_variant_array_impl.h:380
std::shared_ptr< T > & pointer()
Definition: teca_variant_array_impl.h:840
void get(size_t src_start, U *dest, size_t dest_start, size_t n_elem) const
get a range of values
Definition: teca_variant_array_impl.h:536
void set(const const_p_teca_variant_array_impl< U > &src)
Set from the other array.
Definition: teca_variant_array_impl.h:642
void append(const const_p_teca_variant_array &src) override
Definition: teca_variant_array_impl.h:763
int cuda_accessible() const noexcept override
returns true if the data is accessible from CUDA codes
Definition: teca_variant_array_impl.h:843
int host_accessible() const noexcept override
returns true if the data is accessible from codes running on the CPU
Definition: teca_variant_array_impl.h:846
void debug_print(typename std::enable_if<!std::is_arithmetic< U >::value >::type *=0) const
Print the contents of the buffer for debugging.
Definition: teca_variant_array_impl.h:902
void set(const std::vector< U > &src)
set from a vector of values
Definition: teca_variant_array_impl.h:601
teca_variant_array_impl(allocator alloc, size_t n_elem)
construct with preallocated size
Definition: teca_variant_array_impl.h:927
teca_variant_array_impl(allocator alloc, const const_p_teca_variant_array_impl< U > &other)
copy construct from an instance of different type
Definition: teca_variant_array_impl.h:941
void copy(const const_p_teca_variant_array_impl< U > &src, size_t src_start, size_t n_elem)
copy a subset of the other array
Definition: teca_variant_array_impl.h:728
teca_variant_array_impl(allocator alloc, size_t n_elem, const U *vals)
construct with preallocated size and initialized to a specific value
Definition: teca_variant_array_impl.h:936
void get(size_t i, U &val) const
Definition: teca_variant_array_impl.h:512
void reserve(unsigned long n) override
Reserve space.
Definition: teca_variant_array_impl.h:1896
void get(const p_teca_variant_array &dest) const override
get the contents into the other array.
Definition: teca_variant_array_impl.h:543
int to_stream(std::ostream &s) const override
Serialize to the stream.
Definition: teca_variant_array_impl.h:882
const std::shared_ptr< const T > get_host_accessible() const
Definition: teca_variant_array_impl.h:806
void append(const std::vector< U > &vals)
append a vector of values
Definition: teca_variant_array_impl.h:750
void synchronize() const override
Sycnhronize the stream used for data movement.
Definition: teca_variant_array_impl.h:816
void set(const const_p_teca_variant_array &src) override
Set from the other array.
Definition: teca_variant_array_impl.h:621
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n, const U *v)
Definition: teca_variant_array_impl.h:437
void assign(const U *src, size_t src_start, size_t n_elem)
assign a subset from the other array
Definition: teca_variant_array_impl.h:678
void set(size_t dest_start, const U *src, size_t src_start, size_t n_elem)
Definition: teca_variant_array_impl.h:614
const T * data() const
Definition: teca_variant_array_impl.h:822
void copy(const const_p_teca_variant_array_impl< U > &src)
copy the contents from the other array.
Definition: teca_variant_array_impl.h:721
int from_stream(std::ostream &s) override
Deserialize from the stream.
Definition: teca_variant_array_impl.h:889
void debug_print(typename std::enable_if< std::is_arithmetic< U >::value >::type *=0) const
Print the contents of the buffer for debugging.
Definition: teca_variant_array_impl.h:897
const std::shared_ptr< const T > get_cuda_accessible() const
Get a pointer to the data accessible within CUDA.
Definition: teca_variant_array_impl.h:810
void append(const const_p_teca_variant_array &src, size_t src_start, size_t n_elem) override
append a subset of the passed array
Definition: teca_variant_array_impl.h:769
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n, const U &v, allocator alloc)
teca_variant_array_impl()
default construct (the object is unusable)
Definition: teca_variant_array_impl.h:920
void append(const U *src, size_t src_start, size_t n_elem)
append a range of values
Definition: teca_variant_array_impl.h:757
bool equal(const const_p_teca_variant_array &other) const override
virtual equivalence test
Definition: teca_variant_array_impl.h:2338
void assign(const const_p_teca_variant_array &src, size_t src_start, size_t n_elem) override
assign a subset of the other array
Definition: teca_variant_array_impl.h:690
void assign(const const_p_teca_variant_array_impl< U > &src)
assign the contents from the other array.
Definition: teca_variant_array_impl.h:698
void get(size_t src_start, const p_teca_variant_array_impl< U > &dest, size_t dest_start, size_t n_elem) const
Definition: teca_variant_array_impl.h:577
unsigned long size() const noexcept override
Get the current size of the data.
Definition: teca_variant_array_impl.h:1875
teca_variant_array_impl(allocator alloc)
construct with a specific allocator
Definition: teca_variant_array_impl.h:923
virtual void get(const p_teca_variant_array &dest) const=0
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n, const U &v)
Definition: teca_variant_array_impl.h:421
virtual void assign(const const_p_teca_variant_array &src)=0
T get(size_t i) const
get a single value
Definition: teca_variant_array_impl.h:518
int set_allocator(allocator alloc) override
Definition: teca_variant_array_impl.h:1831
std::string get_class_name() const override
Returns the name of the class in a human readable form.
Definition: teca_variant_array_impl.h:1863
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n, const U *v, allocator alloc)
void set(size_t i, const U &val)
Definition: teca_variant_array_impl.h:594
void get(std::vector< U > &dest) const
get a vector of values
Definition: teca_variant_array_impl.h:527
T * data()
Definition: teca_variant_array_impl.h:828
void set(size_t dest_start, const const_p_teca_variant_array_impl< U > &src, size_t src_start, size_t n_elem)
Definition: teca_variant_array_impl.h:655
void assign(const const_p_teca_variant_array_impl< U > &src, size_t src_start, size_t n_elem)
assign a subset of the other array
Definition: teca_variant_array_impl.h:713
void get(const p_teca_variant_array_impl< U > &dest) const
get the contents into the other array.
Definition: teca_variant_array_impl.h:564
void resize(unsigned long n) override
Resize the data.
Definition: teca_variant_array_impl.h:1882
const std::shared_ptr< T > & pointer() const
Definition: teca_variant_array_impl.h:834
void assign(const const_p_teca_variant_array &src) override
assign the contents from the other array.
Definition: teca_variant_array_impl.h:684
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n)
Definition: teca_variant_array_impl.h:406
void append(const U &val)
Definition: teca_variant_array_impl.h:743
int from_stream(teca_binary_stream &s) override
Deserialize from the stream.
Definition: teca_variant_array_impl.h:875
void set(size_t dest_start, const const_p_teca_variant_array &src, size_t src_start, size_t n_elem) override
Definition: teca_variant_array_impl.h:633
void assign(const p_teca_variant_array_impl< U > &src)
assign the contents from the other array.
Definition: teca_variant_array_impl.h:705
void get(size_t src_start, const p_teca_variant_array &dest, size_t dest_start, size_t n_elem) const override
Definition: teca_variant_array_impl.h:555
void swap(const p_teca_variant_array &other) override
virtual swap
Definition: teca_variant_array_impl.h:1846
void assign(const std::vector< U > &src)
Definition: teca_variant_array_impl.h:671
static std::shared_ptr< teca_variant_array_impl< T > > New(size_t n, T *ptr, allocator alloc, int owner, delete_func_t df)
static std::shared_ptr< teca_variant_array_impl< T > > New()
Definition: teca_variant_array_impl.h:393
teca_variant_array_impl(allocator alloc, size_t n_elem, const T &val)
construct with preallocated size and initialized to a specific value
Definition: teca_variant_array_impl.h:931
void clear() noexcept override
Clear the data.
Definition: teca_variant_array_impl.h:1903
teca_variant_array_impl(allocator alloc, size_t size, int owner, T *ptr, delete_func_t df)
zero-copy construct by setting buffer contents directly
Definition: teca_variant_array_impl.h:947
A type erasure for array based data.
Definition: teca_variant_array.h:43
virtual void set(const const_p_teca_variant_array &src)=0
virtual void copy(const const_p_teca_variant_array &src)
copy the contents from the other array.
Definition: teca_variant_array.h:273
virtual void assign(const const_p_teca_variant_array &src)=0
virtual void append(const const_p_teca_variant_array &src)=0
virtual void get(const p_teca_variant_array &dest) const =0
hamr::buffer_allocator allocator
allocator types
Definition: teca_variant_array.h:46
p_teca_variant_array new_instance() const
Definition: teca_variant_array.h:62
p_teca_variant_array new_copy() const
Definition: teca_variant_array.h:101
bool equal(T a, T b, T relTol=equal_tt< T >::relTol(), T absTol=equal_tt< T >::absTol(), typename std::enable_if< std::is_floating_point< T >::value >::type *=0)
Definition: teca_coordinate_util.h:76
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
TECA_EXPORT bool append(teca_variant_array *varr, PyObject *obj)
Append values from the object to the variant array.
Definition: teca_py_array.h:221
TECA_EXPORT bool set(teca_variant_array *varr, unsigned long i, PyObject *obj)
Set i'th element of the variant array to the value of the object.
Definition: teca_py_array.h:305
some functions helping us manipulate teca_variant_array
Definition: teca_variant_array_util.h:14
auto get_host_accessible()
terminates recursion
Definition: teca_variant_array_util.h:99
auto data(V &&... args)
Definition: teca_variant_array_util.h:255
void sync_host_access_any(const array_t &... arrays)
Definition: teca_variant_array_util.h:29
auto New(size_t n_elem, teca_variant_array::allocator alloc=teca_variant_array::allocator::malloc)
Definition: teca_variant_array_util.h:269
Definition: teca_variant_array.h:25
Definition: teca_variant_array.h:24
Creates an instance of teca_variant_array_impl<T> where T is determined from the type code.
Definition: teca_variant_array_impl.h:2676
static p_teca_variant_array New(unsigned int type_code, allocator alloc=allocator::malloc)
Definition: teca_variant_array_impl.h:2684
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:161
#define TECA_FATAL_ERROR(_msg)
Definition: teca_common.h:153
#define TECA_WARNING(_msg)
Constructs a warning message and sends it to the stderr stream.
Definition: teca_common.h:164
std::shared_ptr< teca_variant_array > p_teca_variant_array
Definition: teca_variant_array.h:27
std::shared_ptr< const teca_variant_array > const_p_teca_variant_array
Definition: teca_variant_array.h:27
#define TEMPLATE_DISPATCH(t, p,...)
Definition: teca_variant_array_impl.h:244
std::shared_ptr< const teca_variant_array_impl< T > > const_p_teca_variant_array_impl
Definition: teca_variant_array_impl.h:44
std::shared_ptr< teca_variant_array_impl< T > > p_teca_variant_array_impl
Definition: teca_variant_array_impl.h:44
const_p_teca_variant_array_impl< T > const_ptr(const p_teca_variant_array_impl< T > &v)
Definition: teca_variant_array_impl.h:116