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 #include <set>
52 
55 
56 #include <tuple>
57 
58 namespace mira {
59 
61 
68 class PropertySerializer : public PropertyReflector<PropertySerializer>
69 {
71 
72 public:
73 
75  {}
76 
77 public:
78 
87  template <typename T>
89  PropertyHint&& hint, bool isReadOnly,
90  bool isVolatile) {
91  Base::invokePropertyMemberOverwrite(member, meta, std::move(hint),
92  isReadOnly, isVolatile);
93  }
94 
99  template <typename Getter, typename Setter>
101  const ReflectMemberMeta& meta, PropertyHint&& hint,
102  bool isReadOnly, bool isVolatile) {
103  }
104 
105  // implemented from base class
106 
113  template<typename T>
115  PropertyHint&& hint, bool isReadOnly,
116  bool isVolatile)
117  {
118  typedef typename boost::remove_const<T>::type TwithoutConst;
119 
120  // current node becomes parent node
121  PropertyNode* parentNode = mCurrentNode;
122 
123  if (meta.id)
124  {
125  PropertyNode* node = NULL;
126 
127  if (parentNode)
128  node = parentNode->findChildNode(meta.id);
129 
130  if (node) {
132  dynamic_cast<TypedPropertyNodeImpl<TwithoutConst>*>(node);
133  // if node already exists and has the right type, just update it
134  if (typedNode) {
135  TwithoutConst& nonconstMember = const_cast<TwithoutConst&>(member);
136  typedNode->update(nonconstMember);
137 
138  mUpdatedNodes.insert(node);
139  } else {
140  // We must NOT delete node here, to be able to signal the removal to
141  // listeners first.
142  // After setting the node to NULL, a new node will be created next.
143  // That will result in parentNode having 2 children with same name and id
144  // temporarily, but the older one will be removed in the cleanup below, as
145  // it was not updated.
146  node = NULL;
147  }
148  }
149  if (!node) { // if we cannot use an existing node, create a new one
150  TwithoutConst& nonconstMember = const_cast<TwithoutConst&>(member);
151  node = createNode(parentNode, nonconstMember, meta, hint, isReadOnly, isVolatile);
152  mUpdatedNodes.insert(node);
153  }
154 
155  // set the node as current node
156  mCurrentNode=node;
157  } else if (parentNode && isVolatile) {
158  parentNode->setVolatile(true);
159  }
160 
161  // now do the real reflector invoke (but only if T is a type that
162  // is worth to continue. If it is a GetterSetter, we stop here)
163  continueWithBaseInvoke(member,meta, std::move(hint), isReadOnly, isVolatile);
164 
165  // remove child nodes that have not been updated during serialization --> are obsolete
166 
167  // first, collect all child nodes to be removed (index + iterator + PropertyNode)
168  int index = 0;
169  std::vector<std::tuple<int, PropertyNode::NodeList::iterator, PropertyNode*>> toRemove;
170  for (PropertyNode::NodeList::iterator it = mCurrentNode->children().begin(); it != mCurrentNode->children().end(); ++it, ++index) {
171  if (mUpdatedNodes.find((*it)) == mUpdatedNodes.end())
172  toRemove.push_back(std::make_tuple(index, it, *it));
173  }
174 
175  // second, go through them back to front (making sure iterators remain valid)
176  // remove contiguous subsequences as batch (listeners can profit from handling this as one merged update)
177  int count = 1;
178  for (auto i = toRemove.rbegin(); i != toRemove.rend(); ++i) {
179  auto inext = std::next(i);
180  if ((inext != toRemove.rend()) && (std::get<0>(*i) == std::get<0>(*inext)+1)) { // next one will be the neighbour index -> collect sequence
181  ++count;
182  continue;
183  }
184 
185  mCurrentNode->removeChildren(std::get<0>(*i), std::get<1>(*i), count);
186  count = 1;
187  }
188 
189  // finally (after nodes are removed from the parent and all listeners updated), actually delete these nodes
190  for (auto i = toRemove.rbegin(); i != toRemove.rend(); ++i) {
191  PropertyNode* p = std::get<2>(*i);
192  delete p;
193  }
194 
195  // go back to the parent node (but only if it is not NULL, otherwise we
196  // did not have a root node, so keep the top most node that we have
197  // created, it will be returned by reflectProperties)
198  if(parentNode)
199  mCurrentNode=parentNode;
200  }
201 
202 
203  void itemName(const std::string& name) {
204  if(mCurrentNode) {
205  // replace items only
206  if(mCurrentNode->mID.compare(0,4,"item")==0)
207  mCurrentNode->setName(name);
208  }
209  }
210 
211 public:
212 
213  // public entry points
214 
220  template <typename T>
221  void reflectProperties(PropertyNode* root, const std::string& name, T& object) {
222  mCurrentNode=root;
223  mUpdatedNodes.clear();
224  this->property(name.c_str(), object, "");
225  }
226 
231  template <typename T>
232  void reflectProperties(PropertyNode* root, const std::string& name,
233  const std::string& id, T& object) {
234  mCurrentNode=root;
235  mUpdatedNodes.clear();
236  this->property(name.c_str(), id, object, "");
237  }
238 
245  template <typename T>
246  PropertyNode* reflectProperties(const std::string& name, T& object) {
247  mCurrentNode=NULL;
248  mUpdatedNodes.clear();
249  this->property(name.c_str(), object, "");
250  assert(mCurrentNode!=NULL);
251  return mCurrentNode;
252  }
253 
258  template <typename T>
259  PropertyNode* reflectProperties(const std::string& name,
260  const std::string& id, T& object) {
261  mCurrentNode=NULL;
262  mUpdatedNodes.clear();
263  this->property(name.c_str(), id, object, "");
264  assert(mCurrentNode!=NULL);
265  return mCurrentNode;
266  }
267 
268 
269 private:
270 
271  template<typename T>
272  PropertyNode* createNode(PropertyNode* parentNode, T& member, const ReflectMemberMeta& meta,
273  PropertyHint& hint, bool& isReadOnly, bool& isVolatile)
274  {
275  if (parentNode) { // inherit read only and volatile flags
276  isReadOnly |= parentNode->isReadOnly();
277  isVolatile |= parentNode->isVolatile();
278  }
279 
280  PropertyNode* node = new TypedPropertyNodeImpl<T>(meta.id, meta.name,
281  meta.comment, member,
282  isReadOnly, isVolatile);
283 
284  // set the given hint to the node (by swapping the contents)
285  std::swap(node->mHint, hint);
286 
287  if (parentNode)
288  parentNode->addChild(node);
289 
290  return node;
291  }
292 
293 public:
294 
296 
297 private:
298 
299  std::set<PropertyNode*> mUpdatedNodes;
300 };
301 
303 
304 template <typename T>
305 template <typename Type>
307 
308  return serialization::hasRecursiveReflect<Type, typename PropertySerializer::Tag>();
309 }
310 
311 
312 template <typename T>
313 inline void TypedPropertyNodeImpl<T>::synchronize(value_type& nodeValue)
314 {
315  if (!this->parent())
316  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
317 
319  s.reflectProperties(this->parent(), this->name().c_str(),
320  this->id(), nodeValue);
321 }
322 
323 
324 // specialization for properties of pointers
325 template <typename T>
326 inline void TypedPropertyNodeImpl<T*>::synchronize(value_type& nodePointer)
327 {
328  if (!this->parent())
329  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
330 
332  s.reflectProperties(this->parent(), this->name().c_str(),
333  this->id(), nodePointer);
334 }
335 
336 // specialization for properties with setter
337 template <typename Getter, typename Setter>
338 inline void TypedPropertyNodeImpl<Accessor<Getter,Setter>>::synchronize(AccessorType& nodeAccessor)
339 {
340  if (!this->parent())
341  MIRA_THROW(XInvalidParameter, "PropertyNode::synchronize() requires a valid parent node!");
342 
343  PropertySerializer s;
344  s.reflectProperties(this->parent(), this->name().c_str(),
345  this->id(), nodeAccessor);
346 }
347 
349 
350 // specializations for STL containers
351 
352 namespace serialization { // our private namespace
353 
355 
356 template<typename Reflector, typename Container> struct ReflectReadSetItems;
357 
362 template<typename Container>
363 struct ReflectReadSetItems<PropertySerializer, Container>
364 {
365  typedef typename Container::value_type type;
366 
367  static void reflect(PropertySerializer& r, Container& c)
368  {
369  // store each item
370  int id=0;
371  foreach(const type& v, c)
372  {
373  r.roproperty("item", "item["+toString(id)+"]", v, "",
374  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
375  ++id;
376  }
377  }
378 };
379 
380 template<typename Reflector, typename Container> struct ReflectReadMapItems;
381 
387 template<typename Container>
388 struct ReflectReadMapItems<PropertySerializer, Container>
389 {
390  typedef typename Container::value_type value_type;
391 
392  static void reflect(PropertySerializer& r, Container& c)
393  {
394  // store each item
395  int id=0;
396  foreach(value_type& p, c)
397  {
398  r.roproperty("key", "key["+toString(id)+"]", p.first, "",
399  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
400 
401  // the values can be reflected/deserialized with tracking
402  MIRA_PROPERTY_WITH_ID(r, "item", "item["+toString(id)+"]", p.second, "",
403  PropertyHint(), REFLECT_CTRLFLAG_VOLATILE);
404 
405  ++id;
406  }
407  }
408 };
409 
411 
412 } // namespace
413 
415 
417 
418 } // namespace
419 
420 #endif /* _MIRA_PROPERTYSERIALIZER_H_ */
Abstract base class for all derived property node classes.
Definition: PropertyNode.h:212
void object(T &member)
Is called for each complex object.
Definition: RecursiveMemberReflector.h:385
std::string mID
the unique id of the property
Definition: PropertyNode.h:188
PropertyNode * mCurrentNode
Definition: PropertySerializer.h:295
virtual PropertyNode * parent()
Returns the parent property node (or NULL, if this is a root node)
Definition: PropertyNode.h:234
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:88
Declaration and implementation of the property node hierarchy.
#define MIRA_PROPERTY_WITH_ID(reflector, name, id, var,...)
Definition: ReflectorInterface.h:1009
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:179
virtual NodeList & children()
Returns a vector with all child property nodes.
Definition: PropertyNode.h:240
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:100
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:78
void setVolatile(bool isVolatile)
Definition: PropertyNode.h:183
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:252
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:74
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
static constexpr bool mayHaveChildNodes()
Definition: PropertySerializer.h:306
Implementation of TypedPropertyNode.
Definition: PropertyNode.h:880
void update(T &value)
Is called by PropertySerializer to update the internal representation of the value of the property...
Definition: PropertyNode.h:804
bool isReadOnly() const
Returns true, if this property is read-only and hence, can not be modified.
Definition: PropertyNode.h:169
A special PropertyReflector that creates a PropertyNode for each reflected property.
Definition: PropertySerializer.h:68
void itemName(const std::string &name)
Definition: PropertySerializer.h:203
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:114
PropertyNode * reflectProperties(const std::string &name, T &object)
Reflects the properties of the specified &#39;object&#39;.
Definition: PropertySerializer.h:246
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:232
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:259
void removeChildren(int index, int count)
Removes contiguous children, starting at index (without deleting them).
Definition: PropertyNode.h:382
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.
void synchronize() override
Synchronizes this node and its children with the the actual underlying data representation.
Definition: PropertyNode.h:954
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:172
void reflectProperties(PropertyNode *root, const std::string &name, T &object)
Reflects the properties of the specified &#39;object&#39;.
Definition: PropertySerializer.h:221
const std::string & name() const
Returns the name of this property as specified in the reflect() method.
Definition: PropertyNode.h:145
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:798
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