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  template<typename T>
73  int set(const std::string &name, std::initializer_list<T> val);
74 
75  // insert or update a vector of vectors.
76  template<typename T>
77  int set(const std::string &name, const std::vector<std::vector<T>> &val);
78 
79  // insert a variant array directly. if the property doesn't exist
80  // it is created. if it does it is replaced.
81  int set(const std::string &name, const p_teca_variant_array &prop_val);
82 
83  template<typename T>
84  int set(const std::string &name,
85  const p_teca_variant_array_impl<T> &prop_val);
86 
87  // append a value to the named property. if the property doesn't
88  // exist it is created. return 0 on success.
89  template<typename T>
90  int append(const std::string &name, const T &val);
91 
92  // update a scalar. Fails if the property isn't already in the collection.
93  template<typename T>
94  int update(const std::string &name, const T &val)
95  { return this->update<T>(name, 0, val); }
96 
97  // update the ith value from a scalar. Fails if the property isn't
98  // already in the collection.
99  template<typename T>
100  int update(const std::string &name, unsigned int i, const T &val);
101 
102  // update an array of length n. Fails if the property isn't already
103  // in the collection.
104  template<typename T>
105  int update(const std::string &name, const T *val, unsigned int n);
106 
107  // update a vector. Fails if the property isn't already in the collection.
108  template<typename T>
109  int update(const std::string &name, const std::vector<T> &val);
110 
111  template<typename T>
112  int update(const std::string &name, std::initializer_list<T> val);
113 
114  // update a set. Fails if the property isn't already in the collection.
115  template<typename T>
116  int update(const std::string &name, const std::set<T> &val);
117 
118  // update a variant array directly.
119  // property exists.
120  int update(const std::string &name, p_teca_variant_array prop_val);
121 
122  // get prop value. return 0 if successful
123  template<typename T>
124  int get(const std::string &name, T &val) const
125  { return this->get<T>(name, (unsigned int)(0), val); }
126 
127  // get ith prop value. return 0 if successful
128  template<typename T>
129  int get(const std::string &name, unsigned int i, T &val) const;
130 
131  // get n prop values to an array. see also get_size.
132  // return 0 if successful
133  template<typename T>
134  int get(const std::string &name,
135  T *val, unsigned int n) const;
136 
137  template<typename T, unsigned int N>
138  int get(const std::string &name, T (&val)[N]) const
139  { return this->get(name, val, N); }
140 
141  // copy prop values from the named prop into the passed in vector.
142  // return 0 if successful
143  template<typename T>
144  int get(const std::string &name, std::vector<T> &val) const;
145 
146  // copy prop values from the named prop into the passed in set.
147  // return 0 if successful
148  template<typename T>
149  int get(const std::string &name, std::set<T> &val) const;
150 
151  // copy prop values from the named prop into the passed in
152  // array. return 0 if successful
153  int get(const std::string &name, p_teca_variant_array val) const;
154 
155  // get the variant array, or nullptr if the
156  // property doesn't exist
157  p_teca_variant_array get(const std::string &name);
158  const_p_teca_variant_array get(const std::string &name) const;
159 
160  // get the name of the ith name value pair
161  // return 0 if i is valid index.
162  int get_name(unsigned long i, std::string &name) const;
163 
164  // get the names of all name, value pairs. returns 0
165  // if there are any properties.
166  int get_names(std::vector<std::string> &names) const;
167 
168  // remove. return 0 if successful
169  int remove(const std::string &name) noexcept;
170 
171  // remove all
172  void clear();
173 
174  // returns true if there is a property with the given
175  // name already in the container.
176  int has(const std::string &name) const noexcept;
177 
178  // return true if empty
179  int empty() const noexcept;
180 
181  // return true if not empty
182  explicit operator bool() const noexcept
183  { return !empty(); }
184 
185  // serialize to/from binary
186  int to_stream(teca_binary_stream &s) const;
187  int from_stream(teca_binary_stream &s);
188 
189  // serialize to/from ASCII
190  int to_stream(std::ostream &os) const;
191  int from_stream(std::ostream &) { return -1; }
192 
193 private:
194  unsigned long long get_next_id() const noexcept;
195 
196 private:
197  unsigned long long id;
198  using prop_map_t = std::map<std::string, p_teca_variant_array>;
199  prop_map_t props;
200 
201  friend bool operator<(const teca_metadata &, const teca_metadata &) noexcept;
202  friend bool operator==(const teca_metadata &, const teca_metadata &) noexcept;
203  friend teca_metadata operator&(const teca_metadata &, const teca_metadata &);
204 };
205 
206 // comparison function so that metadata can be
207 // used as a key in std::map.
209 bool operator<(const teca_metadata &lhs, const teca_metadata &rhs) noexcept;
210 
211 // compare meta data objects. two objects are considered
212 // equal if both have the same set of keys and all of the values
213 // are equal
215 bool operator==(const teca_metadata &lhs, const teca_metadata &rhs) noexcept;
216 
217 inline
218 bool operator!=(const teca_metadata &lhs, const teca_metadata &rhs) noexcept
219 { return !(lhs == rhs); }
220 
221 // intersect two metadata objects. return a new object with
222 // common key value pairs
224 teca_metadata operator&(const teca_metadata &lhs, const teca_metadata &rhs);
225 
226 // --------------------------------------------------------------------------
227 template<typename T>
228 void teca_metadata::declare(const std::string &name)
229 {
230  p_teca_variant_array prop_val
232 
233  this->set(name, prop_val);
234 }
235 
236 // --------------------------------------------------------------------------
237 template<typename T>
238 void teca_metadata::declare(const std::string &name, unsigned int n)
239 {
240  p_teca_variant_array prop_val
242 
243  this->set(name, prop_val);
244 }
245 
246 // --------------------------------------------------------------------------
247 template<typename T>
248 int teca_metadata::append(const std::string &name, const T &val)
249 {
250  prop_map_t::iterator it = this->props.find(name);
251  if (it == this->props.end())
252  {
253  return this->set(name, val);
254  }
255 
256  it->second->append(val);
257 
258  return 0;
259 }
260 
261 // --------------------------------------------------------------------------
262 template<typename T>
263 int teca_metadata::set(const std::string &name, const T &val)
264 {
265  p_teca_variant_array prop_val
267 
268  return this->set(name, prop_val);
269 }
270 
271 // --------------------------------------------------------------------------
272 template<typename T>
273 int teca_metadata::set(const std::string &name, const T *vals,
274  unsigned int n_vals)
275 {
276  p_teca_variant_array prop_val
277  = teca_variant_array_impl<T>::New(n_vals, vals);
278 
279  return this->set(name, prop_val);
280 }
281 
282 // --------------------------------------------------------------------------
283 template<typename T>
284 int teca_metadata::set(const std::string &name, const std::set<T> &vals)
285 {
286  size_t n = vals.size();
287 
288  std::vector<T> tmp(vals.begin(), vals.end());
289 
290  p_teca_variant_array prop_val
291  = teca_variant_array_impl<T>::New(n, tmp.data());
292 
293  return this->set(name, prop_val);
294 }
295 
296 // --------------------------------------------------------------------------
297 template<typename T>
298 int teca_metadata::set(const std::string &name,
299  std::initializer_list<T> vals)
300 {
301  return this->set(name, std::vector<T>(vals));
302 }
303 
304 // --------------------------------------------------------------------------
305 template<typename T>
306 int teca_metadata::set(const std::string &name,
307  const std::vector<T> &vals)
308 {
309  size_t n = vals.size();
310 
311  p_teca_variant_array prop_val
312  = teca_variant_array_impl<T>::New(n, vals.data());
313 
314  return this->set(name, prop_val);
315 }
316 
317 // --------------------------------------------------------------------------
318 template<typename T>
319 int teca_metadata::set(const std::string &name,
320  const std::vector<std::vector<T>> &vals)
321 {
322  size_t n = vals.size();
323 
324  p_teca_variant_array prop_vals
326 
327  for (size_t i = 0; i < n; ++i)
328  {
329  p_teca_variant_array prop_val
330  = teca_variant_array_impl<T>::New(vals.at(i).size(), vals.at(i).data());
331  prop_vals->append(prop_val);
332  }
333 
334  return this->set(name, prop_vals);
335 }
336 
337 // --------------------------------------------------------------------------
338 template<typename T>
339 int teca_metadata::set(const std::string &name,
340  const p_teca_variant_array_impl<T> &prop_val)
341 {
342  this->props[name] = prop_val;
343  return 0;
344 }
345 
346 // --------------------------------------------------------------------------
347 template<typename T>
348 int teca_metadata::update(const std::string &name, unsigned int i, const T &val)
349 {
350  prop_map_t::iterator it = this->props.find(name);
351  if (it == this->props.end())
352  {
353  TECA_ERROR(
354  << "attempt to access non-existent property \""
355  << name << "\" ignored!")
356  return -1;
357  }
358 
359  it->second->set(i, val);
360 
361  return 0;
362 }
363 
364 // --------------------------------------------------------------------------
365 template<typename T>
366 int teca_metadata::update(const std::string &name,
367  const T *vals, unsigned int n_vals)
368 {
369  prop_map_t::iterator it = this->props.find(name);
370  if (it == this->props.end())
371  {
372  TECA_ERROR(
373  << "attempt to access non-existent property \""
374  << name << "\" ignored!")
375  return -1;
376  }
377 
378  it->second->set(0, n_vals-1, vals);
379 
380  return 0;
381 }
382 
383 // --------------------------------------------------------------------------
384 template<typename T>
385 int teca_metadata::update(const std::string &name, const std::vector<T> &vals)
386 {
387  prop_map_t::iterator it = this->props.find(name);
388  if (it == this->props.end())
389  {
390  TECA_ERROR(
391  << "attempt to access non-existent property \""
392  << name << "\" ignored!")
393  return -1;
394  }
395 
396  it->second->set(vals);
397 
398  return 0;
399 }
400 
401 // --------------------------------------------------------------------------
402 template<typename T>
403 int teca_metadata::update(const std::string &name, std::initializer_list<T> vals)
404 {
405  return this->update(name, std::vector<T>(vals));
406 }
407 
408 // --------------------------------------------------------------------------
409 template<typename T>
410 int teca_metadata::update(const std::string &name, const std::set<T> &vals)
411 {
412  prop_map_t::iterator it = this->props.find(name);
413  if (it == this->props.end())
414  {
415  TECA_ERROR(
416  << "attempt to access non-existent property \""
417  << name << "\" ignored!")
418  return -1;
419  }
420 
421  std::vector<T> tmp(vals.begin(), vals.end());
422  it->second->set(tmp);
423 
424  return 0;
425 }
426 
427 // --------------------------------------------------------------------------
428 template<typename T>
429 int teca_metadata::get(const std::string &name, unsigned int i, T &val) const
430 {
431  prop_map_t::const_iterator it = this->props.find(name);
432 
433  if (it == this->props.end())
434  return -1;
435 
436  if (it->second->size() <= i)
437  {
438  TECA_ERROR("Requested element " << i << " in property \""
439  << name << "\" of length " << it->second->size())
440  return -1;
441  }
442 
443  it->second->get(i, val);
444 
445  return 0;
446 }
447 
448 // --------------------------------------------------------------------------
449 template<typename T>
450 int teca_metadata::get(const std::string &name, std::vector<T> &vals) const
451 {
452  prop_map_t::const_iterator it = this->props.find(name);
453 
454  if (it == this->props.end())
455  return -1;
456 
457  it->second->get(vals);
458 
459  return 0;
460 }
461 
462 // --------------------------------------------------------------------------
463 template<typename T>
464 int teca_metadata::get(const std::string &name, std::set<T> &vals) const
465 {
466  std::vector<T> tmp;
467  if (!this->get(name, tmp))
468  {
469  vals = std::set<T>(tmp.begin(), tmp.end());
470  return 0;
471  }
472  return -1;
473 }
474 
475 // --------------------------------------------------------------------------
476 template<typename T>
477 int teca_metadata::get(const std::string &name,
478  T *vals, unsigned int n) const
479 {
480  prop_map_t::const_iterator it = this->props.find(name);
481 
482  if (it == this->props.end())
483  return -1;
484 
485  if (it->second->size() < n)
486  {
487  TECA_ERROR("Requested " << n << " values in property \""
488  << name << "\" of length " << it->second->size())
489  return -1;
490  }
491 
492  it->second->get(0, vals, 0, n);
493 
494  return 0;
495 }
496 
497 // convenience defs for nesting metadata
499 using p_teca_metadata_array = std::shared_ptr<teca_variant_array_impl<teca_metadata>>;
500 using const_p_teca_metadata_array = std::shared_ptr<const teca_variant_array_impl<teca_metadata>>;
501 
502 #endif
teca_variant_array.h
teca_binary_stream
Serialize objects into a binary stream.
Definition: teca_binary_stream.h:16
teca_metadata
A generic container for meta data in the form of name=value pairs.
Definition: teca_metadata.h:21
teca_variant_array_impl
The concrete implementation of our type agnostic container for contiguous arrays.
Definition: teca_variant_array_impl.h:39
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
const_p_teca_variant_array
std::shared_ptr< const teca_variant_array > const_p_teca_variant_array
Definition: teca_variant_array.h:27
p_teca_variant_array
std::shared_ptr< teca_variant_array > p_teca_variant_array
Definition: teca_variant_array.h:27
teca_error::TECA_EXPORT
p_teca_error_handler error_handler TECA_EXPORT
The global error handler instance.
p_teca_variant_array_impl
std::shared_ptr< teca_variant_array_impl< T > > p_teca_variant_array_impl
Definition: teca_variant_array_impl.h:39
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_ERROR
#define TECA_ERROR(_msg)
Constructs an error message and sends it to the stderr stream.
Definition: teca_common.h:146
teca_variant_array_impl.h
teca_variant_array_impl::New
static std::shared_ptr< teca_variant_array_impl< T > > New()
Definition: teca_variant_array_impl.h:326