ome-files  0.5.0
MetadataMap.h
1 /*
2  * #%L
3  * OME-FILES C++ library for image IO.
4  * Copyright © 2006 - 2015 Open Microscopy Environment:
5  * - Massachusetts Institute of Technology
6  * - National Institutes of Health
7  * - University of Dundee
8  * - Board of Regents of the University of Wisconsin-Madison
9  * - Glencoe Software, Inc.
10  * %%
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  * this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  * The views and conclusions contained in the software and documentation are
33  * those of the authors and should not be interpreted as representing official
34  * policies, either expressed or implied, of any organization.
35  * #L%
36  */
37 
38 #ifndef OME_FILES_METADATAMAP_H
39 #define OME_FILES_METADATAMAP_H
40 
41 #include <algorithm>
42 #include <cmath>
43 #include <cstdint>
44 #include <iomanip>
45 #include <map>
46 #include <ostream>
47 #include <sstream>
48 #include <string>
49 #include <vector>
50 
51 #include <ome/common/variant.h>
52 
53 namespace ome
54 {
55  namespace files
56  {
57 
80  {
81  private:
82  /*
83  * The following series of typedefs may appear a little
84  * complicated, and perhaps unnecessary, but they do have a
85  * purpose. They exist to work around pre-C++11 compiler
86  * limitations (lack of variadic templates), primarily a limit
87  * to the maximum number of types which may be used with
88  * boost::variant. To exceed this limit (minimum guaranteed is
89  * 10), boost::mpl sequences are used to define the variant
90  * types. These also have length limits, so the type list is
91  * built up by defining separate type sequences, then
92  * concatenating them, and transforming them to provide list
93  * variants. Note that none of this is code per se; it's all
94  * compile-time template expansion which evaluates to a list of
95  * permitted types.
96  */
97 
99  typedef boost::mpl::vector<std::string,
101 
103  typedef boost::mpl::vector<uint8_t,
104  uint16_t,
105  uint32_t,
106  uint64_t,
107  int8_t,
108  int16_t,
109  int32_t,
110  int64_t> integer_types;
111 
113  typedef boost::mpl::vector<float,
114  double,
115  long double> float_types;
116 
118  typedef boost::mpl::joint_view<integer_types,
119  float_types>::type numeric_types_view;
120 
122  typedef boost::mpl::joint_view<non_numeric_types,
123  numeric_types_view>::type basic_types_view;
124 
126  template<typename T>
127  struct make_vector
128  {
130  typedef std::vector<T> type;
131  };
132 
134  typedef boost::mpl::transform_view<basic_types_view, make_vector<boost::mpl::_1>>::type list_types_view;
135 
137  typedef boost::mpl::joint_view<basic_types_view, list_types_view> all_types_view;
138 
140  typedef boost::mpl::insert_range<boost::mpl::vector0<>, boost::mpl::end<boost::mpl::vector0<>>::type, all_types_view>::type discriminated_types;
141 
142  public:
144  typedef std::string key_type;
145 
147  typedef boost::make_variant_over<discriminated_types>::type value_type;
148 
150  typedef std::map<key_type, value_type> map_type;
151 
153  typedef map_type::size_type size_type;
154 
156  typedef map_type::iterator iterator;
157 
159  typedef map_type::const_iterator const_iterator;
160 
162  typedef map_type::reverse_iterator reverse_iterator;
163 
165  typedef map_type::const_reverse_iterator const_reverse_iterator;
166 
167  private:
170 
171  public:
174  {}
175 
178  {}
179 
189  void
190  set(const key_type& key,
191  const value_type& value)
192  {
193  iterator i = find(key);
194  if (i != end())
195  erase(i);
196  map_type::value_type newvalue(key, value);
197  insert(newvalue);
198  }
199 
209  template <typename T>
210  void
211  set(const key_type& key,
212  const T& value)
213  {
214  value_type v = value;
215  set(key, v);
216  }
217 
228  template <typename T>
229  void
230  append(const key_type& key,
231  const T& value)
232  {
233  typedef typename std::vector<T> list_type;
234 
235  try
236  {
237  list_type& list(get<list_type>(key));
238  list.push_back(value);
239  }
240  catch (const boost::bad_get&)
241  {
242  list_type new_list;
243  new_list.push_back(value);
244  set(key, new_list);
245  }
246  }
247 
257  bool
258  get(const key_type& key,
259  value_type& value) const
260  {
261  const_iterator i = find(key);
262  if (i == end())
263  return false;
264 
265  value = i->second;
266  return true;
267  }
268 
280  template <typename T>
281  bool
282  get(const key_type& key,
283  T& value) const
284  {
285  try
286  {
287  value = get<T>(key);
288  return true;
289  }
290  catch (const boost::bad_get&)
291  {
292  return false;
293  }
294  }
295 
307  template <typename T>
308  T&
309  get(const key_type& key)
310  {
311  return boost::get<T>(get<value_type>(key));
312  }
313 
325  template <typename T>
326  const T&
327  get(const key_type& key) const
328  {
329  return boost::get<T>(get<value_type>(key));
330  }
331 
338  iterator
339  find(const key_type& key)
340  {
341  return discriminating_map.find(key);
342  }
343 
350  const_iterator
351  find(const key_type& key) const
352  {
353  return discriminating_map.find(key);
354  }
355 
369  std::pair<iterator, bool>
370  insert(map_type::value_type& value)
371  {
372  return discriminating_map.insert(value);
373  }
374 
380  void
381  erase(const key_type& key)
382  {
383  discriminating_map.erase(key);
384  }
385 
391  void
392  erase(iterator pos)
393  {
394  discriminating_map.erase(pos);
395  }
396 
397  private:
399  struct getkey
400  {
407  template <typename T>
408  typename T::first_type operator()(T pair) const
409  {
410  return pair.first;
411  }
412  };
413 
414  public:
424  std::vector<key_type>
425  keys() const
426  {
427  std::vector<key_type> ret;
428  std::transform(begin(), end(), std::back_inserter(ret), getkey());
429  std::sort(ret.begin(), ret.end());
430 
431  return ret;
432  }
433 
441  void
443  const std::string& prefix)
444  {
445  for (const auto& m : map)
446  {
447  map_type::value_type v(prefix + m.first, m.second);
448  insert(v);
449  }
450  }
451 
462  flatten() const;
463 
469  map_type&
470  map()
471  {
472  return discriminating_map;
473  }
474 
480  const map_type&
481  map() const
482  {
483  return discriminating_map;
484  }
485 
491  iterator
493  {
494  return discriminating_map.begin();
495  }
496 
502  const_iterator
503  begin() const
504  {
505  return discriminating_map.begin();
506  }
507 
513  iterator
514  end()
515  {
516  return discriminating_map.end();
517  }
518 
524  const_iterator
525  end() const
526  {
527  return discriminating_map.end();
528  }
529 
535  reverse_iterator
537  {
538  return discriminating_map.rbegin();
539  }
540 
546  const_reverse_iterator
547  rbegin() const
548  {
549  return discriminating_map.rbegin();
550  }
551 
557  reverse_iterator
559  {
560  return discriminating_map.rend();
561  }
562 
568  const_reverse_iterator
569  rend() const
570  {
571  return discriminating_map.rend();
572  }
573 
584  value_type&
585  operator[] (const key_type& key)
586  {
587  return discriminating_map[key];
588  }
589 
596  bool
597  operator == (const MetadataMap& rhs) const
598  {
599  return discriminating_map == rhs.discriminating_map;
600  }
601 
608  bool
609  operator != (const MetadataMap& rhs) const
610  {
611  return discriminating_map != rhs.discriminating_map;
612  }
613 
620  bool
621  operator < (const MetadataMap& rhs) const
622  {
623  return discriminating_map < rhs.discriminating_map;
624  }
625 
633  bool
634  operator <= (const MetadataMap& rhs) const
635  {
636  return discriminating_map <= rhs.discriminating_map;
637  }
638 
645  bool
646  operator > (const MetadataMap& rhs) const
647  {
648  return discriminating_map > rhs.discriminating_map;
649  }
650 
658  bool
659  operator >= (const MetadataMap& rhs) const
660  {
661  return discriminating_map >= rhs.discriminating_map;
662  }
663 
672  size_type
673  size() const
674  {
675  return discriminating_map.size();
676  }
677 
683  bool
684  empty() const
685  {
686  return discriminating_map.empty();
687  }
688 
694  void
696  {
697  return discriminating_map.clear();
698  }
699  };
700 
701  namespace detail
702  {
703 
707  struct MetadataMapValueTypeOStreamVisitor : public boost::static_visitor<>
708  {
710  std::ostream& os;
711 
718  os(os)
719  {}
720 
728  template <typename T>
729  void
730  operator() (const std::vector<T> & c) const
731  {
732  for (typename std::vector<T>::const_iterator i = c.begin();
733  i != c.end();
734  ++i)
735  {
736  os << *i;
737  if (i + 1 != c.end())
738  os << ", ";
739  }
740  }
741 
747  template <typename T>
748  void
749  operator() (const T& v) const
750  {
751  os << v;
752  }
753  };
754 
758  struct MetadataMapOStreamVisitor : public boost::static_visitor<>
759  {
761  std::ostream& os;
764 
771  MetadataMapOStreamVisitor(std::ostream& os,
772  const MetadataMap::key_type& key):
773  os(os),
774  key(key)
775  {}
776 
787  template <typename T>
788  void
789  operator() (const std::vector<T> & c) const
790  {
791  typename std::vector<T>::size_type idx = 1;
792  // Determine the optimal padding based on the maximum digit count.
793  int sf = static_cast<int>(std::log10(static_cast<float>(c.size()))) + 1;
794  for (typename std::vector<T>::const_iterator i = c.begin();
795  i != c.end();
796  ++i, ++idx)
797  {
798  os << key << " #" << std::setw(sf) << std::setfill('0') << std::right << idx << " = " << *i << '\n';
799  }
800  }
801 
810  template <typename T>
811  void
812  operator() (const T& v) const
813  {
814  os << key << " = " << v << '\n';
815  }
816  };
817 
821  struct MetadataMapFlattenVisitor : public boost::static_visitor<>
822  {
827 
835  const MetadataMap::key_type& key):
836  map(map),
837  key(key)
838  {}
839 
850  template <typename T>
851  void
852  operator() (const std::vector<T> & c) const
853  {
854  typename std::vector<T>::size_type idx = 1;
855  // Determine the optimal padding based on the maximum digit count.
856  int sf = static_cast<int>(std::log10(static_cast<float>(c.size()))) + 1;
857  for (typename std::vector<T>::const_iterator i = c.begin();
858  i != c.end();
859  ++i, ++idx)
860  {
861  std::ostringstream os;
862  os << key << " #" << std::setw(sf) << std::setfill('0') << std::right << idx;
863  map.set(os.str(), *i);
864  }
865  }
866 
875  template <typename T>
876  void
877  operator() (const T& v) const
878  {
879  map.set(key, v);
880  }
881  };
882 
883  }
884 
896  template<>
898  MetadataMap::get<MetadataMap::value_type>(const key_type& key)
899  {
900  map_type::iterator i = discriminating_map.find(key);
901  if (i == discriminating_map.end())
902  throw boost::bad_get();
903 
904  return i->second;
905  }
906 
918  template<>
919  inline const MetadataMap::value_type&
920  MetadataMap::get<MetadataMap::value_type>(const key_type& key) const
921  {
922  map_type::const_iterator i = discriminating_map.find(key);
923  if (i == discriminating_map.end())
924  throw boost::bad_get();
925 
926  return i->second;
927  }
928 
929  inline
932  {
933  MetadataMap newmap;
934  for (const auto& m : discriminating_map)
935  {
936  boost::apply_visitor(detail::MetadataMapFlattenVisitor(newmap, m.first), m.second);
937  }
938  return newmap;
939  }
940 
941  }
942 }
943 
944 namespace std
945 {
946 
954  template<class charT, class traits>
955  inline basic_ostream<charT,traits>&
956  operator<< (basic_ostream<charT,traits>& os,
957  const ::ome::files::MetadataMap::value_type& vt)
958  {
959  boost::apply_visitor(::ome::files::detail::MetadataMapValueTypeOStreamVisitor(os), vt);
960  return os;
961  }
962 
970  template<class charT, class traits>
971  inline basic_ostream<charT,traits>&
972  operator<< (basic_ostream<charT,traits>& os,
973  const ::ome::files::MetadataMap& map)
974  {
975  for (const auto& m : map)
976  {
977  boost::apply_visitor(::ome::files::detail::MetadataMapOStreamVisitor(os, m.first), m.second);
978  }
979  return os;
980  }
981 
982 }
983 
984 #endif // OME_FILES_METADATAMAP_H
985 
986 /*
987  * Local Variables:
988  * mode:C++
989  * End:
990  */
const MetadataMap::key_type & key
The key of the value being flattened.
Definition: MetadataMap.h:826
void clear()
Clear the map.
Definition: MetadataMap.h:695
boost::mpl::transform_view< basic_types_view, make_vector< boost::mpl::_1 > >::type list_types_view
Aggregate view of all storable list types.
Definition: MetadataMap.h:134
map_type::reverse_iterator reverse_iterator
Reverse iterator.
Definition: MetadataMap.h:162
Visitor template for output of MetadataMap values to an ostream.
Definition: MetadataMap.h:758
boost::mpl::joint_view< basic_types_view, list_types_view > all_types_view
Aggregate view of all storable types.
Definition: MetadataMap.h:137
map_type & map()
Get the underlying map.
Definition: MetadataMap.h:470
reverse_iterator rend()
Get a reverse iterator to the beginning of the map.
Definition: MetadataMap.h:558
bool operator<=(const MetadataMap &rhs) const
Check if map is less than or equal to another map.
Definition: MetadataMap.h:634
boost::mpl::vector< std::string, bool > non_numeric_types
Storable non-numeric types.
Definition: MetadataMap.h:100
Functor to get a map key.
Definition: MetadataMap.h:399
bool operator==(const MetadataMap &rhs) const
Compare maps for equality.
Definition: MetadataMap.h:597
boost::make_variant_over< discriminated_types >::type value_type
Value type, allowing assignment of all storable types.
Definition: MetadataMap.h:147
MetadataMapValueTypeOStreamVisitor(std::ostream &os)
Constructor.
Definition: MetadataMap.h:717
boost::mpl::insert_range< boost::mpl::vector0<>, boost::mpl::end< boost::mpl::vector0<> >::type, all_types_view >::type discriminated_types
List of discriminated types used by boost::variant.
Definition: MetadataMap.h:140
void erase(iterator pos)
Erase a key from the map by an iterator position.
Definition: MetadataMap.h:392
STL namespace.
const_iterator begin() const
Get a constant iterator to the beginning of the map.
Definition: MetadataMap.h:503
std::pair< iterator, bool > insert(map_type::value_type &value)
Insert a value into the map.
Definition: MetadataMap.h:370
MetadataMap & map
The map in which to set the flattened elements.
Definition: MetadataMap.h:824
Metadata key-value map using a restricted set of value types.
Definition: MetadataMap.h:79
map_type discriminating_map
Key-value mapping.
Definition: MetadataMap.h:169
iterator begin()
Get an iterator to the beginning of the map.
Definition: MetadataMap.h:492
std::vector< T > type
The result type.
Definition: MetadataMap.h:130
std::vector< key_type > keys() const
Get a list of keys in the map.
Definition: MetadataMap.h:425
iterator find(const key_type &key)
Find a key in the map.
Definition: MetadataMap.h:339
bool operator>(const MetadataMap &rhs) const
Check if map is greater than another map.
Definition: MetadataMap.h:646
MetadataMap()
Constructor.
Definition: MetadataMap.h:173
Visitor template for flattening of MetadataMap vector values.
Definition: MetadataMap.h:821
Visitor template for output of MetadataMap values to an ostream.
Definition: MetadataMap.h:707
MetadataMapOStreamVisitor(std::ostream &os, const MetadataMap::key_type &key)
Constructor.
Definition: MetadataMap.h:771
Open Microscopy Environment C++.
const_iterator end() const
Get a constant iterator to the end of the map.
Definition: MetadataMap.h:525
~MetadataMap()
Destructor.
Definition: MetadataMap.h:177
std::string key_type
Key type.
Definition: MetadataMap.h:144
value_type & operator[](const key_type &key)
Get or set a value by key index.
Definition: MetadataMap.h:585
const_reverse_iterator rend() const
Get a constant reverse iterator to the beginning of the map.
Definition: MetadataMap.h:569
bool operator>=(const MetadataMap &rhs) const
Check if map is greater than or equal to another map.
Definition: MetadataMap.h:659
map_type::const_iterator const_iterator
Constant iterator.
Definition: MetadataMap.h:159
reverse_iterator rbegin()
Get a reverse iterator to the end of the map.
Definition: MetadataMap.h:536
boost::mpl::joint_view< non_numeric_types, numeric_types_view >::type basic_types_view
Aggregate view of all storable simple types.
Definition: MetadataMap.h:123
const MetadataMap::key_type & key
The key of the value being output.
Definition: MetadataMap.h:763
boost::mpl::vector< uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t > integer_types
Storable integer types.
Definition: MetadataMap.h:110
const_reverse_iterator rbegin() const
Get a constant reverse iterator to the end of the map.
Definition: MetadataMap.h:547
const_iterator find(const key_type &key) const
Find a key in the map.
Definition: MetadataMap.h:351
bool empty() const
Check if the map is empty.
Definition: MetadataMap.h:684
bool operator<(const MetadataMap &rhs) const
Check if map is less than another map.
Definition: MetadataMap.h:621
map_type::const_reverse_iterator const_reverse_iterator
Constant reverse iterator.
Definition: MetadataMap.h:165
void merge(const MetadataMap &map, const std::string &prefix)
Merge a separate map into this map.
Definition: MetadataMap.h:442
std::ostream & os
The stream to output to.
Definition: MetadataMap.h:761
void erase(const key_type &key)
Erase a key from the map by name.
Definition: MetadataMap.h:381
T::first_type operator()(T pair) const
Get key from pair.
Definition: MetadataMap.h:408
boost::mpl::vector< float, double, long double > float_types
Storable floating-point types.
Definition: MetadataMap.h:115
std::map< key_type, value_type > map_type
std::string to discriminated type mapping.
Definition: MetadataMap.h:150
bool operator!=(const MetadataMap &rhs) const
Compare maps for non-equality.
Definition: MetadataMap.h:609
const map_type & map() const
Get the underlying map.
Definition: MetadataMap.h:481
Convert T into a std::vector<T>.
Definition: MetadataMap.h:127
MetadataMap flatten() const
Create a flattened map.
Definition: MetadataMap.h:931
boost::mpl::joint_view< integer_types, float_types >::type numeric_types_view
Aggregate view of all numeric types.
Definition: MetadataMap.h:119
MetadataMapFlattenVisitor(MetadataMap &map, const MetadataMap::key_type &key)
Constructor.
Definition: MetadataMap.h:834
void append(const key_type &key, const T &value)
Append a value to a vector.
Definition: MetadataMap.h:230
iterator end()
Get an iterator to the end of the map.
Definition: MetadataMap.h:514
map_type::size_type size_type
Size type.
Definition: MetadataMap.h:153
size_type size() const
Get the size of the map.
Definition: MetadataMap.h:673
map_type::iterator iterator
Iterator.
Definition: MetadataMap.h:156
void set(const key_type &key, const value_type &value)
Add a key-value pair to the map.
Definition: MetadataMap.h:190
std::ostream & os
The stream to output to.
Definition: MetadataMap.h:710