MIRA
Deserializer.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_DESERIALIZER_H_
48 #define _MIRA_DESERIALIZER_H_
49 
50 #include <map>
51 #include <vector>
52 
54 
55 namespace mira {
56 
58 
98 template <typename Derived>
99 class Deserializer : public RecursiveMemberReflector<Derived>
100 {
102 public:
103 
104  typedef boost::mpl::bool_<false> isReadOnly;
105  typedef boost::mpl::bool_<true> isObjectTrackingSupported;
106 
107 public:
108 
109 
112  {}
113 
119  {
120  // make sure the resolve is only ever done once
121  static int version = Base::checkForcedVersion("MIRA_FORCE_DESERIALIZE_VERSION");
122  return version;
123  }
124 
125 public:
126 
132  template <typename T>
133  void deserialize(const std::string& name, T& value)
134  {
135  // reset object tracking etc.
136  mObjectNameToInstance.clear();
137  mObjects.clear();
138  mStdSharedPointers.clear();
139  mBoostSharedPointers.clear();
140 
141  // the Derived was derived from Serializer<Derived>,
142  // so we can safely cast to it ...
143  this->This()->member(name.c_str(), value, "");
144  }
145 
146 public:
147 
148  template<typename T>
150  {
151  // only if tracking is enabled
152  if(this->template isTrackingEnabled<T>())
153  addObject(member);
154  }
155 
156  template<typename T>
157  void pointer(T* &pointer)
158  {
159  // #####################################################################
160  // If you get a compiler error here, you tried to serialize a pointer on
161  // a fundamental datatype like int, float, etc. For performance reasons
162  // this is not allowed. Use a wrapper on the fundamental type
163  // to serialize the pointer
164  // #####################################################################
165  static_assert(!boost::is_fundamental<T>::value,
166  "Pointers on fundamental types cannot be serialized");
167 
168  // #####################################################################
169  // If you get a compiler error here, you tried to serialize a pointer on
170  // a pointer. This is not allowed and can not be deserialized. Try to
171  // change your code to avoid pointers on pointers!
172  // #####################################################################
173  static_assert(!boost::is_pointer<T>::value,
174  "Pointers on pointers cannot be serialized");
175 
176  // explicitly initialize the pointer with NULL, it will be created
177  // in one of the methods below.
178  pointer=NULL;
180  }
181 
182  template<typename T>
183  void pointerNormal(T* &pointer, int typeId)
184  {
185  // create a new instance of T ...
186  pointer = new T;
187  // and let our RecursiveMemberReflector handle the pointer
189  }
190 
191 
192  template<typename T>
194  {
195  // our base class was not able to obtain the typeId, since
196  // we initialized the pointer with NULL above
197  assert(typeId<0);
198 
199  // obtain the class type directly from the deserializer using the
200  // pointerClassType() method that must read it from the data source
201  std::string type = this->This()->pointerClassType();
202 
203  // try to create a new instance of the type
204  pointer = T::CLASS().newInstance(type);
205  if(pointer==NULL) {
206  const ReflectMemberMeta& meta = this->getCurrentMemberMeta();
207  MIRA_THROW(XIO, "Cannot deserialize the polymorphic member pointer '"
208  << meta.getName() << "'. The specified class '" << type
209  << "' is not known to the class factory.");
210  }
211 
212  // obtain the class of the concrete created object
213  const Class& c = pointer->getClass();
214 
215  // now obtain the real typeid ...
216  typeId = c.getTypeId();
217 
218  // ... and let our RecursiveMemberReflector handle the pointer
220  }
221 
222 
223  template<typename T>
224  void pointerAbstract(T* &pointer, int typeId) {
225  // #####################################################################
226  // If you get a compiler error here, you tried to deserialize an abstract
227  // object that was not inherited from mira::Object. To resolve this issue
228  // you should inherit your class from mira::Object using the class
229  // factory.
230  // #####################################################################
231  static_assert(sizeof(T)==0, "You tried to deserialize an abstract "
232  "class that is not an mira::Object");
233  }
234 
242  std::string pointerClassType() { return ""; }
243 
244  template<class T>
245  void sharedPointerReset(boost::shared_ptr<T>& ptr, T* rawPtr)
246  {
248  }
249 
250  template<class T>
251  void sharedPointerReset(std::shared_ptr<T>& ptr, T* rawPtr)
252  {
253  sharedPointerReset( ptr, rawPtr, mStdSharedPointers );
254  }
255 
256  template<template<class> class SType, class T>
257  void sharedPointerReset(SType<T>& ptr, T* rawPtr, std::map<void*,
258  SType<void> >& pointerMap)
259  {
260  // handle simple null pointer case
261  if(rawPtr==NULL) {
262  ptr.reset();
263  return;
264  }
265 
266  // check if we have a shared pointer for this pointer already
267 
268  typedef typename boost::remove_const<T>::type TwithoutConst;
269  TwithoutConst* rawConstFreePtr = const_cast<TwithoutConst*>(rawPtr);
270 
271  void* p = static_cast<void*>(rawConstFreePtr);
272  auto it = pointerMap.find(p);
273  if(it==pointerMap.end()) { // no, we don't
274  // so create new shared pointer
275  ptr.reset(rawPtr);
276  // store the shared pointer
277  SType<void> voidptr(ptr, p);
278  pointerMap.insert(std::make_pair(p, voidptr));
279  } else {
280  // use existing shared pointer
281  ptr = SType<T>(it->second, static_cast<T*>(it->second.get()));
282  }
283  }
284 
285 protected:
286 
288  template<typename T>
289  bool isTrackingEnabled() const {
290  return Derived::isObjectTrackingSupported::value &&
292  (this->template isReflectedAsPointer<T>() ||
293  std::is_base_of<mira::Object, T>::value);
294  }
295 
296 protected:
297 
298  typedef std::map<std::string, void*> ObjectNameToInstanceMap;
301 
302  typedef std::vector<void*> ObjectsVector;
305 
306  typedef std::pair<ObjectsVector, ObjectNameToInstanceMap> TrackingState;
307  std::stack<TrackingState> mTrackingStack;
308 
309 public:
310 
312  {
313  mTrackingStack.push(std::make_pair(mObjects, mObjectNameToInstance));
314  }
315 
317  {
318  std::tie(mObjects, mObjectNameToInstance) = mTrackingStack.top();
319  mTrackingStack.pop();
320  }
321 
322 protected:
323 
324  typedef std::map<void*, boost::shared_ptr<void> > BoostSharedPointerMap;
326 
327  typedef std::map<void*, std::shared_ptr<void> > StdSharedPointerMap;
329 
330 protected:
331 
342  template<typename T>
343  T* resolveReference(int objectId)
344  {
345  if(!this->template isTrackingEnabled<T>())
346  MIRA_THROW(XRuntime, "Cannot use a reference for the object with id'"
347  << objectId << "' where object tracking is disabled");
348 
349  // get object with that id
350 
351  if((std::size_t)objectId>=mObjects.size())
352  MIRA_THROW(XRuntime, "Unresolved reference to unknown object with id '"
353  << objectId << "'");
354 
355  return serialization::void_downcast<T>(mObjects[objectId]);
356  }
357 
364  template<typename T>
365  T* resolveReference(const std::string& fullId)
366  {
367  if(!this->template isTrackingEnabled<T>())
368  MIRA_THROW(XRuntime, "Cannot use a reference for the object '"
369  << fullId << "' where object tracking is disabled");
370 
371  if(!this->usesHumanReadableIDs())
372  MIRA_THROW(XLogical, "Cannot use a reference for the object '"
373  << fullId << "' since Deserializer does not support "
374  "human readable IDs");
375 
376  // get object with that id
377  ObjectNameToInstanceMap::iterator it = mObjectNameToInstance.find(fullId);
378  if(it==mObjectNameToInstance.end())
379  MIRA_THROW(XRuntime, "Unresolved reference to unknown object '"
380  << fullId << "'");
381 
382  return serialization::void_downcast<T>(it->second);
383  }
384 
385 private:
389  template<typename T>
390  void addObject(T& member)
391  {
392  assert(this->template isTrackingEnabled<T>());
393 
395  mObjects.push_back(pointer);
396 
397  if(this->usesHumanReadableIDs()) {
398  std::string fullId = this->getCurrentMemberFullID();
399  //assert(mObjectNameToInstance.count(fullId)==0); // id must be unique,
400  mObjectNameToInstance.insert(std::make_pair(fullId, pointer));
401  }
402  }
403 };
404 
406 
407 } // namespace
408 
409 #endif
TypeId typeId()
Generates unique IDs for different types.
Definition: TypeId.h:94
StdSharedPointerMap mStdSharedPointers
Definition: Deserializer.h:328
static int checkForcedVersion(const std::string &variable)
Definition: ReflectorInterface.h:841
Type trait that indicates whether pointer tracking can be enabled for this type.
Definition: IsObjectTrackable.h:68
T * resolveReference(int objectId)
Resolves a pointer reference to a previously stored object with the specified full id...
Definition: Deserializer.h:343
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
std::string getName() const
Definition: ReflectMemberMeta.h:82
void sharedPointerReset(std::shared_ptr< T > &ptr, T *rawPtr)
Definition: Deserializer.h:251
bool isTrackingEnabled() const
Returns true, if object tracking is enabled for the type T.
Definition: Deserializer.h:289
void pointer(T *&pointer)
Definition: Deserializer.h:157
void deserialize(const std::string &name, T &value)
Deserializes the specified object value with the given name.
Definition: Deserializer.h:133
boost::mpl::bool_< false > isReadOnly
Definition: Deserializer.h:104
void pushObjectTrackingStore()
Definition: Deserializer.h:311
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
const std::string & getCurrentMemberFullID() const
Returns the full human readable object id / name of the current member being reflected.
Definition: RecursiveMemberReflector.h:470
void member(const char *name, T &member, const char *comment, ReflectCtrlFlags flags=REFLECT_CTRLFLAG_NONE)
Definition: RecursiveMemberReflector.h:862
void pointerAbstract(T *&pointer, int typeId)
Definition: Deserializer.h:224
static int forcedDeserializeVersion()
Returns either the version number from value of environment variable &#39;MIRA_FORCE_DESERIALIZE_VERSION&#39;...
Definition: Deserializer.h:118
Class object which supports some kind of class reflection.
Definition: Class.h:97
Stores meta information for each member.
Definition: ReflectMemberMeta.h:64
std::vector< void * > ObjectsVector
Definition: Deserializer.h:302
std::map< std::string, void * > ObjectNameToInstanceMap
Definition: Deserializer.h:298
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:82
Derived * This()
"Curiously recurring template pattern" (CRTP).
Definition: AbstractReflector.h:246
const ReflectMemberMeta & getCurrentMemberMeta() const
Returns the meta-information of the current member that is reflected.
Definition: RecursiveMemberReflector.h:459
std::pair< ObjectsVector, ObjectNameToInstanceMap > TrackingState
Definition: Deserializer.h:306
static bool usesHumanReadableIDs()
Returns true, if the concrete derived Reflector supports human readable IDs.
Definition: ReflectorInterface.h:801
std::map< void *, std::shared_ptr< void > > StdSharedPointerMap
Definition: Deserializer.h:327
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:367
ObjectNameToInstanceMap mObjectNameToInstance
maps full id names to instance pointers
Definition: Deserializer.h:300
void sharedPointerReset(boost::shared_ptr< T > &ptr, T *rawPtr)
Definition: Deserializer.h:245
void pointerNormal(T *&pointer, int typeId)
Is called if a reflected pointer is a "normal" pointer.
Definition: RecursiveMemberReflector.h:352
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
std::map< void *, boost::shared_ptr< void > > BoostSharedPointerMap
Definition: Deserializer.h:324
boost::mpl::bool_< true > isObjectTrackingSupported
Definition: Deserializer.h:105
ObjectsVector mObjects
maps the ids to the instance pointers
Definition: Deserializer.h:304
void popObjectTrackingStore()
Definition: Deserializer.h:316
void sharedPointerReset(SType< T > &ptr, T *rawPtr, std::map< void *, SType< void > > &pointerMap)
Definition: Deserializer.h:257
void trackObject(T &member)
Definition: Deserializer.h:149
BoostSharedPointerMap mBoostSharedPointers
Definition: Deserializer.h:325
void pointer(T *&pointer)
Is called if the member is a pointer.
Definition: RecursiveMemberReflector.h:325
std::string pointerClassType()
Must be overwritten from the concrete deserializer and is called if the pointer that is deserialized ...
Definition: Deserializer.h:242
void pointerPolymorphic(T *&pointer, int typeId)
Definition: Deserializer.h:193
Deserializer()
The constructor.
Definition: Deserializer.h:111
std::stack< TrackingState > mTrackingStack
Definition: Deserializer.h:307
The RecursiveMemberReflector extents the RecursiveMemberReflectorBase class and implements the member...
Definition: RecursiveMemberReflector.h:853
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:108
void pointerNormal(T *&pointer, int typeId)
Definition: Deserializer.h:183
Is a special reflector that is used for deserialization.
Definition: Deserializer.h:99
virtual int getTypeId() const =0
Return unique id for the class.
T * resolveReference(const std::string &fullId)
Same as the above method, but here the object id can be specified as full human readable id...
Definition: Deserializer.h:365