TECA
The Toolkit for Extreme Climate Analysis
teca_variant_array.h
Go to the documentation of this file.
1 #ifndef teca_variant_array_h
2 #define teca_variant_array_h
3 
4 /// @file
5 
6 #include <vector>
7 #include <string>
8 #include <sstream>
9 #include <exception>
10 #include <typeinfo>
11 #include <iterator>
12 #include <algorithm>
13 #include <type_traits>
14 #include <typeinfo>
15 #include <utility>
16 #include <hamr_buffer_allocator.h>
17 
18 #include "teca_config.h"
19 #include "teca_common.h"
20 #include "teca_binary_stream.h"
21 #include "teca_bad_cast.h"
22 #include "teca_shared_object.h"
23 
24 template <typename T> struct pod_dispatch;
25 template <typename T> struct object_dispatch;
26 
27 TECA_SHARED_OBJECT_FORWARD_DECL(teca_variant_array)
28 
29 /// A type erasure for array based data.
30 /** The variant array supports: set, get, assign, and append. The elements of the
31  * array can be stored on different accelerator devices using different
32  * technologies and accessed seamless from other accelerator devices and
33  * technologies.
34  *
35  * Use the type erasure (this class) to implement collections of arrays and
36  * public API. Use the concrete implementation (::teca_variant_array_impl) for
37  * direct access to the typed data.
38  *
39  * See #TEMPLATE_DISPATCH and #NESTED_TEMPLATE_DISPATCH for details on how to
40  * apply type specific code to an instance of teca_variant_array.
41  */
42 class TECA_EXPORT teca_variant_array : public std::enable_shared_from_this<teca_variant_array>
43 {
44 public:
45  /// allocator types
46  using allocator = hamr::buffer_allocator;
47 
48  // construct
49  teca_variant_array() noexcept = default;
50  virtual ~teca_variant_array() noexcept = default;
51 
52  // copy/move construct. can't copy/move construct from a base
53  // pointer. these require a downcast.
54  teca_variant_array(const teca_variant_array &other) = delete;
55  teca_variant_array(teca_variant_array &&other) = delete;
56  teca_variant_array &operator=(teca_variant_array &other) = delete;
57  teca_variant_array &operator=(teca_variant_array &&other) = delete;
58 
59  /** return a newly allocated empty object of the same type. The default
60  * allocator will be used.
61  */
62  p_teca_variant_array new_instance() const
63  {
64  return new_instance(allocator::malloc);
65  }
66 
67  /** returns a newly allocated object of the same type will n_elem elements
68  * allocated. The default allocator will be used.
69  *
70  * @param[in] n_elem the number of elements to allocate.
71  */
73  {
74  return new_instance(n, allocator::malloc);
75  }
76 
77  /** @returns a newly allocated empty object of the same type.
78  *
79  * @param[in] alloc selects the allocator to use (See ::allocator)
80  */
81  virtual p_teca_variant_array new_instance(allocator alloc) const = 0;
82 
83  /** returns a newly allocated object of the same type will n_elem elements
84  * allocated.
85  *
86  * @param[in] n_elem the number of elements to allocate.
87  * @param[in[ alloc selects the allocator to use (See ::allocator)
88  */
89  //
90  virtual p_teca_variant_array new_instance(size_t n, allocator alloc) const = 0;
91 
92  /** return a newly allocated object, initialized copy from this.
93  *
94  * @param[in] alloc selects the allocator to use (See ::allocator)
95  */
96  virtual p_teca_variant_array new_copy(allocator alloc) const = 0;
97 
98  /** return a newly allocated object, initialized copy from this. The
99  * default allocator will be used.
100  */
102  {
103  return new_copy(allocator::malloc);
104  }
105 
106  /** return a newly allocated object, initialized copy from a subset of
107  * this.
108  *
109  * @param[in[ src_start the first element to copy
110  * @param[in] n_elem the number of elements to copy
111  * @param[in] alloc selects the allocator to use (See ::allocator)
112  */
113  virtual p_teca_variant_array new_copy(size_t src_start,
114  size_t n_elem, allocator alloc) const = 0;
115 
116  /** return a newly allocated object, initialized copy from a subset of
117  * this. The default allocator will be used.
118  *
119  * @param[in[ src_start the first element to copy
120  * @param[in] n_elem the number of elements to copy
121  */
122  p_teca_variant_array new_copy(size_t src_start, size_t n_elem) const
123  {
124  return new_copy(src_start, n_elem, allocator::malloc);
125  }
126 
127  /** Set the allocator. If the passed allocator is already in use this is a
128  * NOOP. Otherwise the contents of the variant array are reallocated and
129  * moved using a buffer allocated with the passed allocator. This can be
130  * used to explicitly move the data.
131  *
132  * @param[in] alloc the new ::allocator to use
133  * @returns 0 if successful
134  */
135  virtual int set_allocator(allocator alloc) = 0;
136 
137  /// return the name of the class in a human readable form
138  virtual std::string get_class_name() const = 0;
139 
140  /// initialize the elements using the default constructor
141  virtual void initialize() = 0;
142 
143  /** @name get
144  * Copy the contest of this array to the passed instance. The desitination
145  * must be large enough to hold the results. These calls could throw
146  * std::bad_cast if the passed in type is not castable to the internal
147  * type.
148  */
149  ///@{
150  /// get the contents into the other array.
151  virtual void get(const p_teca_variant_array &dest) const = 0;
152 
153  /** get a subset of the contents into a subset of the other array
154  *
155  * @param[in] dest_start the first location to assign to
156  * @param[in] src the array to copy values from
157  * @param[in] src_start the first location to copy from
158  * @param[in] n_elem the number of elements to copy
159  */
160  virtual void get(size_t src_start, const p_teca_variant_array &dest,
161  size_t dest_start, size_t n_elem) const = 0;
162 
163  /// get a single value
164  template<typename T>
165  void get(unsigned long i, T &val) const;
166 
167  /// get a single value
168  template<typename T>
169  T get(unsigned long i) const;
170 
171  /// get the contents into the passed vector. The vector is resized as needed.
172  template<typename T>
173  void get(std::vector<T> &vals) const;
174 
175  /// get a subset of the contents into the passed in array.
176  template<typename T>
177  void get(size_t src_start, T *dest, size_t dest_start, size_t n_elem) const;
178  ///@}
179 
180  /** @name set
181  * Assign values to this array form another. This array must already be
182  * large enough to hold the result. If automatic resizing is desired use
183  * copy instead. These calls could throw std::bad_cast if the passed in
184  * type is not castable to the internal type.
185  */
186  ///@{
187  /// Set from the other array
188  virtual void set(const const_p_teca_variant_array &src) = 0;
189 
190  /// Set from the other array
191  virtual void set(const p_teca_variant_array &src)
192  {
193  // forward to the set from const implementation
194  this->set(const_p_teca_variant_array(src));
195  }
196 
197  /** Set a subset of this array from a subset opf the contents of the other
198  * array.
199  *
200  * @param[in] dest_start the first location to assign to
201  * @param[in] src the array to copy values from
202  * @param[in] src_start the first location to copy from
203  * @param[in] n_elem the number of elements to copy
204  */
205  virtual void set(size_t dest_start, const const_p_teca_variant_array &src,
206  size_t src_start, size_t n_elem) = 0;
207 
208  /** Set a subset of this array from a subset opf the contents of the other
209  * array.
210  *
211  * @param[in] dest_start the first location to assign to
212  * @param[in] src the array to copy values from
213  * @param[in] src_start the first location to copy from
214  * @param[in] n_elem the number of elements to copy
215  */
216  virtual void set(size_t dest_start, const p_teca_variant_array &src,
217  size_t src_start, size_t n_elem)
218  {
219  // forward to the set from const implementation
220  this->set(dest_start, const_p_teca_variant_array(src), src_start, n_elem);
221  }
222 
223  /// set a single value
224  template<typename T>
225  void set(unsigned long i, const T &val);
226 
227  /// set the contents from a vector of values. this array is not resized.
228  template<typename T>
229  void set(const std::vector<T> &src);
230 
231  /// set a subset of the array from a passed array. this array is not resized.
232  template<typename T>
233  void set(size_t dest_start, const T *src, size_t src_start, size_t n_elem);
234  ///@}
235 
236  /** @name assign
237  * assign the contents of the passed array to this array. This array will be
238  * resized to hold the results. These calls could throw std::bad_cast if
239  * the passed in type is not castable to the internal type.
240  */
241  ///@{
242  /// assign the contents from the other array.
243  virtual void assign(const const_p_teca_variant_array &src) = 0;
244 
245  /// assign the contents from the other array.
246  virtual void assign(const p_teca_variant_array &src)
247  {
248  // forward to the assign from const implementation
249  this->assign(const_p_teca_variant_array(src));
250  }
251 
252  /// assign a subset of the other array
253  virtual void assign(const const_p_teca_variant_array &src,
254  size_t src_start, size_t n_elem) = 0;
255 
256  /// assign a subset of the other array
257  virtual void assign(const p_teca_variant_array &src,
258  size_t src_start, size_t n_elem)
259  {
260  // forward to the assign from const implementation
261  this->assign(const_p_teca_variant_array(src), src_start, n_elem);
262  }
263 
264  /// assign the contents from a vector of values. this array is resized as needed.
265  template<typename T>
266  void assign(const std::vector<T> &src);
267 
268  /// assign the contents from a passed array. this array is resized as needed.
269  template<typename T>
270  void assign(const T *src, size_t src_start, size_t n_elem);
271 
272  /// copy the contents from the other array.
273  virtual void copy(const const_p_teca_variant_array &src)
274  {
275  this->assign(src);
276  }
277 
278  /// copy the contents from the other array.
279  virtual void copy(const p_teca_variant_array &src)
280  {
281  // forward to the copy from const implementation
282  this->copy(const_p_teca_variant_array(src));
283  }
284 
285  /// copy a subset of the other array
287  size_t src_start, size_t n_elem)
288  {
289  this->assign(src, src_start, n_elem);
290  }
291  ///@}
292 
293  /** @name append
294  * Append data at the back of the array. These calls could throw
295  * std::bad_cast if the passed in type is not castable to the internal
296  * type.
297  */
298  ///@{
299  /// append the passed array.
300  virtual void append(const const_p_teca_variant_array &src) = 0;
301 
302  /// append the passed array.
303  virtual void append(const p_teca_variant_array &src)
304  {
305  // forward to the append from const implementation
307  }
308 
309  /// append a subset of the passed array
310  virtual void append(const const_p_teca_variant_array &src,
311  size_t src_start, size_t n_elem) = 0;
312 
313  /// append a subset of the passed array
314  virtual void append(const p_teca_variant_array &src,
315  size_t src_start, size_t n_elem)
316  {
317  // forward to the append from const implementation
318  this->append(const_p_teca_variant_array(src), src_start, n_elem);
319  }
320 
321  /// append a single value. this array is extended as needed.
322  template<typename T>
323  void append(const T &val);
324 
325  /** Append the contents from a vector of values. this array is extended as
326  * needed.
327  */
328  template<typename T>
329  void append(const std::vector<T> &src);
330 
331  /** Append the contents from a passed array. this array is extended as
332  * needed.
333  */
334  template<typename T>
335  void append(const T *src, size_t src_start, size_t n_elem);
336  ///@}
337 
338  /// get the number of elements in the array
339  virtual unsigned long size() const noexcept = 0;
340 
341  /// resize. allocates new storage and copies in existing values
342  virtual void resize(unsigned long i) = 0;
343 
344  /** reserve. reserves the requested amount of space with out constructing
345  * elements
346  */
347  virtual void reserve(unsigned long i) = 0;
348 
349  /// free all the internal data
350  virtual void clear() noexcept = 0;
351 
352  /** swap the contents of this and the other object. an exception is thrown
353  * when no conversion between the two types exists.
354  */
355  virtual void swap(const p_teca_variant_array &other) = 0;
356 
357  /// compare the two arrays element wize for equality
358  virtual bool equal(const const_p_teca_variant_array &other) const = 0;
359 
360  /// serrialize to the binary stream in the internal format
361  virtual int to_stream(teca_binary_stream &s) const = 0;
362 
363  /// derrialize from the binary stream
364  virtual int from_stream(teca_binary_stream &s) = 0;
365 
366  /// serrialize to the stream in a human readable format
367  virtual int to_stream(std::ostream &s) const = 0;
368 
369  /// derrialize from the human readable stream
370  virtual int from_stream(std::ostream &s) = 0;
371 
372  /// a code for the contained data type used for serialization
373  virtual unsigned int type_code() const noexcept = 0;
374 
375 private:
376  template<typename T>
377  void get_dispatch(unsigned long i, T &val,
378  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
379 
380  template<typename T>
381  void get_dispatch(unsigned long i, T &val,
382  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
383 
384  template<typename T>
385  void get_dispatch(std::vector<T> &vals,
386  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
387 
388  template<typename T>
389  void get_dispatch(std::vector<T> &vals,
390  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
391 
392  template<typename T>
393  void get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
394  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
395 
396  template<typename T>
397  void get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
398  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
399 
400  template<typename T>
401  void set_dispatch(unsigned long i, const T &val,
402  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
403 
404  template<typename T>
405  void set_dispatch(unsigned long i, const T &val,
406  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
407 
408  template<typename T>
409  void set_dispatch(const std::vector<T> &src,
410  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
411 
412  template<typename T>
413  void set_dispatch(const std::vector<T> &src,
414  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
415 
416  template<typename T>
417  void set_dispatch(size_t dest_start, const T *src, size_t src_start, size_t n_elem,
418  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
419 
420  template<typename T>
421  void set_dispatch(size_t dest_start, const T *src, size_t src_start, size_t n_elem,
422  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
423 
424  template<typename T>
425  void assign_dispatch(const std::vector<T> &src,
426  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
427 
428  template<typename T>
429  void assign_dispatch(const std::vector<T> &src,
430  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
431 
432  template<typename T>
433  void assign_dispatch(const T *src, size_t src_start, size_t n_elem,
434  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
435 
436  template<typename T>
437  void assign_dispatch(const T *src, size_t src_start, size_t n_elem,
438  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
439 
440  template<typename T>
441  void append_dispatch(const T &val,
442  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
443 
444  template<typename T>
445  void append_dispatch(const T &val,
446  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
447 
448  template<typename T>
449  void append_dispatch(const std::vector<T> &src,
450  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
451 
452  template<typename T>
453  void append_dispatch(const std::vector<T> &src,
454  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
455 
456  template<typename T>
457  void append_dispatch(const T *src, size_t src_start, size_t n_elem,
458  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
459 
460  template<typename T>
461  void append_dispatch(const T *src, size_t src_start, size_t n_elem,
462  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
463 };
464 
465 #endif
teca_variant_array::copy
virtual void copy(const p_teca_variant_array &src)
copy the contents from the other array.
Definition: teca_variant_array.h:279
teca_binary_stream
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:16
teca_variant_array::assign
virtual void assign(const p_teca_variant_array &src)
assign the contents from the other array.
Definition: teca_variant_array.h:246
teca_variant_array::append
virtual void append(const p_teca_variant_array &src)
append the passed array.
Definition: teca_variant_array.h:303
teca_variant_array
A type erasure for array based data.
Definition: teca_variant_array.h:42
teca_variant_array::assign
virtual void assign(const p_teca_variant_array &src, size_t src_start, size_t n_elem)
assign a subset of the other array
Definition: teca_variant_array.h:257
teca_py_array::set
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
object_dispatch
Definition: teca_variant_array.h:25
teca_variant_array::copy
void copy(const const_p_teca_variant_array &src, size_t src_start, size_t n_elem)
copy a subset of the other array
Definition: teca_variant_array.h:286
teca_variant_array::allocator
hamr::buffer_allocator allocator
allocator types
Definition: teca_variant_array.h:46
teca_coordinate_util::equal
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:70
teca_common.h
const_p_teca_variant_array
std::shared_ptr< const teca_variant_array > const_p_teca_variant_array
Definition: teca_variant_array.h:27
pod_dispatch
Definition: teca_variant_array.h:24
teca_variant_array::new_copy
p_teca_variant_array new_copy(size_t src_start, size_t n_elem) const
Definition: teca_variant_array.h:122
teca_variant_array::copy
virtual void copy(const const_p_teca_variant_array &src)
copy the contents from the other array.
Definition: teca_variant_array.h:273
teca_py_array::copy
TECA_EXPORT bool copy(teca_variant_array *varr, PyObject *obj)
Copy values from the object into variant array.
Definition: teca_py_array.h:290
teca_shared_object.h
teca_variant_array::set
virtual void set(const p_teca_variant_array &src)
Set from the other array.
Definition: teca_variant_array.h:191
teca_variant_array::new_copy
p_teca_variant_array new_copy() const
Definition: teca_variant_array.h:101
p_teca_variant_array
std::shared_ptr< teca_variant_array > p_teca_variant_array
Definition: teca_variant_array.h:27
teca_variant_array::append
virtual void append(const p_teca_variant_array &src, size_t src_start, size_t n_elem)
append a subset of the passed array
Definition: teca_variant_array.h:314
teca_variant_array::set
virtual void set(size_t dest_start, const p_teca_variant_array &src, size_t src_start, size_t n_elem)
Definition: teca_variant_array.h:216
teca_error::TECA_EXPORT
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
teca_py_array::append
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_variant_array::new_instance
p_teca_variant_array new_instance(size_t n) const
Definition: teca_variant_array.h:72