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