TECA
The Toolkit for Extreme Climate Analysis
teca_metadata.h
1 #ifndef teca_metadata_h
2 #define teca_metadata_h
3 
4 #include "teca_config.h"
5 #include "teca_variant_array.h"
7 
8 #include <iosfwd>
9 #include <map>
10 #include <string>
11 #include <initializer_list>
12 #include <vector>
13 #include <set>
14 
15 /// A generic container for meta data in the form of name=value pairs.
16 /**
17  * Value arrays are supported. See metadata
18  * producer-consumer documentation for
19  * information about what names are valid.
20  */
22 {
23 public:
24  teca_metadata() noexcept;
25  ~teca_metadata() noexcept;
26 
27  teca_metadata(const teca_metadata &other);
28  teca_metadata &operator=(const teca_metadata &other);
29 
30  teca_metadata(teca_metadata &&other) noexcept;
31  teca_metadata &operator=(teca_metadata &&other) noexcept;
32 
33  // get the number of name value pairs stored in the container
34  unsigned int size() const { return props.size(); }
35 
36  // get the length of the named property. return 0 if successful
37  int size(const std::string &name,
38  unsigned int &size) const noexcept;
39 
40  // resize the named property
41  void resize(const std::string &name, unsigned int n);
42 
43  // declare a property. properties must be declared or inserted
44  // before accessing them via set/get.
45  template<typename T>
46  void declare(const std::string &name);
47 
48  template<typename T>
49  void declare(const std::string &name, unsigned int n);
50 
51  // insert or update a scalar value. if the property doesn't exist
52  // it is created. if it does its value is updated
53  template<typename T>
54  int set(const std::string &name, const T &val);
55 
56  // insert or update an array of length n.
57  template<typename T>
58  int set(const std::string &name, const T *val, unsigned int n);
59 
60  template<typename T, unsigned int N>
61  int set(const std::string &name, const T (&val)[N])
62  { return this->set(name, val, N); }
63 
64  // insert or update a set.
65  template<typename T>
66  int set(const std::string &name, const std::set<T> &val);
67 
68  // insert or update a vector.
69  template<typename T>
70  int set(const std::string &name, const std::vector<T> &val);
71 
72  // insert or update an array.
73  template<typename T, size_t N>
74  int set(const std::string &name, const std::array<T,N> &val);
75 
76  template<typename T>
77  int set(const std::string &name, std::initializer_list<T> val);
78 
79  // insert or update a vector of vectors.
80  template<typename T>
81  int set(const std::string &name, const std::vector<std::vector<T>> &val);
82 
83  // insert a variant array directly. if the property doesn't exist
84  // it is created. if it does it is replaced.
85  int set(const std::string &name, const p_teca_variant_array &prop_val);
86 
87  template<typename T>
88  int set(const std::string &name,
89  const p_teca_variant_array_impl<T> &prop_val);
90 
91  // append a value to the named property. if the property doesn't
92  // exist it is created. return 0 on success.
93  template<typename T>
94  int append(const std::string &name, const T &val);
95 
96  // update a scalar. Fails if the property isn't already in the collection.
97  template<typename T>
98  int update(const std::string &name, const T &val)
99  { return this->update<T>(name, 0, val); }
100 
101  // update the ith value from a scalar. Fails if the property isn't
102  // already in the collection.
103  template<typename T>
104  int update(const std::string &name, unsigned int i, const T &val);
105 
106  // update an array of length n. Fails if the property isn't already
107  // in the collection.
108  template<typename T>
109  int update(const std::string &name, const T *val, unsigned int n);
110 
111  // update a vector. Fails if the property isn't already in the collection.
112  template<typename T>
113  int update(const std::string &name, const std::vector<T> &val);
114 
115  // update a vector. Fails if the property isn't already in the collection.
116  template<typename T, size_t N>
117  int update(const std::string &name, const std::array<T,N> &val);
118 
119  template<typename T>
120  int update(const std::string &name, std::initializer_list<T> val);
121 
122  // update a set. Fails if the property isn't already in the collection.
123  template<typename T>
124  int update(const std::string &name, const std::set<T> &val);
125 
126  // update a variant array directly.
127  // property exists.
128  int update(const std::string &name, p_teca_variant_array prop_val);
129 
130  // get prop value. return 0 if successful
131  template<typename T>
132  int get(const std::string &name, T &val) const
133  { return this->get<T>(name, (unsigned int)(0), val); }
134 
135  // get ith prop value. return 0 if successful
136  template<typename T>
137  int get(const std::string &name, unsigned int i, T &val) const;
138 
139  // get n prop values to an array. see also get_size.
140  // return 0 if successful
141  template<typename T>
142  int get(const std::string &name,
143  T *val, unsigned int n) const;
144 
145  template<typename T, unsigned int N>
146  int get(const std::string &name, T (&val)[N]) const
147  { return this->get(name, val, N); }
148 
149  // copy prop values from the named prop into the passed in vector.
150  // return 0 if successful
151  template<typename T>
152  int get(const std::string &name, std::vector<T> &val) const;
153 
154  // copy prop values from the named prop into the passed in array.
155  // return 0 if successful
156  template<typename T, size_t N>
157  int get(const std::string &name, std::array<T,N> &val) const;
158 
159  // copy prop values from the named prop into the passed in set.
160  // return 0 if successful
161  template<typename T>
162  int get(const std::string &name, std::set<T> &val) const;
163 
164  // copy prop values from the named prop into the passed in
165  // array. return 0 if successful
166  int get(const std::string &name, p_teca_variant_array val) const;
167 
168  // get the variant array, or nullptr if the
169  // property doesn't exist
170  p_teca_variant_array get(const std::string &name);
171  const_p_teca_variant_array get(const std::string &name) const;
172 
173  // get the name of the ith name value pair
174  // return 0 if i is valid index.
175  int get_name(unsigned long i, std::string &name) const;
176 
177  // get the names of all name, value pairs. returns 0
178  // if there are any properties.
179  int get_names(std::vector<std::string> &names) const;
180 
181  // remove. return 0 if successful
182  int remove(const std::string &name) noexcept;
183 
184  // remove all
185  void clear();
186 
187  // returns true if there is a property with the given
188  // name already in the container.
189  int has(const std::string &name) const noexcept;
190 
191  // return true if empty
192  int empty() const noexcept;
193 
194  // return true if not empty
195  explicit operator bool() const noexcept
196  { return !empty(); }
197 
198  // serialize to/from binary
199  int to_stream(teca_binary_stream &s) const;
200  int from_stream(teca_binary_stream &s);
201 
202  // serialize to/from ASCII
203  int to_stream(std::ostream &os) const;
204  int from_stream(std::ostream &) { return -1; }
205 
206 private:
207  unsigned long long get_next_id() const noexcept;
208 
209 private:
210  unsigned long long id;
211  using prop_map_t = std::map<std::string, p_teca_variant_array>;
212  prop_map_t props;
213 
214  friend bool operator<(const teca_metadata &, const teca_metadata &) noexcept;
215  friend bool operator==(const teca_metadata &, const teca_metadata &) noexcept;
216  friend teca_metadata operator&(const teca_metadata &, const teca_metadata &);
217 };
218 
219 // comparison function so that metadata can be
220 // used as a key in std::map.
222 bool operator<(const teca_metadata &lhs, const teca_metadata &rhs) noexcept;
223 
224 // compare meta data objects. two objects are considered
225 // equal if both have the same set of keys and all of the values
226 // are equal
228 bool operator==(const teca_metadata &lhs, const teca_metadata &rhs) noexcept;
229 
230 inline
231 bool operator!=(const teca_metadata &lhs, const teca_metadata &rhs) noexcept
232 { return !(lhs == rhs); }
233 
234 // intersect two metadata objects. return a new object with
235 // common key value pairs
237 teca_metadata operator&(const teca_metadata &lhs, const teca_metadata &rhs);
238 
239 // --------------------------------------------------------------------------
240 template<typename T>
241 void teca_metadata::declare(const std::string &name)
242 {
243  p_teca_variant_array prop_val
245 
246  this->set(name, prop_val);
247 }
248 
249 // --------------------------------------------------------------------------
250 template<typename T>
251 void teca_metadata::declare(const std::string &name, unsigned int n)
252 {
253  p_teca_variant_array prop_val
255 
256  this->set(name, prop_val);
257 }
258 
259 // --------------------------------------------------------------------------
260 template<typename T>
261 int teca_metadata::append(const std::string &name, const T &val)
262 {
263  prop_map_t::iterator it = this->props.find(name);
264  if (it == this->props.end())
265  {
266  return this->set(name, val);
267  }
268 
269  it->second->append(val);
270 
271  return 0;
272 }
273 
274 // --------------------------------------------------------------------------
275 template<typename T>
276 int teca_metadata::set(const std::string &name, const T &val)
277 {
278  p_teca_variant_array prop_val
280 
281  return this->set(name, prop_val);
282 }
283 
284 // --------------------------------------------------------------------------
285 template<typename T>
286 int teca_metadata::set(const std::string &name, const T *vals,
287  unsigned int n_vals)
288 {
289  p_teca_variant_array prop_val
290  = teca_variant_array_impl<T>::New(n_vals, vals);
291 
292  return this->set(name, prop_val);
293 }
294 
295 // --------------------------------------------------------------------------
296 template<typename T>
297 int teca_metadata::set(const std::string &name, const std::set<T> &vals)
298 {
299  size_t n = vals.size();
300 
301  std::vector<T> tmp(vals.begin(), vals.end());
302 
303  p_teca_variant_array prop_val
304  = teca_variant_array_impl<T>::New(n, tmp.data());
305 
306  return this->set(name, prop_val);
307 }
308 
309 // --------------------------------------------------------------------------
310 template<typename T>
311 int teca_metadata::set(const std::string &name,
312  std::initializer_list<T> vals)
313 {
314  return this->set(name, std::vector<T>(vals));
315 }
316 
317 // --------------------------------------------------------------------------
318 template<typename T>
319 int teca_metadata::set(const std::string &name,
320  const std::vector<T> &vals)
321 {
322  size_t n = vals.size();
323 
324  p_teca_variant_array prop_val
325  = teca_variant_array_impl<T>::New(n, vals.data());
326 
327  return this->set(name, prop_val);
328 }
329 
330 // --------------------------------------------------------------------------
331 template<typename T, size_t N>
332 int teca_metadata::set(const std::string &name, const std::array<T,N> &vals)
333 {
334  p_teca_variant_array prop_val
335  = teca_variant_array_impl<T>::New(N, vals.data());
336 
337  return this->set(name, prop_val);
338 }
339 
340 // --------------------------------------------------------------------------
341 template<typename T>
342 int teca_metadata::set(const std::string &name,
343  const std::vector<std::vector<T>> &vals)
344 {
345  size_t n = vals.size();
346 
347  p_teca_variant_array prop_vals
349 
350  for (size_t i = 0; i < n; ++i)
351  {
352  p_teca_variant_array prop_val
353  = teca_variant_array_impl<T>::New(vals.at(i).size(), vals.at(i).data());
354  prop_vals->append(prop_val);
355  }
356 
357  return this->set(name, prop_vals);
358 }
359 
360 // --------------------------------------------------------------------------
361 template<typename T>
362 int teca_metadata::set(const std::string &name,
363  const p_teca_variant_array_impl<T> &prop_val)
364 {
365  this->props[name] = prop_val;
366  return 0;
367 }
368 
369 // --------------------------------------------------------------------------
370 template<typename T>
371 int teca_metadata::update(const std::string &name, unsigned int i, const T &val)
372 {
373  prop_map_t::iterator it = this->props.find(name);
374  if (it == this->props.end())
375  {
376  TECA_ERROR(
377  << "attempt to access non-existent property \""
378  << name << "\" ignored!")
379  return -1;
380  }
381 
382  it->second->set(i, val);
383 
384  return 0;
385 }
386 
387 // --------------------------------------------------------------------------
388 template<typename T>
389 int teca_metadata::update(const std::string &name,
390  const T *vals, unsigned int n_vals)
391 {
392  prop_map_t::iterator it = this->props.find(name);
393  if (it == this->props.end())
394  {
395  TECA_ERROR(
396  << "attempt to access non-existent property \""
397  << name << "\" ignored!")
398  return -1;
399  }
400 
401  it->second->set(0, n_vals-1, vals);
402 
403  return 0;
404 }
405 
406 // --------------------------------------------------------------------------
407 template<typename T>
408 int teca_metadata::update(const std::string &name, const std::vector<T> &vals)
409 {
410  prop_map_t::iterator it = this->props.find(name);
411  if (it == this->props.end())
412  {
413  TECA_ERROR(
414  << "attempt to access non-existent property \""
415  << name << "\" ignored!")
416  return -1;
417  }
418 
419  it->second->set(vals);
420 
421  return 0;
422 }
423 
424 // --------------------------------------------------------------------------
425 template<typename T, size_t N>
426 int teca_metadata::update(const std::string &name, const std::array<T,N> &vals)
427 {
428  return this->update(name, vals.data(), N);
429 }
430 
431 // --------------------------------------------------------------------------
432 template<typename T>
433 int teca_metadata::update(const std::string &name, std::initializer_list<T> vals)
434 {
435  return this->update(name, std::vector<T>(vals));
436 }
437 
438 // --------------------------------------------------------------------------
439 template<typename T>
440 int teca_metadata::update(const std::string &name, const std::set<T> &vals)
441 {
442  prop_map_t::iterator it = this->props.find(name);
443  if (it == this->props.end())
444  {
445  TECA_ERROR(
446  << "attempt to access non-existent property \""
447  << name << "\" ignored!")
448  return -1;
449  }
450 
451  std::vector<T> tmp(vals.begin(), vals.end());
452  it->second->set(tmp);
453 
454  return 0;
455 }
456 
457 // --------------------------------------------------------------------------
458 template<typename T>
459 int teca_metadata::get(const std::string &name, unsigned int i, T &val) const
460 {
461  prop_map_t::const_iterator it = this->props.find(name);
462 
463  if (it == this->props.end())
464  return -1;
465 
466  if (it->second->size() <= i)
467  {
468  TECA_ERROR("Requested element " << i << " in property \""
469  << name << "\" of length " << it->second->size())
470  return -1;
471  }
472 
473  it->second->get(i, val);
474 
475  return 0;
476 }
477 
478 // --------------------------------------------------------------------------
479 template<typename T>
480 int teca_metadata::get(const std::string &name, std::vector<T> &vals) const
481 {
482  prop_map_t::const_iterator it = this->props.find(name);
483 
484  if (it == this->props.end())
485  return -1;
486 
487  it->second->get(vals);
488 
489  return 0;
490 }
491 
492 // --------------------------------------------------------------------------
493 template<typename T, size_t N>
494 int teca_metadata::get(const std::string &name, std::array<T,N> &vals) const
495 {
496  return this->get(name, vals.data(), N);
497 }
498 
499 // --------------------------------------------------------------------------
500 template<typename T>
501 int teca_metadata::get(const std::string &name, std::set<T> &vals) const
502 {
503  std::vector<T> tmp;
504  if (!this->get(name, tmp))
505  {
506  vals = std::set<T>(tmp.begin(), tmp.end());
507  return 0;
508  }
509  return -1;
510 }
511 
512 // --------------------------------------------------------------------------
513 template<typename T>
514 int teca_metadata::get(const std::string &name,
515  T *vals, unsigned int n) const
516 {
517  prop_map_t::const_iterator it = this->props.find(name);
518 
519  if (it == this->props.end())
520  return -1;
521 
522  if (it->second->size() < n)
523  {
524  TECA_ERROR("Requested " << n << " values in property \""
525  << name << "\" of length " << it->second->size())
526  return -1;
527  }
528 
529  it->second->get(0, vals, 0, n);
530 
531  return 0;
532 }
533 
534 // convenience defs for nesting metadata
536 using p_teca_metadata_array = std::shared_ptr<teca_variant_array_impl<teca_metadata>>;
537 using const_p_teca_metadata_array = std::shared_ptr<const teca_variant_array_impl<teca_metadata>>;
538 
539 #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
static std::shared_ptr< teca_variant_array_impl< T > > New()
Definition: teca_variant_array_impl.h:393
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
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:161
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
std::shared_ptr< teca_variant_array_impl< T > > p_teca_variant_array_impl
Definition: teca_variant_array_impl.h:44