MTC
properties.h
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2017, Bielefeld University
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Bielefeld University nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Robert Haschke
36  Desc: PropertyMap stores variables of stages
37 */
38 
39 #pragma once
40 
41 #include <boost/any.hpp>
42 #include <typeindex>
43 #include <map>
44 #include <set>
45 #include <vector>
46 #include <functional>
47 #include <sstream>
48 #include <ros/serialization.h>
49 
50 namespace moveit {
51 namespace task_constructor {
52 
53 class Property;
54 class PropertyMap;
55 
57 boost::any fromName(const PropertyMap& other, const std::string& other_name);
58 
69 class Property
70 {
71  friend class PropertyMap;
72 
74  Property(const boost::typeindex::type_info& type_info, const std::string& description,
75  const boost::any& default_value);
76 
77 public:
78  using type_info = boost::typeindex::type_info;
79 
81  Property();
82 
84  class error;
86  class undeclared;
88  class undefined;
90  class type_error;
91 
92  using SourceFlags = uint;
94  using InitializerFunction = std::function<boost::any(const PropertyMap&)>;
95 
97  void setValue(const boost::any& value);
98  void setCurrentValue(const boost::any& value);
99  void setDefaultValue(const boost::any& value);
100 
102  void reset();
103 
105  inline bool defined() const { return !value_.empty(); }
106 
108  inline const boost::any& value() const { return value_.empty() ? default_ : value_; }
109  inline boost::any& value() { return value_.empty() ? default_ : value_; }
111  const boost::any& defaultValue() const { return default_; }
112 
114  static std::string serialize(const boost::any& value);
115  static boost::any deserialize(const std::string& type_name, const std::string& wire);
116  std::string serialize() const { return serialize(value()); }
117 
119  const std::string& description() const { return description_; }
120  void setDescription(const std::string& desc) { description_ = desc; }
121 
123  static std::string typeName(const type_info& type_info);
124  std::string typeName() const;
125 
127  bool initsFrom(SourceFlags source) const;
129  Property& configureInitFrom(SourceFlags source, const InitializerFunction& f);
131  Property& configureInitFrom(SourceFlags source, const std::string& name);
132 
133 private:
134  std::string description_;
135  const type_info& type_info_;
136  boost::any default_;
137  boost::any value_;
138 
140  SourceFlags source_flags_ = 0;
141  SourceFlags initialized_from_;
142  InitializerFunction initializer_;
143 };
144 
145 class Property::error : public std::runtime_error
146 {
147 protected:
148  std::string property_name_;
149  std::string msg_;
150 
151 public:
152  explicit error(const std::string& msg);
153  const std::string& name() const { return property_name_; }
154  void setName(const std::string& name);
155  const char* what() const noexcept override { return msg_.c_str(); }
156 };
158 {
159 public:
160  explicit undeclared(const std::string& name, const std::string& msg = "undeclared");
161 };
163 {
164 public:
165  explicit undefined(const std::string& name, const std::string& msg = "undefined");
166 };
168 {
169 public:
170  explicit type_error(const std::string& current_type, const std::string& declared_type);
171 };
172 
173 // hasSerialize<T>::value provides a true/false constexpr depending on whether operator<< is supported.
174 // This uses SFINAE, extracted from https://jguegant.github.io/blogs/tech/sfinae-introduction.html
175 template <typename T, typename = std::ostream&>
176 struct hasSerialize : std::false_type
177 {};
178 
179 template <typename T>
180 struct hasSerialize<T, decltype(std::declval<std::ostream&>() << std::declval<T>())> : std::true_type
181 {};
182 
183 template <typename T, typename = std::istream&>
184 struct hasDeserialize : std::false_type
185 {};
186 
187 template <typename T>
188 struct hasDeserialize<T, decltype(std::declval<std::istream&>() >> std::declval<T&>())> : std::true_type
189 {};
190 
192 {
193 public:
194  using SerializeFunction = std::string (*)(const boost::any&);
195  using DeserializeFunction = boost::any (*)(const std::string&);
196 
197  static std::string dummySerialize(const boost::any& /*unused*/) { return ""; }
198  static boost::any dummyDeserialize(const std::string& /*unused*/) { return boost::any(); }
199 
200 protected:
201  static bool insert(const std::type_index& type_index, const std::string& type_name, SerializeFunction serialize,
202  DeserializeFunction deserialize);
203 };
204 
206 template <typename T>
208 {
209 public:
210  PropertySerializer() { insert(typeid(T), typeName<T>(), &serialize, &deserialize); }
211 
212  template <class Q = T>
213  static typename std::enable_if<ros::message_traits::IsMessage<Q>::value, std::string>::type typeName() {
214  return ros::message_traits::DataType<T>::value();
215  }
216 
217  template <class Q = T>
218  static typename std::enable_if<!ros::message_traits::IsMessage<Q>::value, std::string>::type typeName() {
219  return typeid(T).name();
220  }
221 
222 private:
224  template <class Q = T>
225  static typename std::enable_if<hasSerialize<Q>::value, std::string>::type serialize(const boost::any& value) {
226  std::ostringstream oss;
227  oss << boost::any_cast<T>(value);
228  return oss.str();
229  }
230  template <class Q = T>
231  static typename std::enable_if<hasSerialize<Q>::value && hasDeserialize<Q>::value, boost::any>::type
232  deserialize(const std::string& wired) {
233  std::istringstream iss(wired);
234  T value;
235  iss >> value;
236  return value;
237  }
238 
240  template <class Q = T>
241  static typename std::enable_if<!hasSerialize<Q>::value, std::string>::type serialize(const boost::any& value) {
242  return dummySerialize(value);
243  }
244  template <class Q = T>
245  static typename std::enable_if<!hasSerialize<Q>::value || !hasDeserialize<Q>::value, boost::any>::type
246  deserialize(const std::string& wire) {
247  return dummyDeserialize(wire);
248  }
249 };
250 
257 {
258  std::map<std::string, Property> props_;
259 
261  Property& declare(const std::string& name, const Property::type_info& type_info, const std::string& description,
262  const boost::any& default_value);
263 
264 public:
266  template <typename T>
267  Property& declare(const std::string& name, const std::string& description = "") {
268  PropertySerializer<T>(); // register serializer/deserializer
269  return declare(name, typeid(T), description, boost::any());
270  }
272  template <typename T>
273  Property& declare(const std::string& name, const T& default_value, const std::string& description = "") {
274  PropertySerializer<T>(); // register serializer/deserializer
275  return declare(name, typeid(T), description, default_value);
276  }
277 
279  void exposeTo(PropertyMap& other, const std::set<std::string>& properties) const;
280 
282  void exposeTo(PropertyMap& other, const std::string& name, const std::string& other_name) const;
283 
285  bool hasProperty(const std::string& name) const;
286 
288  Property& property(const std::string& name);
289  const Property& property(const std::string& name) const { return const_cast<PropertyMap*>(this)->property(name); }
290 
291  using iterator = std::map<std::string, Property>::iterator;
292  using const_iterator = std::map<std::string, Property>::const_iterator;
293 
294  iterator begin() { return props_.begin(); }
295  iterator end() { return props_.end(); }
296  const_iterator begin() const { return props_.begin(); }
297  const_iterator end() const { return props_.end(); }
298 
300  void configureInitFrom(Property::SourceFlags source, const std::set<std::string>& properties = {});
301 
303  template <typename T>
304  void set(const std::string& name, const T& value) {
305  auto it = props_.find(name);
306  if (it == props_.end()) // name is not yet declared
307  declare<T>(name, value, "");
308  else
309  it->second.setValue(value);
310  }
311 
313  inline void set(const std::string& name, const char* value) { set<std::string>(name, value); }
314 
316  void setCurrent(const std::string& name, const boost::any& value);
317 
319  const boost::any& get(const std::string& name) const;
320 
322  template <typename T>
323  const T& get(const std::string& name) const {
324  const boost::any& value = get(name);
325  if (value.empty())
326  throw Property::undefined(name);
327  return boost::any_cast<const T&>(value);
328  }
330  template <typename T>
331  const T& get(const std::string& name, const T& fallback) const {
332  const boost::any& value = get(name);
333  return (value.empty()) ? fallback : boost::any_cast<const T&>(value);
334  }
335 
337  size_t countDefined(const std::vector<std::string>& list) const;
338 
340  void reset();
341 
343  void performInitFrom(Property::SourceFlags source, const PropertyMap& other);
344 };
345 
346 // boost::any needs a specialization to avoid infinite recursion
347 template <>
348 void PropertyMap::set<boost::any>(const std::string& name, const boost::any& value);
349 
350 } // namespace task_constructor
351 } // namespace moveit
Definition: properties.h:257
void performInitFrom(Property::SourceFlags source, const PropertyMap &other)
perform initialization of still undefined properties using configured initializers
Definition: properties.cpp:272
void set(const std::string &name, const char *value)
overloading: const char* is stored as std::string
Definition: properties.h:313
void setCurrent(const std::string &name, const boost::any &value)
temporarily set the value of a property
Definition: properties.cpp:250
void exposeTo(PropertyMap &other, const std::set< std::string > &properties) const
declare all given properties also in other PropertyMap
Definition: properties.cpp:216
bool hasProperty(const std::string &name) const
check whether given property is declared
Definition: properties.cpp:204
Property & declare(const std::string &name, const T &default_value, const std::string &description="")
declare a property with default value
Definition: properties.h:273
void configureInitFrom(Property::SourceFlags source, const std::set< std::string > &properties={})
allow initialization from given source for listed properties - always using the same name
Definition: properties.cpp:226
size_t countDefined(const std::vector< std::string > &list) const
count number of defined properties from given list
Definition: properties.cpp:258
Property & property(const std::string &name)
get the property with given name, throws Property::undeclared for unknown name
Definition: properties.cpp:209
const boost::any & get(const std::string &name) const
Get the value of a property. Throws undeclared if unknown name.
Definition: properties.cpp:254
void reset()
reset all properties to their defaults
Definition: properties.cpp:267
const T & get(const std::string &name, const T &fallback) const
get typed value of property, using fallback if undefined. Throws bad_any_cast on type mismatch.
Definition: properties.h:331
const T & get(const std::string &name) const
Get typed value of property. Throws undeclared, undefined, or bad_any_cast.
Definition: properties.h:323
Property & declare(const std::string &name, const std::string &description="")
declare a property for future use
Definition: properties.h:267
void set(const std::string &name, const T &value)
set (and, if neccessary, declare) the value of a property
Definition: properties.h:304
utility class to register serializer/deserializer functions for a property of type T
Definition: properties.h:208
Definition: properties.h:146
Definition: properties.h:70
void reset()
reset to default value (which can be empty)
Definition: properties.cpp:143
bool initsFrom(SourceFlags source) const
return true, if property initialized from given SourceId
Definition: properties.cpp:177
std::function< boost::any(const PropertyMap &)> InitializerFunction
function callback used to initialize property value from another PropertyMap
Definition: properties.h:94
const boost::any & value() const
get current value (or default if not defined)
Definition: properties.h:108
bool defined() const
the current value defined or will the fallback be used?
Definition: properties.h:105
const std::string & description() const
get description text
Definition: properties.h:119
Property & configureInitFrom(SourceFlags source, const InitializerFunction &f)
configure initialization from source using an arbitrary function
Definition: properties.cpp:181
const boost::any & defaultValue() const
get default value
Definition: properties.h:111
Property()
Construct a property holding a any value.
Definition: properties.cpp:120
void setValue(const boost::any &value)
set current value and default value
Definition: properties.cpp:122
Definition: properties.h:185
Definition: properties.h:177