MIRA
Serializer.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 by
3  * MetraLabs GmbH (MLAB), GERMANY
4  * and
5  * Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
6  * All rights reserved.
7  *
8  * Contact: info@mira-project.org
9  *
10  * Commercial Usage:
11  * Licensees holding valid commercial licenses may use this file in
12  * accordance with the commercial license agreement provided with the
13  * software or, alternatively, in accordance with the terms contained in
14  * a written agreement between you and MLAB or NICR.
15  *
16  * GNU General Public License Usage:
17  * Alternatively, this file may be used under the terms of the GNU
18  * General Public License version 3.0 as published by the Free Software
19  * Foundation and appearing in the file LICENSE.GPL3 included in the
20  * packaging of this file. Please review the following information to
21  * ensure the GNU General Public License version 3.0 requirements will be
22  * met: http://www.gnu.org/copyleft/gpl.html.
23  * Alternatively you may (at your option) use any later version of the GNU
24  * General Public License if such license has been publicly approved by
25  * MLAB and NICR (or its successors, if any).
26  *
27  * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
28  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
29  * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
30  * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
33  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
34  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
35  * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
36  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
37  */
38 
47 #ifndef _MIRA_SERIALIZER_H_
48 #define _MIRA_SERIALIZER_H_
49 
50 #include <set>
51 #include <map>
52 
53 #ifndef Q_MOC_RUN
54 #include <boost/type_traits/is_fundamental.hpp>
55 #include <boost/type_traits/is_pointer.hpp>
56 #endif
57 
59 
60 namespace mira {
61 
63 
125 template <typename Derived>
126 class Serializer : public RecursiveMemberReflector<Derived>
127 {
129 
130 public:
131 
132  typedef boost::mpl::bool_<true> isReadOnly;
133  typedef boost::mpl::bool_<true> isObjectTrackingSupported;
134 
135 public:
136 
139  {}
140 
146  {
147  // make sure the resolve is only ever done once
148  static int version = Base::checkForcedVersion("MIRA_FORCE_SERIALIZE_VERSION");
149  return version;
150  }
151 
152 public:
153 
154  typedef typename Base::VersionType VersionType;
156 
158  void desireClassVersions(const ClassVersionMap& versions) { mDesiredClassVersions = versions; }
159 
160 protected:
161 
163  bool acceptDesiredVersion = false) {
164  auto it = mDesiredClassVersions.find(type);
165  if (it == mDesiredClassVersions.end())
166  return version; // no entry = default case, just use version
167 
168  if (!acceptDesiredVersion && it->second != version) {
169  MIRA_LOG(WARNING) << "Desiring version for type '" << type <<
170  "': " << (int)(it->second) << ", but desiring a version "
171  "is not supported by the type's serialization. "
172  "Using type's current version " << (int)version << " instead.";
173  return version;
174  }
175 
176  if (it->second > version) {
177  MIRA_LOG(WARNING) << "Desiring version for type '" << type <<
178  "': " << (int)(it->second) << ", but current version "
179  "(=maximum implemented version) is: " << (int)version <<
180  ". Using that current version instead.";
181  return version;
182  }
183 
184  return it->second;
185  }
186 
187  template <typename T>
189  bool acceptDesiredVersion = false) {
190  return queryDesiredClassVersion(version, typeName<T>(), acceptDesiredVersion);
191  }
192 
194 
195 public:
196 
203  template <typename T>
204  void serialize(const std::string& name, const T& value,
205  const std::string& comment="")
206  {
207  // reset object tracking etc.
208  mObjects.clear();
209  mObjectIDToName.clear();
210 
211  // cast away the constness, this is safe since all serializer
212  // will read from the object only but have to use the
213  // reflect interface which is non-const, since the same interface
214  // is used for deserialization
215  T& value_const = const_cast<T&>(value);
216  this->This()->member(name.c_str(), value_const, comment.c_str());
217  }
218 
219 public:
220 
221  // implement methods of RecursiveMemberReflector
222 
223  template<typename T>
225  {
226  // only if tracking is enabled
227  if(this->template isTrackingEnabled<T>())
228  addObject(member);
229  }
230 
231  template<typename T>
232  void pointer(T* &pointer)
233  {
234  // #####################################################################
235  // If you get a compiler error here, you tried to serialize a pointer on
236  // a fundamental data type like int, float, etc. For performance reasons
237  // this is not allowed. Use a wrapper for those fundamental types
238  // to serialize the pointer
239  // #####################################################################
240  static_assert(!boost::is_fundamental<T>::value,
241  "Pointers on fundamental types cannot be serialized");
242 
243  // #####################################################################
244  // If you get a compiler error here, you tried to serialize a pointer on
245  // a pointer. This is not allowed and can not be deserialized. Try to
246  // change your code to avoid pointers on pointers!
247  // #####################################################################
248  static_assert(!boost::is_pointer<T>::value,
249  "Pointers on pointers cannot be serialized");
250 
251  // check if we have a NULL pointer
252  if(pointer==NULL) {
253  this->This()->pointerNull();
254  return;
255  }
256 
257  Base::pointer(pointer);
258  }
259 
260  template<typename T>
261  void pointerNormal(T* &pointer, int typeId) {
262  // catch if we found an already stored pointer
263  if(checkForPointerReference<T>(pointer, typeId))
264  return;
265 
266  this->This()->pointerWithoutClassType();
267 
268  // otherwise let our RecursiveMemberReflector handle the pointer
269  Base::pointerNormal(pointer, typeId);
270  }
271 
272  template<typename T>
274  // catch if we found an already stored pointer
275  if(checkForPointerReference<T>(pointer, typeId))
276  return;
277 
278  // otherwise obtain the class identifier ...
279  const Class& c = pointer->getClass();
280  this->This()->pointerWithClassType(c.getIdentifier());
281 
282  // ... and let our RecursiveMemberReflector handle the pointer
284  }
285 
286 
287  template<typename T>
288  void pointerAbstract(T* &pointer, int typeId) {
289  // #####################################################################
290  // If you get a compiler error here, you tried to serialize an abstract
291  // object that was not inherited from mira::Object. To resolve this issue
292  // you should inherit your class from mira::Object using the class
293  // factory
294  // #####################################################################
295  static_assert(sizeof(T)==0, "You tried to serialize an abstract class "
296  "that is not an mira::Object");
297  }
298 
301 
308  void pointerReference(int referencedObjectID)
309  {
310  }
311 
317  void pointerNull()
318  {
319  }
320 
330  {
331  }
332 
340  void pointerWithClassType(const std::string& type)
341  {
342  }
343 
345 
346 protected:
347 
349  template<typename T>
350  bool isTrackingEnabled() const {
351  return Derived::isObjectTrackingSupported::value &&
353  (this->template isReflectedAsPointer<T>() ||
354  std::is_base_of<mira::Object, T>::value);
355  }
356 
357 protected:
358 
396  struct AObject
397  {
398  void* address;
399  int type;
400  int objectID;
401 
402  AObject(void* iAddress, int iType) :
403  address(iAddress), type(iType) {}
404 
405  bool operator<(const AObject &rhs) const
406  {
407  assert(address != NULL);
408  assert(rhs.address != NULL);
409  if( address < rhs.address )
410  return true;
411  if( address > rhs.address )
412  return false;
413  // if addresses are the same then we use the typeId
414  // to distinguish
415  return type < rhs.type;
416  }
417 
418  AObject & operator=(const AObject & rhs)
419  {
420  address = rhs.address;
421  type = rhs.type;
422  objectID = rhs.objectID;
423  return *this;
424  }
425  };
426 
427  typedef std::set<AObject> ObjectSet;
428  ObjectSet mObjects; // the objects that we have stored already
429 
430  typedef std::map<int, std::string> ObjectIDToNameMap;
432 
433  typedef std::pair<ObjectSet, ObjectIDToNameMap> TrackingState;
434  std::stack<TrackingState> mTrackingStack;
435 
436 public:
437 
439  {
440  mTrackingStack.push(std::make_pair(mObjects, mObjectIDToName));
441  }
442 
444  {
445  std::tie(mObjects, mObjectIDToName) = mTrackingStack.top();
446  mTrackingStack.pop();
447  }
448 
449 protected:
450 
456  const std::string& getHumanReadableFullID(int objectID) const
457  {
458  assert(this->usesHumanReadableIDs());
459  std::map<int, std::string>::const_iterator it = mObjectIDToName.find(objectID);
460  assert(it!=mObjectIDToName.end());
461  return it->second;
462  }
463 
464 private:
465 
470  template<typename T>
471  bool checkForPointerReference(T* pointer, int typeId)
472  {
473  if(this->template isTrackingEnabled<T>()) {
474  // check if we have serialized the object already
476  typename ObjectSet::iterator i = mObjects.find(o);
477  if(i!=mObjects.end()) {
478  // pointer was already serialized, so store reference only
479  // the id the referenced object is the value in the map
480  this->This()->pointerReference(i->objectID);
481  return true;
482  }
483  }
484  return false;
485  }
486 
490  template<typename T>
491  void addObject(T& member)
492  {
493  assert(this->template isTrackingEnabled<T>());
494 
495  // create new object entry for the object's address and type
496  AObject o( serialization::void_upcast(&member), typeId<T>());
497  o.objectID = mObjects.size();
498 
499  // try to add the object
500  std::pair<typename ObjectSet::const_iterator, bool> res = mObjects.insert(o);
501 
502  // make sure that an object of THAT type does not exists at this
503  // address yet (otherwise we have a pointer conflict)
504  if(!res.second) {
505  // we have serialized the object already
506  const ReflectMemberMeta& meta = this->getCurrentMemberMeta();
507  std::string objectName = meta.getName();
508  if(this->usesHumanReadableIDs())
509  objectName = this->getCurrentMemberFullID();
510 
511  MIRA_THROW(XIO, "Pointer conflict: the object '" << objectName <<
512  "' at address " << &member <<
513  " was serialized already (probably by a pointer). "
514  "Try to resolve this conflict by serializing the "
515  "object BEFORE the pointer that points to that "
516  "object.");
517  }
518 
519  // store the full id/name of the object for the object id
520  if(this->usesHumanReadableIDs())
521  mObjectIDToName.insert(std::make_pair(o.objectID, this->getCurrentMemberFullID()));
522  }
523 };
524 
526 
527 } // namespace
528 
529 #endif
TypeId typeId()
Generates unique IDs for different types.
Definition: TypeId.h:94
void desireClassVersions(const ClassVersionMap &versions)
implements ReflectorInterface (for documentation see ReflectorInterface)
Definition: Serializer.h:158
static int checkForcedVersion(const std::string &variable)
Definition: ReflectorInterface.h:885
Type trait that indicates whether pointer tracking can be enabled for this type.
Definition: IsObjectTrackable.h:68
void pointerAbstract(T *&pointer, int typeId)
Definition: Serializer.h:288
VersionType version(VersionType version, const T *caller=NULL)
Specifies the current class version and returns the version found in the data stream.
Definition: ReflectorInterface.h:242
ReflectorInterface< ConcreteBinarySerializer< mira::BinaryOstream, BinaryFormatVersion, false > >::VersionType VersionType
Definition: AbstractReflector.h:170
void popObjectTrackingStore()
Definition: Serializer.h:443
serialization::ClassVersionMap ClassVersionMap
Definition: ReflectorInterface.h:294
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
AObject & operator=(const AObject &rhs)
Definition: Serializer.h:418
ObjectSet mObjects
Definition: Serializer.h:428
const std::string & getCurrentMemberFullID() const
Returns the full human readable object id / name of the current member being reflected.
Definition: RecursiveMemberReflector.h:462
void member(const char *name, T &member, const char *comment, ReflectCtrlFlags flags=REFLECT_CTRLFLAG_NONE)
Definition: RecursiveMemberReflector.h:871
const std::string & getHumanReadableFullID(int objectID) const
Returns the full human readable object id / name for the given internal objectID. ...
Definition: Serializer.h:456
Is a special reflector that is used for serialization.
Definition: Serializer.h:126
#define MIRA_LOG(level)
Use this macro to log data.
Definition: LoggingCore.h:528
Class object which supports some kind of class reflection.
Definition: Class.h:97
std::set< AObject > ObjectSet
Definition: Serializer.h:427
boost::mpl::bool_< true > isObjectTrackingSupported
Definition: Serializer.h:133
std::map< int, std::string > ObjectIDToNameMap
Definition: Serializer.h:430
ClassVersionMap mDesiredClassVersions
Definition: Serializer.h:193
void serialize(const std::string &name, const T &value, const std::string &comment="")
Serializes the specified object value under the given name.
Definition: Serializer.h:204
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:81
void pointerWithoutClassType()
Is called if a pointer points to a non-polymorphic type and hence the object can be stored without sp...
Definition: Serializer.h:329
Derived * This()
"Curiously recurring template pattern" (CRTP).
Definition: AbstractReflector.h:251
const ReflectMemberMeta & getCurrentMemberMeta() const
Returns the meta-information of the current member that is reflected.
Definition: RecursiveMemberReflector.h:451
VersionType queryDesiredClassVersion(VersionType version, bool acceptDesiredVersion=false)
Definition: Serializer.h:188
Abstract base class for most Reflectors.
Definition: AbstractReflector.h:165
int objectID
Definition: Serializer.h:400
static bool usesHumanReadableIDs()
Returns true, if the concrete derived Reflector supports human readable IDs.
Definition: ReflectorInterface.h:845
Is used to store the type and the address of all previously serialized objects in a map...
Definition: Serializer.h:396
void pointerPolymorphic(T *&pointer, int typeId)
Is called if a reflected pointer is a polymorphic pointer to an object that is derived from mira::Obj...
Definition: RecursiveMemberReflector.h:369
bool isTrackingEnabled() const
Returns true, if object tracking is enabled for the type T.
Definition: Serializer.h:350
Serializer()
The constructor.
Definition: Serializer.h:138
AObject(void *iAddress, int iType)
Definition: Serializer.h:402
void pointerNormal(T *&pointer, int typeId)
Is called if a reflected pointer is a "normal" pointer.
Definition: RecursiveMemberReflector.h:355
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
std::pair< ObjectSet, ObjectIDToNameMap > TrackingState
Definition: Serializer.h:433
void pointerPolymorphic(T *&pointer, int typeId)
Definition: Serializer.h:273
boost::mpl::bool_< true > isReadOnly
Definition: Serializer.h:132
void trackObject(T &member)
Definition: Serializer.h:224
int type
Definition: Serializer.h:399
void pointerNormal(T *&pointer, int typeId)
Definition: Serializer.h:261
virtual std::string const & getIdentifier() const
Return identifier for the class.
void pushObjectTrackingStore()
Definition: Serializer.h:438
std::stack< TrackingState > mTrackingStack
Definition: Serializer.h:434
Base::VersionType VersionType
Definition: Serializer.h:154
static int forcedSerializeVersion()
Returns either the version number from value of environment variable &#39;MIRA_FORCE_SERIALIZE_VERSION&#39;, or -1 (= do not force a version).
Definition: Serializer.h:145
ObjectIDToNameMap mObjectIDToName
Definition: Serializer.h:431
void pointer(T *&pointer)
Definition: Serializer.h:232
Definition: LoggingCore.h:75
void pointerWithClassType(const std::string &type)
Is called if a pointer points to a polymorphic type and hence the object must be stored with specifyi...
Definition: Serializer.h:340
bool operator<(const AObject &rhs) const
Definition: Serializer.h:405
void pointer(T *&pointer)
Is called if the member is a pointer.
Definition: RecursiveMemberReflector.h:326
Base::ClassVersionMap ClassVersionMap
Definition: Serializer.h:155
void pointerNull()
Is called by the pointer() method to indicate that a pointer that is to be serialized is a NULL-point...
Definition: Serializer.h:317
The RecursiveMemberReflector extents the RecursiveMemberReflectorBase class and implements the member...
Definition: RecursiveMemberReflector.h:862
void * void_upcast(T *pointer)
Safe cast for casting from a pointer upwards to void* while taking care of polymorphism and multiple ...
Definition: VoidCast.h:117
void * address
Definition: Serializer.h:398
void pointerReference(int referencedObjectID)
Is called by the pointer() method if an object, a pointer references, was already serialized and a re...
Definition: Serializer.h:308
VersionType queryDesiredClassVersion(VersionType version, const std::string &type, bool acceptDesiredVersion=false)
Definition: Serializer.h:162