ome-files  0.1.1
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 <iomanip>
44 #include <map>
45 #include <ostream>
46 #include <sstream>
47 #include <string>
48 #include <vector>
49 
50 #include <ome/compat/cstdint.h>
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_iterator i = map.begin();
446  i != map.end();
447  ++i)
448  {
449  map_type::value_type v(prefix + i->first, i->second);
450  insert(v);
451  }
452  }
453 
464  flatten() const;
465 
471  map_type&
472  map()
473  {
474  return discriminating_map;
475  }
476 
482  const map_type&
483  map() const
484  {
485  return discriminating_map;
486  }
487 
493  iterator
495  {
496  return discriminating_map.begin();
497  }
498 
504  const_iterator
505  begin() const
506  {
507  return discriminating_map.begin();
508  }
509 
515  iterator
516  end()
517  {
518  return discriminating_map.end();
519  }
520 
526  const_iterator
527  end() const
528  {
529  return discriminating_map.end();
530  }
531 
537  reverse_iterator
539  {
540  return discriminating_map.rbegin();
541  }
542 
548  const_reverse_iterator
549  rbegin() const
550  {
551  return discriminating_map.rbegin();
552  }
553 
559  reverse_iterator
561  {
562  return discriminating_map.rend();
563  }
564 
570  const_reverse_iterator
571  rend() const
572  {
573  return discriminating_map.rend();
574  }
575 
586  value_type&
587  operator[] (const key_type& key)
588  {
589  return discriminating_map[key];
590  }
591 
598  bool
599  operator == (const MetadataMap& rhs) const
600  {
601  return discriminating_map == rhs.discriminating_map;
602  }
603 
610  bool
611  operator != (const MetadataMap& rhs) const
612  {
613  return discriminating_map != rhs.discriminating_map;
614  }
615 
622  bool
623  operator < (const MetadataMap& rhs) const
624  {
625  return discriminating_map < rhs.discriminating_map;
626  }
627 
635  bool
636  operator <= (const MetadataMap& rhs) const
637  {
638  return discriminating_map <= rhs.discriminating_map;
639  }
640 
647  bool
648  operator > (const MetadataMap& rhs) const
649  {
650  return discriminating_map > rhs.discriminating_map;
651  }
652 
660  bool
661  operator >= (const MetadataMap& rhs) const
662  {
663  return discriminating_map >= rhs.discriminating_map;
664  }
665 
674  size_type
675  size() const
676  {
677  return discriminating_map.size();
678  }
679 
685  bool
686  empty() const
687  {
688  return discriminating_map.empty();
689  }
690 
696  void
698  {
699  return discriminating_map.clear();
700  }
701  };
702 
703  namespace detail
704  {
705 
709  struct MetadataMapValueTypeOStreamVisitor : public boost::static_visitor<>
710  {
712  std::ostream& os;
713 
720  os(os)
721  {}
722 
730  template <typename T>
731  void
732  operator() (const std::vector<T> & c) const
733  {
734  for (typename std::vector<T>::const_iterator i = c.begin();
735  i != c.end();
736  ++i)
737  {
738  os << *i;
739  if (i + 1 != c.end())
740  os << ", ";
741  }
742  }
743 
749  template <typename T>
750  void
751  operator() (const T& v) const
752  {
753  os << v;
754  }
755  };
756 
760  struct MetadataMapOStreamVisitor : public boost::static_visitor<>
761  {
763  std::ostream& os;
766 
773  MetadataMapOStreamVisitor(std::ostream& os,
774  const MetadataMap::key_type& key):
775  os(os),
776  key(key)
777  {}
778 
789  template <typename T>
790  void
791  operator() (const std::vector<T> & c) const
792  {
793  typename std::vector<T>::size_type idx = 1;
794  // Determine the optimal padding based on the maximum digit count.
795  int sf = static_cast<int>(std::log10(static_cast<float>(c.size()))) + 1;
796  for (typename std::vector<T>::const_iterator i = c.begin();
797  i != c.end();
798  ++i, ++idx)
799  {
800  os << key << " #" << std::setw(sf) << std::setfill('0') << std::right << idx << " = " << *i << '\n';
801  }
802  }
803 
812  template <typename T>
813  void
814  operator() (const T& v) const
815  {
816  os << key << " = " << v << '\n';
817  }
818  };
819 
823  struct MetadataMapFlattenVisitor : public boost::static_visitor<>
824  {
829 
837  const MetadataMap::key_type& key):
838  map(map),
839  key(key)
840  {}
841 
852  template <typename T>
853  void
854  operator() (const std::vector<T> & c) const
855  {
856  typename std::vector<T>::size_type idx = 1;
857  // Determine the optimal padding based on the maximum digit count.
858  int sf = static_cast<int>(std::log10(static_cast<float>(c.size()))) + 1;
859  for (typename std::vector<T>::const_iterator i = c.begin();
860  i != c.end();
861  ++i, ++idx)
862  {
863  std::ostringstream os;
864  os << key << " #" << std::setw(sf) << std::setfill('0') << std::right << idx;
865  map.set(os.str(), *i);
866  }
867  }
868 
877  template <typename T>
878  void
879  operator() (const T& v) const
880  {
881  map.set(key, v);
882  }
883  };
884 
885  }
886 
898  template<>
900  MetadataMap::get<MetadataMap::value_type>(const key_type& key)
901  {
902  map_type::iterator i = discriminating_map.find(key);
903  if (i == discriminating_map.end())
904  throw boost::bad_get();
905 
906  return i->second;
907  }
908 
920  template<>
921  inline const MetadataMap::value_type&
922  MetadataMap::get<MetadataMap::value_type>(const key_type& key) const
923  {
924  map_type::const_iterator i = discriminating_map.find(key);
925  if (i == discriminating_map.end())
926  throw boost::bad_get();
927 
928  return i->second;
929  }
930 
931  inline
934  {
935  MetadataMap newmap;
937  i != discriminating_map.end();
938  ++i)
939  {
940  boost::apply_visitor(detail::MetadataMapFlattenVisitor(newmap, i->first), i->second);
941  }
942  return newmap;
943  }
944 
945  }
946 }
947 
948 namespace std
949 {
950 
958  template<class charT, class traits>
959  inline basic_ostream<charT,traits>&
960  operator<< (basic_ostream<charT,traits>& os,
961  const ::ome::files::MetadataMap::value_type& vt)
962  {
963  boost::apply_visitor(::ome::files::detail::MetadataMapValueTypeOStreamVisitor(os), vt);
964  return os;
965  }
966 
974  template<class charT, class traits>
975  inline basic_ostream<charT,traits>&
976  operator<< (basic_ostream<charT,traits>& os,
977  const ::ome::files::MetadataMap& map)
978  {
979  for (::ome::files::MetadataMap::const_iterator i = map.begin();
980  i != map.end();
981  ++i)
982  {
983  boost::apply_visitor(::ome::files::detail::MetadataMapOStreamVisitor(os, i->first), i->second);
984  }
985  return os;
986  }
987 
988 }
989 
990 #endif // OME_FILES_METADATAMAP_H
991 
992 /*
993  * Local Variables:
994  * mode:C++
995  * End:
996  */
bool operator<(const MetadataMap &rhs) const
Check if map is less than another map.
Definition: MetadataMap.h:623
const MetadataMap::key_type & key
The key of the value being flattened.
Definition: MetadataMap.h:828
void clear()
Clear the map.
Definition: MetadataMap.h:697
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
bool empty() const
Check if the map is empty.
Definition: MetadataMap.h:686
Visitor template for output of MetadataMap values to an ostream.
Definition: MetadataMap.h:760
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:472
reverse_iterator rend()
Get a reverse iterator to the beginning of the map.
Definition: MetadataMap.h:560
std::vector< key_type > keys() const
Get a list of keys in the map.
Definition: MetadataMap.h:425
bool operator<=(const MetadataMap &rhs) const
Check if map is less than or equal to another map.
Definition: MetadataMap.h:636
boost::mpl::vector< std::string, bool > non_numeric_types
Storable non-numeric types.
Definition: MetadataMap.h:100
bool operator==(const MetadataMap &rhs) const
Compare maps for equality.
Definition: MetadataMap.h:599
Functor to get a map key.
Definition: MetadataMap.h:399
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:719
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.
std::pair< iterator, bool > insert(map_type::value_type &value)
Insert a value into the map.
Definition: MetadataMap.h:370
const_iterator find(const key_type &key) const
Find a key in the map.
Definition: MetadataMap.h:351
MetadataMap & map
The map in which to set the flattened elements.
Definition: MetadataMap.h:826
Metadata key-value map using a restricted set of value types.
Definition: MetadataMap.h:79
const_iterator begin() const
Get a constant iterator to the beginning of the map.
Definition: MetadataMap.h:505
const_reverse_iterator rend() const
Get a constant reverse iterator to the beginning of the map.
Definition: MetadataMap.h:571
MetadataMap flatten() const
Create a flattened map.
Definition: MetadataMap.h:933
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:494
std::vector< T > type
The result type.
Definition: MetadataMap.h:130
iterator find(const key_type &key)
Find a key in the map.
Definition: MetadataMap.h:339
MetadataMap()
Constructor.
Definition: MetadataMap.h:173
Visitor template for flattening of MetadataMap vector values.
Definition: MetadataMap.h:823
bool operator>(const MetadataMap &rhs) const
Check if map is greater than another map.
Definition: MetadataMap.h:648
size_type size() const
Get the size of the map.
Definition: MetadataMap.h:675
Visitor template for output of MetadataMap values to an ostream.
Definition: MetadataMap.h:709
MetadataMapOStreamVisitor(std::ostream &os, const MetadataMap::key_type &key)
Constructor.
Definition: MetadataMap.h:773
~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:587
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:538
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:765
const_iterator end() const
Get a constant iterator to the end of the map.
Definition: MetadataMap.h:527
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
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
const map_type & map() const
Get the underlying map.
Definition: MetadataMap.h:483
std::ostream & os
The stream to output to.
Definition: MetadataMap.h:763
void erase(const key_type &key)
Erase a key from the map by name.
Definition: MetadataMap.h:381
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:611
bool operator>=(const MetadataMap &rhs) const
Check if map is greater than or equal to another map.
Definition: MetadataMap.h:661
Convert T into a std::vector<T>.
Definition: MetadataMap.h:127
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:836
void append(const key_type &key, const T &value)
Append a value to a vector.
Definition: MetadataMap.h:230
T::first_type operator()(T pair) const
Get key from pair.
Definition: MetadataMap.h:408
const_reverse_iterator rbegin() const
Get a constant reverse iterator to the end of the map.
Definition: MetadataMap.h:549
iterator end()
Get an iterator to the end of the map.
Definition: MetadataMap.h:516
map_type::size_type size_type
Size type.
Definition: MetadataMap.h:153
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:712