MIRA
PropertySerializer.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_PROPERTYSERIALIZER_H_
48 #define _MIRA_PROPERTYSERIALIZER_H_
49 
50 #include <assert.h>
51 
54 
55 #include <tuple>
56 
57 namespace mira {
58 
60 
67 class PropertySerializer : public PropertyReflector<PropertySerializer>
68 {
70 
71 public:
72 
74  {}
75 
76 public:
77 
86  template <typename T>
88  PropertyHint&& hint, bool isReadOnly,
89  bool isVolatile) {
90  Base::invokePropertyMemberOverwrite(member, meta, std::move(hint),
91  isReadOnly, isVolatile);
92  }
93 
98  template <typename Getter, typename Setter>
100  const ReflectMemberMeta& meta, PropertyHint&& hint,
101  bool isReadOnly, bool isVolatile) {
102  }
103 
104  // implemented from base class
105 
112  template<typename T>
114  PropertyHint&& hint, bool isReadOnly,
115  bool isVolatile)
116  {
117  typedef typename boost::remove_const<T>::type TwithoutConst;
118 
119  // current node becomes parent node
120  PropertyNode* parentNode = mCurrentNode;
121 
122  if (meta.id)
123  {
124  PropertyNode* node = NULL;
125 
126  if (parentNode)
127  node = parentNode->findChildNode(meta.id);
128 
129  if (node) {
131  dynamic_cast<TypedPropertyNodeImpl<TwithoutConst>*>(node);
132  // if node already exists and has the right type, just update it
133  if (typedNode) {
134  TwithoutConst& nonconstMember = const_cast<TwithoutConst&>(member);
135  typedNode->update(nonconstMember);
136 
137  typedNode->mUpdated = true;
138  foreach (auto c, typedNode->children())
139  c->mUpdated = false;
140  } else {
141  // We must NOT delete node here, to be able to signal the removal to
142  // listeners first.
143  // After setting the node to NULL, a new node will be created next.
144  // That will result in parentNode having 2 children with same name and id
145  // temporarily, but the older one will be removed in the cleanup below, as
146  // it was not updated.
147  node = NULL;
148  }
149  }
150  if (!node) { // if we cannot use an existing node, create a new one
151  TwithoutConst& nonconstMember = const_cast<TwithoutConst&>(member);
152  node = createNode(parentNode, nonconstMember, meta, hint, isReadOnly, isVolatile);
153  }
154 
155  // set the node as current node
156  mCurrentNode=node;
157  }
158 
159  // now do the real reflector invoke (but only if T is a type that
160  // is worth to continue. If it is a GetterSetter, we stop here)
161  continueWithBaseInvoke(member,meta, std::move(hint), isReadOnly, isVolatile);
162 
163  // remove child nodes that have not been updated during serialization --> are obsolete
164 
165  // first, collect all child nodes to be removed (index + iterator + PropertyNode)
166  int index = 0;
167  std::vector<std::tuple<int, PropertyNode::NodeList::iterator, PropertyNode*>> toRemove;
168  for (PropertyNode::NodeList::iterator it = mCurrentNode->children().begin(); it != mCurrentNode->children().end(); ++it, ++index) {
169  if (!(*it)->mUpdated)
170  toRemove.push_back(std::make_tuple(index, it, *it));
171  }
172 
173  // second, go through them back to front (making sure iterators remain valid)
174  // remove contiguous subsequences as batch (listeners can profit from handling this as one merged update)
175  int count = 1;
176  for (auto i = toRemove.rbegin(); i != toRemove.rend(); ++i) {
177  auto inext = std::next(i);
178  if ((inext != toRemove.rend()) && (std::get<0>(*i) == std::get<0>(*inext)+1)) { // next one will be the neighbour index -> collect sequence
179  ++count;
180  continue;
181  }
182 
183  mCurrentNode->removeChildren(std::get<0>(*i), std::get<1>(*i), count);
184  count = 1;
185  }
186 
187  // finally (after nodes are removed from the parent and all listeners updated), actually delete these nodes
188  for (auto i = toRemove.rbegin(); i != toRemove.rend(); ++i) {
189  PropertyNode* p = std::get<2>(*i);
190  delete p;
191  }
192 
193  // go back to the parent node (but only if it is not NULL, otherwise we
194  // did not have a root node, so keep the top most node that we have
195  // created, it will be returned by reflectProperties)
196  if(parentNode)
197  mCurrentNode=parentNode;
198  }
199 
200 
201  void itemName(const std::string& name) {
202  if(mCurrentNode) {
203  // replace items only
204  if(mCurrentNode->mID.compare(0,4,"item")==0)
205  mCurrentNode->setName(name);
206  }
207  }
208 
209 public:
210 
211  // public entry points
212 
218  template <typename T>
219  void reflectProperties(PropertyNode* root, const std::string& name, T& object) {
220  mCurrentNode=root;
221  this->property(name.c_str(), object, "");
222  }
223 
228  template <typename T>
229  void reflectProperties(PropertyNode* root, const std::string& name,
230  const std::string& id, T& object) {
231  mCurrentNode=root;
232  this->property(name.c_str(), id, object, "");
233  }
234 
241  template <typename T>
242  PropertyNode* reflectProperties(const std::string& name, T& object) {
243  mCurrentNode=NULL;
244  this->property(name.c_str(), object, "");
245  assert(mCurrentNode!=NULL);
246  return mCurrentNode;
247  }
248 
253  template <typename T>
254  PropertyNode* reflectProperties(const std::string& name,
255  const std::string& id, T& object) {
256  mCurrentNode=NULL;
257  this->property(name.c_str(), id, object, "");
258  assert(mCurrentNode!=NULL);
259  return mCurrentNode;
260  }
261 
262 
263 private:
264 
265  template<typename T>
266  PropertyNode* createNode(PropertyNode* parentNode, T& member, const ReflectMemberMeta& meta,
267  PropertyHint& hint, bool& isReadOnly, bool& isVolatile)
268  {
269  if (parentNode) { // inherit read only and volatile flags
270  isReadOnly |= parentNode->isReadOnly();
271  isVolatile |= parentNode->isVolatile();
272  }
273 
274  PropertyNode* node = new TypedPropertyNodeImpl<T>(meta.id, meta.name,
275  meta.comment, member,
276  isReadOnly, isVolatile);
277 
278  // set the given hint to the node (by swapping the contents)
279  std::swap(node->mHint, hint);
280 
281  if (parentNode)
282  parentNode->addChild(node);
283 
284  return node;
285  }
286 
287 public:
288 
290 };
291 
293 
294 template <typename T>
296 {
297  if (!this->parent())
298  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
299 
301  s.reflectProperties(this->parent(), this->name().c_str(),
302  this->id(), *this->value());
303 }
304 
305 
306 // specialization for properties of pointers
307 template <typename T>
308 inline void TypedPropertyNodeImpl<T*>::synchronize()
309 {
310  if (!this->parent())
311  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
312 
314  s.reflectProperties(this->parent(), this->name().c_str(),
315  this->id(), *this->pointer());
316 }
317 
318 // specialization for properties with setter
319 template <typename Getter, typename Setter>
320 inline void TypedPropertyNodeImpl<Accessor<Getter,Setter>>::synchronize()
321 {
322  if (!this->parent())
323  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
324 
325  PropertySerializer s;
326  s.reflectProperties(this->parent(), this->name().c_str(),
327  this->id(), *this->accessor());
328 }
329 
331 
332 // specializations for STL containers
333 
334 namespace serialization { // our private namespace
335 
337 
338 template<typename Reflector, typename Container> struct ReflectReadSetItems;
339 
344 template<typename Container>
345 struct ReflectReadSetItems<PropertySerializer, Container>
346 {
347  typedef typename Container::value_type type;
348 
349  static void reflect(PropertySerializer& r, Container& c)
350  {
351  // store each item
352  int id=0;
353  foreach(const type& v, c)
354  {
355  r.roproperty("item", "item["+toString(id)+"]", v, "",
356  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
357  ++id;
358  }
359  }
360 };
361 
362 template<typename Reflector, typename Container> struct ReflectReadMapItems;
363 
369 template<typename Container>
370 struct ReflectReadMapItems<PropertySerializer, Container>
371 {
372  typedef typename Container::value_type value_type;
373 
374  static void reflect(PropertySerializer& r, Container& c)
375  {
376  // store each item
377  int id=0;
378  foreach(value_type& p, c)
379  {
380  r.roproperty("key", "key["+toString(id)+"]", p.first, "",
381  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
382 
383  // the values can be reflected/deserialized with tracking
384  MIRA_PROPERTY_WITH_ID(r, "item", "item["+toString(id)+"]", p.second, "",
385  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
386 
387  ++id;
388  }
389  }
390 };
391 
393 
394 } // namespace
395 
397 
399 
400 } // namespace
401 
402 #endif /* _MIRA_PROPERTYSERIALIZER_H_ */
Abstract base class for all derived property node classes.
Definition: PropertyNode.h:202
void object(T &member)
Is called for each complex object.
Definition: RecursiveMemberReflector.h:302
std::string mID
the unique id of the property
Definition: PropertyNode.h:178
PropertyNode * mCurrentNode
Definition: PropertySerializer.h:289
virtual PropertyNode * parent()
Returns the parent property node (or NULL, if this is a root node)
Definition: PropertyNode.h:224
const PropertyNode * findChildNode(const std::vector< std::string > &ids, std::size_t level=0) const
Searches for a child property node (which may also be a child of a child of a child, etc).
static void reflect(Reflector &r, Container &c)
Definition: StlCollections.h:142
void continueWithBaseInvoke(T &member, const ReflectMemberMeta &meta, PropertyHint &&hint, bool isReadOnly, bool isVolatile)
Is called by invokePropertyMemberOverwrite() and will call the actual Base::invokePropertyMemberOverw...
Definition: PropertySerializer.h:87
Declaration and implementation of the property node hierarchy.
#define MIRA_PROPERTY_WITH_ID(reflector, name, id, var,...)
Definition: ReflectorInterface.h:1053
specialize cv::DataType for our ImgPixel and inherit from cv::DataType<Vec>
Definition: IOService.h:67
void setName(const std::string &name)
For internal use by PropertySerializer only: Overrides the name of the property.
Definition: PropertyNode.h:173
virtual NodeList & children()
Returns a vector with all child property nodes.
Definition: PropertyNode.h:230
Stores meta information for each member.
Definition: ReflectMemberMeta.h:64
void continueWithBaseInvoke(Accessor< Getter, Setter > &accessor, const ReflectMemberMeta &meta, PropertyHint &&hint, bool isReadOnly, bool isVolatile)
Specialization of the above method for properties with getters and setters.
Definition: PropertySerializer.h:99
const char * name
The name (as specified in the XML file).
Definition: ReflectMemberMeta.h:67
void member(const char *name, T &member, const char *comment, ReflectCtrlFlags flags=REFLECT_CTRLFLAG_NONE)
Definition: PropertyReflector.h:75
#define MIRA_THROW(ex, msg)
Macro for throwing an exception.
Definition: Exception.h:81
A property hint gives optional instructions to the property editor, i.e.
Definition: PropertyHint.h:82
std::string toString(const T &value, int precision=-1)
Converts any data type to string (the data type must support the stream << operator).
Definition: ToString.h:256
boost::mpl::bool_< true > isReadOnly
Specifies, if the Reflector is read-only (true) or write-only (false).
Definition: ReflectorInterface.h:121
PropertySerializer()
Definition: PropertySerializer.h:73
static void reflect(Reflector &r, Container &c)
Definition: StlCollections.h:343
PropertyHint type(const std::string &t)
Sets the attribute "type" to the specified value.
Definition: PropertyHint.h:295
Container::value_type value_type
Definition: StlCollections.h:341
Implementation of TypedPropertyNode.
Definition: PropertyNode.h:811
void update(T &value)
Is called by PropertySerializer to update the internal representation of the value of the property...
Definition: PropertyNode.h:735
bool isReadOnly() const
Returns true, if this property is read-only and hence, can not be modified.
Definition: PropertyNode.h:167
A special PropertyReflector that creates a PropertyNode for each reflected property.
Definition: PropertySerializer.h:67
void itemName(const std::string &name)
Definition: PropertySerializer.h:201
This object is volatile: its memory location may become invalid to access.
Definition: ReflectControlFlags.h:90
const char * comment
Additional user comments.
Definition: ReflectMemberMeta.h:76
void invokePropertyMemberOverwrite(T &member, const ReflectMemberMeta &meta, PropertyHint &&hint, bool isReadOnly, bool isVolatile)
Invokes the PropertyReflector on the specified member.
Definition: PropertySerializer.h:113
PropertyNode * reflectProperties(const std::string &name, T &object)
Reflects the properties of the specified &#39;object&#39;.
Definition: PropertySerializer.h:242
The Accessor class is used as an adapter to reduce the code bloat within the reflection and serializa...
Definition: Accessor.h:244
void reflectProperties(PropertyNode *root, const std::string &name, const std::string &id, T &object)
Same as above, but additionally, a unique id can be specified for the object.
Definition: PropertySerializer.h:229
PropertyNode * reflectProperties(const std::string &name, const std::string &id, T &object)
Same as above, but additionally, a unique id can be specified for the object.
Definition: PropertySerializer.h:254
void removeChildren(int index, int count)
Removes contiguous children, starting at index (without deleting them).
Definition: PropertyNode.h:364
void addChild(PropertyNode *child, int index=-1)
Adds the specified property node as child node.
Base class for all Reflectors that take care of properties.
Base class for all Reflectors that take care of properties.
Definition: PropertyReflector.h:62
bool isVolatile() const
Returns true, if this property is volatile and hence, must be locked for access.
Definition: PropertyNode.h:170
void reflectProperties(PropertyNode *root, const std::string &name, T &object)
Reflects the properties of the specified &#39;object&#39;.
Definition: PropertySerializer.h:219
const std::string & name() const
Returns the name of this property as specified in the reflect() method.
Definition: PropertyNode.h:143
void property(const char *name, T &member, const char *comment, PropertyHint &&hint=PropertyHint(), ReflectCtrlFlags flags=REFLECT_CTRLFLAG_NONE)
Definition: PropertyReflector.h:126
friend class PropertySerializer
Definition: PropertyNode.h:729
const char * id
The id (used for containers where the name is identical, in all other cases the id usually is equal t...
Definition: ReflectMemberMeta.h:73
void invokePropertyMemberOverwrite(T &member, const ReflectMemberMeta &meta, PropertyHint &&hint, bool isReadOnly, bool isVolatile)
Is called by invokePropertyMember.
Definition: PropertyReflector.h:337
Container::value_type type
Definition: StlCollections.h:140