TECA
The Toolkit for Extreme Climate Analysis
teca_dataset.h
1 #ifndef teca_dataset_h
2 #define teca_dataset_h
3 
4 #include "teca_config.h"
5 #include "teca_common.h"
6 #include "teca_shared_object.h"
7 #include "teca_variant_array.h"
9 
10 #include <vector>
11 #include <iosfwd>
12 #include <type_traits>
13 
14 class teca_binary_stream;
15 class teca_metadata;
16 
17 TECA_SHARED_OBJECT_FORWARD_DECL(teca_dataset)
18 
19 // this is a convenience macro to be used to
20 // declare New and enable seamless operation
21 // with std C++11 shared pointer
22 #define TECA_DATASET_STATIC_NEW(T) \
23  \
24 static p_##T New() \
25 { \
26  return std::make_shared<T>(); \
27 } \
28  \
29 std::shared_ptr<T> shared_from_this() \
30 { \
31  return std::static_pointer_cast<T>( \
32  teca_dataset::shared_from_this()); \
33 } \
34  \
35 std::shared_ptr<T const> shared_from_this() const \
36 { \
37  return std::static_pointer_cast<T const>( \
38  teca_dataset::shared_from_this()); \
39 }
40 
41 // convenience macro implementing new_instance method
42 #define TECA_DATASET_NEW_INSTANCE() \
43 virtual p_teca_dataset new_instance() const override \
44 { \
45  return std::make_shared \
46  <std::remove_const<std::remove_reference \
47  <decltype(*this)>::type>::type >(); \
48 }
49 
50 // convenience macro implementing new_copy method
51 #define TECA_DATASET_NEW_COPY() \
52 /** @copydoc teca_dataset::new_copy(allocator) */ \
53 virtual p_teca_dataset new_copy(allocator alloc = \
54  allocator::malloc) const override \
55 { \
56  p_teca_dataset o = std::make_shared \
57  <std::remove_const<std::remove_reference \
58  <decltype(*this)>::type>::type>(); \
59  \
60  o->copy(this->shared_from_this(), alloc); \
61  \
62  return o; \
63 } \
64  \
65 virtual p_teca_dataset new_shallow_copy() override \
66 { \
67  p_teca_dataset o = std::make_shared \
68  <std::remove_const<std::remove_reference \
69  <decltype(*this)>::type>::type>(); \
70  \
71  o->shallow_copy(this->shared_from_this()); \
72  \
73  return o; \
74 }
75 
76 // convenience macro for adding properties to dataset
77 // objects
78 #define TECA_DATASET_PROPERTY(T, name) \
79  \
80 void set_##name(const T &val) \
81 { \
82  this->name = val; \
83 } \
84  \
85 const T &get_##name() const \
86 { \
87  return this->name; \
88 } \
89  \
90 T &get_##name() \
91 { \
92  return this->name; \
93 }
94 
95 // convenience set get methods for dataset metadata
96 #define TECA_DATASET_METADATA(key, T, len) \
97 TECA_DATASET_METADATA_V(T, key, len) \
98 TECA_DATASET_METADATA_A(T, key, len) \
99 TECA_DATASET_METADATA_ ## len (T, key)
100 
101 
102 #define TECA_DATASET_METADATA_1(T, key) \
103 void set_##key(const T & val_1) \
104 { \
105  this->get_metadata().set<T>(#key, val_1); \
106 } \
107  \
108 int get_##key(T &val_1) const \
109 { \
110  return this->get_metadata().get<T>( \
111  #key, val_1); \
112 }
113 
114 #define TECA_DATASET_METADATA_2(T, key) \
115 void set_##key(const T & val_1, const T & val_2) \
116 { \
117  this->get_metadata().set<T>( \
118  #key, {val_1, val_2}); \
119 } \
120  \
121 int get_##key(T &val_1, T &val_2) const \
122 { \
123  std::vector<T> vals; \
124  if (this->get_metadata().get<T>(#key, vals)) \
125  return -1; \
126  val_1 = vals[0]; \
127  val_2 = vals[1]; \
128  return 0; \
129 }
130 
131 #define TECA_DATASET_METADATA_3(T, key) \
132 void set_##key(const T & val_1, const T & val_2, \
133  const T & val_3) \
134 { \
135  this->get_metadata().set<T>(#key, \
136  {val_1, val_2, val_3}); \
137 } \
138  \
139 int get_##key(T &val_1, T &val_2, T &val_3) const \
140 { \
141  std::vector<T> vals; \
142  if (this->get_metadata().get<T>(#key, vals)) \
143  return -1; \
144  val_1 = vals[0]; \
145  val_2 = vals[1]; \
146  val_3 = vals[2]; \
147  return 0; \
148 }
149 
150 #define TECA_DATASET_METADATA_4(T, key) \
151 void set_##key(const T & val_1, const T & val_2, \
152  const T & val_3, const T & val_4) \
153 { \
154  this->get_metadata().set<T>(#key, \
155  {val_1, val_2, val_3, val_4}); \
156 }
157 
158 #define TECA_DATASET_METADATA_6(T, key) \
159 void set_##key(const T & val_1, const T & val_2, \
160  const T & val_3, const T & val_4, \
161  const T & val_5, const T & val_6) \
162 { \
163  this->get_metadata().set<T>(#key, \
164  {val_1, val_2, val_3, \
165  val_4, val_5, val_6}); \
166 }
167 
168 #define TECA_DATASET_METADATA_8(T, key) \
169 void set_##key(const T & val_1, const T & val_2, \
170  const T & val_3, const T & val_4, \
171  const T & val_5, const T & val_6, \
172  const T & val_7, const T & val_8) \
173 { \
174  this->get_metadata().set<T>(#key, \
175  {val_1, val_2, val_3, val_4, val_5, \
176  val_6, val_7, val_8}); \
177 }
178 
179 #define TECA_DATASET_METADATA_V(T, key, len) \
180 void set_##key(const std::vector<T> &vals) \
181 { \
182  if (vals.size() != len) \
183  { \
184  TECA_ERROR(#key " requires " #len " values") \
185  } \
186  this->get_metadata().set<T>(#key, vals); \
187 } \
188  \
189 int get_##key(std::vector<T> &vals) const \
190 { \
191  return this->get_metadata().get<T>(#key, vals); \
192 } \
193  \
194 void set_##key(const p_teca_variant_array &vals) \
195 { \
196  if (vals->size() != len) \
197  { \
198  TECA_ERROR(#key " requires " #len " values") \
199  } \
200  this->get_metadata().set(#key, vals); \
201 } \
202  \
203 int get_##key(p_teca_variant_array vals) const \
204 { \
205  return this->get_metadata().get(#key, vals); \
206 } \
207  \
208 void set_##key(const std::initializer_list<T> &l) \
209 { \
210  std::vector<T> vals(l); \
211  if (vals.size() != len) \
212  { \
213  TECA_ERROR(#key " requires " #len " values") \
214  } \
215  this->get_metadata().set<T>(#key, vals); \
216 } \
217 
218 #define TECA_DATASET_METADATA_A(T, key, len) \
219 void set_##key(const T *vals) \
220 { \
221  this->get_metadata().set<T>(#key, vals, len); \
222 } \
223  \
224 int get_##key(T *vals) const \
225 { \
226  return this->get_metadata().get<T>( \
227  #key, vals, len); \
228 }
229 
230 /// Interface for TECA datasets.
231 class TECA_EXPORT teca_dataset : public std::enable_shared_from_this<teca_dataset>
232 {
233 public:
234  using allocator = teca_variant_array::allocator;
235 
236  virtual ~teca_dataset();
237 
238  /** @name index_request_key
239  * The name of the key that holds the index identifying this dataset's
240  * location in the index set.
241  */
242  ///@{
243  TECA_DATASET_METADATA(index_request_key, std::string, 1)
244  ///@}
245 
246  /** Set the name of the index_request_key and a key with that name set to an
247  * inclusive range of indices [i0, i1].
248  *
249  * @param[in] request_key the name of the index_request_key will be stored
250  * in the dataset metadata index_request_key
251  * @param[in] ids an inclusive range of indices that will be stored in a
252  * key named by the value of request_key
253  *
254  * @returns zero if successful
255  */
256  virtual int set_request_indices(const std::string &request_key,
257  const unsigned long ids[2]);
258 
259  /** Looks for an index_request_key and uses the value to get the inclusive
260  * range of indices stored in this dataset. The call can fail if the
261  * index_request_key has not been set.
262  *
263  * @param[out] ids the inclusive range of indices stored in this dataset.
264  *
265  * @returns zero if successful.
266  */
267  virtual int get_request_indices(unsigned long ids[2]) const;
268 
269  /** Looks for an index_request_key and uses the value to get the single index
270  * stored in this dataset. The call can fail if the index_request_key has
271  * not been set or if the dataset holds more than one index.
272  *
273  * @param[out] ids the inclusive range of indices stored in this dataset.
274  *
275  * @returns zero if successful.
276  */
277  //
278  virtual int get_request_index(unsigned long &index) const;
279 
280  /** Set the name of the index_request_key and a key with that name set to an
281  * inclusive range of indices [i0, i0] i.e. a single index.
282  *
283  * @param[in] request_key the name of the index_request_key will be stored
284  * in the dataset metadata index_request_key
285  * @param[in] ids an inclusive range of indices that will be stored in a
286  * key named by the value of request_key
287  *
288  * @returns zero if successful
289  */
290  virtual int set_request_index(const std::string &request_key,
291  unsigned long index);
292 
293  /** covert to boolean. @returns true if the dataset is not empty, otherwise
294  * false.
295  */
296  explicit operator bool() const noexcept
297  { return !this->empty(); }
298 
299  /// @returns true if the dataset is empty.
300  virtual bool empty() const noexcept
301  { return true; }
302 
303  /// virtual constructor. return a new dataset of the same type.
304  virtual p_teca_dataset new_instance() const = 0;
305 
306  /** Virtual copy constructor. return a deep copy of this dataset in a new
307  * instance.
308  *
309  * @param[in] alloc The allocator to use for alloctions of data structures
310  * to hold the copy. The default is a CPU based allocator.
311  */
312  virtual p_teca_dataset new_copy(allocator alloc = allocator::malloc) const = 0;
313 
314  /** Virtual shallow copy constructor. return a shallow copy of this dataset
315  * in a new instance. References to source data structures are taken, but
316  * metadata is always deep copied.
317  */
318  virtual p_teca_dataset new_shallow_copy() = 0;
319 
320  // return a string identifier uniquely naming the dataset type
321  virtual std::string get_class_name() const = 0;
322 
323  // return an integer identifier uniquely naming the dataset type
324  virtual int get_type_code() const = 0;
325 
326  /** Deep copy data and metdata.
327  *
328  * @param[in] other The dataset to copy.
329  * @param[in] alloc The allocator to use for alloctions of data structures
330  * to hold the copy. The default is a CPU based allocator.
331  */
332  virtual void copy(const const_p_teca_dataset &other,
333  allocator alloc = allocator::malloc);
334 
335  /** Shallow copy data and metadata. The shallow copy takes references to
336  * the source data structures. Metadata is always deep copied.
337  *
338  * @param[in] other The dataset to copy.
339  */
340  virtual void shallow_copy(const p_teca_dataset &other);
341 
342  /// copy metadata. always a deep copy.
343  virtual void copy_metadata(const const_p_teca_dataset &other);
344 
345  /// swap internals of the two objects
346  virtual void swap(const p_teca_dataset &other);
347 
348  /// get the dataset metadata
349  virtual teca_metadata &get_metadata() noexcept;
350 
351  /// get the dataset metadata
352  virtual const teca_metadata &get_metadata() const noexcept;
353 
354  /// set the dataset metadata
355  virtual void set_metadata(const teca_metadata &md);
356 
357  /// serialize the dataset to the given stream for I/O or communication
358  virtual int to_stream(teca_binary_stream &) const;
359 
360  /// deserialize the dataset from the given stream for I/O or communication
361  virtual int from_stream(teca_binary_stream &);
362 
363  /// send to stream in a human readable representation
364  virtual int to_stream(std::ostream &) const;
365 
366  /// read from stream in a human readable representation
367  virtual int from_stream(std::istream &);
368 
369 protected:
370  teca_dataset();
371 
372  teca_dataset(const teca_dataset &) = delete;
373  teca_dataset(const teca_dataset &&) = delete;
374 
375  void operator=(const p_teca_dataset &other) = delete;
376  void operator=(p_teca_dataset &&other) = delete;
377 
378  teca_metadata *metadata;
379 };
380 
381 #endif
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:17
Interface for TECA datasets.
Definition: teca_dataset.h:232
virtual void swap(const p_teca_dataset &other)
swap internals of the two objects
virtual p_teca_dataset new_copy(allocator alloc=allocator::malloc) const =0
virtual bool empty() const noexcept
Definition: teca_dataset.h:300
virtual teca_metadata & get_metadata() noexcept
get the dataset metadata
virtual p_teca_dataset new_instance() const =0
virtual constructor. return a new dataset of the same type.
virtual p_teca_dataset new_shallow_copy()=0
virtual void copy_metadata(const const_p_teca_dataset &other)
copy metadata. always a deep copy.
virtual void shallow_copy(const p_teca_dataset &other)
virtual void copy(const const_p_teca_dataset &other, allocator alloc=allocator::malloc)
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:22
hamr::buffer_allocator allocator
allocator types
Definition: teca_variant_array.h:46
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.