MMTF-C++
The C++ language MMTF libraries
map_decoder.hpp
Go to the documentation of this file.
1 // *************************************************************************
2 //
3 // Licensed under the MIT License (see accompanying LICENSE file).
4 //
5 // The authors of this code are: Gabriel Studer, Gerardo Tauriello, and
6 // Daniel Farrell.
7 //
8 // Based on mmtf_c developed by Julien Ferte (http://www.julienferte.com/),
9 // Anthony Bradley, Thomas Holder with contributions from Yana Valasatava,
10 // Gazal Kalyan, Alexander Rose.
11 //
12 // *************************************************************************
13 
14 #ifndef MMTF_MAP_DECODER_H
15 #define MMTF_MAP_DECODER_H
16 
17 #include "structure_data.hpp"
18 #include "binary_decoder.hpp"
19 #include "errors.hpp"
20 
21 #include <msgpack.hpp>
22 #include <map>
23 #include <iostream>
24 
25 namespace mmtf {
26 
31 class MapDecoder {
32 public:
33 
38 
45  MapDecoder(const msgpack::object& obj);
46 
52  MapDecoder(const std::map<std::string, msgpack::object>& map_in);
53 
59  void initFromObject(const msgpack::object& obj);
64  void initFromBuffer(const char* buffer, size_t size);
65 
78  template<typename T>
79  void decode(const std::string& key, bool required, T& target) const;
80 
97  void
98  copy_decode(const std::string& key, bool required,
99  std::map<std::string, msgpack::object>& target,
100  msgpack::zone& zone) const;
101 
107  void checkExtraKeys() const;
108 
109 private:
110  // when constructed with byte buffer, we keep unpacked object
111  // NOTE: this contains a unique pointer to msgpack data (cannot copy)
112  msgpack::object_handle object_handle_;
113  // key-value pairs extracted from msgpack map
114  typedef std::map<std::string, const msgpack::object*> data_map_type_;
115  data_map_type_ data_map_;
116  // set of keys that were successfully decoded
117  mutable std::set<std::string> decoded_keys_;
118 
123  void init_from_msgpack_obj(const msgpack::object& obj);
124 
125  // type checking (note: doesn't check array elements)
126  // -> only writes warning to cerr
127  // -> exception thrown by msgpack if conversion fails
128  void checkType_(const std::string& key, msgpack::type::object_type type,
129  const float& target) const;
130  void checkType_(const std::string& key, msgpack::type::object_type type,
131  const int32_t& target) const;
132  void checkType_(const std::string& key, msgpack::type::object_type type,
133  const char& target) const;
134  void checkType_(const std::string& key, msgpack::type::object_type type,
135  const std::string& target) const;
136  template <typename T>
137  void checkType_(const std::string& key, msgpack::type::object_type type,
138  const std::vector<T>& target) const;
139  template <typename T>
140  void checkType_(const std::string& key, msgpack::type::object_type type,
141  const T& target) const;
142 };
143 
144 // *************************************************************************
145 // IMPLEMENTATION
146 // *************************************************************************
147 
148 inline MapDecoder::MapDecoder(const msgpack::object& obj) {
149  init_from_msgpack_obj(obj);
150 }
151 
152 inline MapDecoder::MapDecoder(const std::map<std::string, msgpack::object>& map_in) {
153  std::map<std::string, msgpack::object>::const_iterator it;
154  for (it = map_in.begin(); it != map_in.end(); ++it) {
155  data_map_[it->first] = &(it->second);
156  }
157 }
158 
159 inline void MapDecoder::initFromObject(const msgpack::object& obj) {
160  data_map_.clear();
161  decoded_keys_.clear();
162  init_from_msgpack_obj(obj);
163 }
164 
165 inline void MapDecoder::initFromBuffer(const char* buffer, std::size_t size) {
166  msgpack::unpack(object_handle_, buffer, size);
167  initFromObject(object_handle_.get());
168 }
169 
170 void
171 inline MapDecoder::copy_decode(const std::string& key, bool required,
172  std::map<std::string, msgpack::object>& target,
173  msgpack::zone & zone) const {
174  // note: cost of O(M*log(N)) string comparisons (M parsed, N in map)
175  data_map_type_::const_iterator it = data_map_.find(key);
176  if (it != data_map_.end()) {
177  decoded_keys_.insert(key);
178  // expensive copy here
179  msgpack::object tmp_object(*it->second, zone);
180  tmp_object.convert(target);
181  }
182  else if (required) {
183  throw DecodeError("MsgPack MAP does not contain required entry "
184  + key);
185  }
186 }
187 
188 template<typename T>
189 inline void MapDecoder::decode(const std::string& key, bool required, T& target) const {
190  // note: cost of O(M*log(N)) string comparisons (M parsed, N in map)
191  data_map_type_::const_iterator it = data_map_.find(key);
192  if (it != data_map_.end()) {
193  checkType_(key, it->second->type, target);
194  if (it->second->type == msgpack::type::BIN) {
195  BinaryDecoder bd(*it->second, key);
196  bd.decode(target);
197  } else {
198  it->second->convert(target);
199  }
200  decoded_keys_.insert(key);
201  }
202  else if (required) {
203  throw DecodeError("MsgPack MAP does not contain required entry "
204  + key);
205  }
206 }
207 
208 
209 inline void MapDecoder::checkExtraKeys() const {
210  // note: cost of O(N*log(M))) string comparisons (M parsed, N in map)
211  // simple set difference algorithm
212  data_map_type_::const_iterator map_it;
213  std::set<std::string>::const_iterator parsed_it;
214  for (map_it = data_map_.begin(); map_it != data_map_.end(); ++map_it) {
215  parsed_it = decoded_keys_.find(map_it->first);
216  if (parsed_it == decoded_keys_.end()) {
217  std::cerr << "Warning: Found non-parsed key " << map_it->first
218  << " in MsgPack MAP.\n";
219  }
220  }
221 }
222 
223 inline void MapDecoder::init_from_msgpack_obj(const msgpack::object& obj) {
224  // sanity checks
225  if (obj.type != msgpack::type::MAP) {
226  throw DecodeError("Expected msgpack type to be MAP");
227  }
228  // get data
229  msgpack::object_kv* current_key_value = obj.via.map.ptr;
230  msgpack::object_kv* last_key_value = current_key_value + obj.via.map.size;
231  for (; current_key_value != last_key_value; ++current_key_value) {
232  msgpack::object* key = &(current_key_value->key);
233  msgpack::object* value = &(current_key_value->val);
234  if (key->type == msgpack::type::STR) {
235  std::string data_map_key(key->via.str.ptr, key->via.str.size);
236  data_map_[data_map_key] = value;
237  } else {
238  std::cerr << "Warning: Found non-string key type " << key->type
239  << "! Skipping..." << std::endl;
240  }
241  }
242 }
243 
244 inline void MapDecoder::checkType_(const std::string& key,
245  msgpack::type::object_type type,
246  const float&) const {
247  if (type != msgpack::type::FLOAT32 && type != msgpack::type::FLOAT64) {
248  std::cerr << "Warning: Non-float type " << type << " found for "
249  "entry " << key << std::endl;
250  }
251 }
252 inline void MapDecoder::checkType_(const std::string& key,
253  msgpack::type::object_type type,
254  const int32_t&) const {
255  if ( type != msgpack::type::POSITIVE_INTEGER
256  && type != msgpack::type::NEGATIVE_INTEGER) {
257  std::cerr << "Warning: Non-int type " << type << " found for "
258  "entry " << key << std::endl;
259  }
260 }
261 inline void MapDecoder::checkType_(const std::string& key,
262  msgpack::type::object_type type,
263  const char&) const {
264  if (type != msgpack::type::STR) {
265  std::cerr << "Warning: Non-string type " << type << " found for "
266  "entry " << key << std::endl;
267  }
268 }
269 inline void MapDecoder::checkType_(const std::string& key,
270  msgpack::type::object_type type,
271  const std::string&) const {
272  if (type != msgpack::type::STR) {
273  std::cerr << "Warning: Non-string type " << type << " found for "
274  "entry " << key << std::endl;
275  }
276 }
277 
278 template <typename T>
279 void MapDecoder::checkType_(const std::string& key,
280  msgpack::type::object_type type,
281  const std::vector<T>&) const {
282  if (type != msgpack::type::ARRAY && type != msgpack::type::BIN) {
283  std::cerr << "Warning: Non-array type " << type << " found for "
284  "entry " << key << std::endl;
285  }
286 }
287 
288 
289 template <typename T>
290 void MapDecoder::checkType_(const std::string&,
291  msgpack::type::object_type,
292  const T &) const {
293  // Do nothing -- allow all through
294 }
295 
296 } // mmtf namespace
297 
298 #endif
Helper class to decode msgpack binary into a vector.
Definition: binary_decoder.hpp:30
void decode(T &target) const
Decode binary msgpack object into the given target.
Definition: binary_decoder.hpp:220
Exception thrown when failing during decoding.
Definition: errors.hpp:23
Helper class to decode msgpack maps into object fields. Class cannot be copied as it contains unique ...
Definition: map_decoder.hpp:31
void initFromBuffer(const char *buffer, size_t size)
Initialize from byte buffer of given size. Unpacks data and then same effect as MapDecoder::initFromO...
Definition: map_decoder.hpp:165
void copy_decode(const std::string &key, bool required, std::map< std::string, msgpack::object > &target, msgpack::zone &zone) const
Don't decode, but instead just copy map-contents onto a zone for later decoding/processing you should...
Definition: map_decoder.hpp:171
void initFromObject(const msgpack::object &obj)
Initialize given a msgpack::object. Clears internal data and has same effect as MapDecoder::MapDecode...
Definition: map_decoder.hpp:159
MapDecoder()
Construct empty decoder. Use init-functions to fill it.
Definition: map_decoder.hpp:37
void checkExtraKeys() const
Check if there are any keys, that were not decoded. This is to be called after all expected fields ha...
Definition: map_decoder.hpp:209
void decode(const std::string &key, bool required, T &target) const
Extract value from map and decode into target.
Definition: map_decoder.hpp:189
Definition: binary_decoder.hpp:25