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 #VARIANT_ARRAY_DISPATCH and #NESTED_VARIANT_ARRAY_DISPATCH for details
40  * on how to 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  /// @returns true if the contents are accesisble from the CPU
376  virtual int host_accessible() const noexcept = 0;
377 
378  /// @returns true if the contents are accesisble from CUDA
379  virtual int cuda_accessible() const noexcept = 0;
380 
381  /// synchronize on the associated stream
382  virtual void synchronize() const = 0;
383 
384 private:
385  template<typename T>
386  void get_dispatch(unsigned long i, T &val,
387  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
388 
389  template<typename T>
390  void get_dispatch(unsigned long i, T &val,
391  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
392 
393  template<typename T>
394  void get_dispatch(std::vector<T> &vals,
395  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
396 
397  template<typename T>
398  void get_dispatch(std::vector<T> &vals,
399  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
400 
401  template<typename T>
402  void get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
403  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0) const;
404 
405  template<typename T>
406  void get_dispatch(size_t src_start, T *dest, size_t dest_start, size_t n_elem,
407  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0) const;
408 
409  template<typename T>
410  void set_dispatch(unsigned long i, const T &val,
411  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
412 
413  template<typename T>
414  void set_dispatch(unsigned long i, const T &val,
415  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
416 
417  template<typename T>
418  void set_dispatch(const std::vector<T> &src,
419  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
420 
421  template<typename T>
422  void set_dispatch(const std::vector<T> &src,
423  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
424 
425  template<typename T>
426  void set_dispatch(size_t dest_start, const T *src, size_t src_start, size_t n_elem,
427  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
428 
429  template<typename T>
430  void set_dispatch(size_t dest_start, const T *src, size_t src_start, size_t n_elem,
431  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
432 
433  template<typename T>
434  void assign_dispatch(const std::vector<T> &src,
435  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
436 
437  template<typename T>
438  void assign_dispatch(const std::vector<T> &src,
439  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
440 
441  template<typename T>
442  void assign_dispatch(const T *src, size_t src_start, size_t n_elem,
443  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
444 
445  template<typename T>
446  void assign_dispatch(const T *src, size_t src_start, size_t n_elem,
447  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
448 
449  template<typename T>
450  void append_dispatch(const T &val,
451  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
452 
453  template<typename T>
454  void append_dispatch(const T &val,
455  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
456 
457  template<typename T>
458  void append_dispatch(const std::vector<T> &src,
459  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
460 
461  template<typename T>
462  void append_dispatch(const std::vector<T> &src,
463  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
464 
465  template<typename T>
466  void append_dispatch(const T *src, size_t src_start, size_t n_elem,
467  typename std::enable_if<object_dispatch<T>::value, T>::type* = 0);
468 
469  template<typename T>
470  void append_dispatch(const T *src, size_t src_start, size_t n_elem,
471  typename std::enable_if<pod_dispatch<T>::value, T>::type* = 0);
472 };
473 
474 #endif
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:17
A type erasure for array based data.
Definition: teca_variant_array.h:43
virtual p_teca_variant_array new_instance(allocator alloc) const =0
virtual void get(size_t src_start, const p_teca_variant_array &dest, size_t dest_start, size_t n_elem) const =0
p_teca_variant_array new_copy(size_t src_start, size_t n_elem) const
Definition: teca_variant_array.h:122
virtual int set_allocator(allocator alloc)=0
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
virtual void set(const const_p_teca_variant_array &src)=0
virtual void set(const p_teca_variant_array &src)
Set from the other array.
Definition: teca_variant_array.h:191
virtual void assign(const p_teca_variant_array &src)
assign the contents from the other array.
Definition: teca_variant_array.h:246
p_teca_variant_array new_instance(size_t n) const
Definition: teca_variant_array.h:72
virtual void set(size_t dest_start, const const_p_teca_variant_array &src, size_t src_start, size_t n_elem)=0
virtual void copy(const const_p_teca_variant_array &src)
copy the contents from the other array.
Definition: teca_variant_array.h:273
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
virtual void append(const const_p_teca_variant_array &src, size_t src_start, size_t n_elem)=0
append a subset of the passed array
virtual p_teca_variant_array new_instance(size_t n, allocator alloc) const =0
virtual p_teca_variant_array new_copy(size_t src_start, size_t n_elem, allocator alloc) const =0
virtual void assign(const const_p_teca_variant_array &src, size_t src_start, size_t n_elem)=0
assign a subset of the other array
virtual unsigned long size() const noexcept=0
get the number of elements in the array
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
virtual void initialize()=0
initialize the elements using the default constructor
virtual void assign(const const_p_teca_variant_array &src)=0
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
virtual void append(const const_p_teca_variant_array &src)=0
virtual void append(const p_teca_variant_array &src)
append the passed array.
Definition: teca_variant_array.h:303
virtual void get(const p_teca_variant_array &dest) const =0
hamr::buffer_allocator allocator
allocator types
Definition: teca_variant_array.h:46
virtual void copy(const p_teca_variant_array &src)
copy the contents from the other array.
Definition: teca_variant_array.h:279
virtual std::string get_class_name() const =0
return the name of the class in a human readable form
virtual p_teca_variant_array new_copy(allocator alloc) const =0
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 copy(teca_variant_array *varr, PyObject *obj)
Copy values from the object into variant array.
Definition: teca_py_array.h:290
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
Definition: teca_variant_array.h:25
Definition: teca_variant_array.h:24
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