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