ecto
tendril.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 #pragma once
30 #include <boost/shared_ptr.hpp>
31 #include <boost/function/function1.hpp>
32 #ifndef BOOST_SIGNALS2_MAX_ARGS
33  #define BOOST_SIGNALS2_MAX_ARGS 3
34 #endif
35 #include <boost/signals2.hpp>
36 #include <boost/any.hpp>
37 
38 #include <ecto/forward.hpp>
39 
40 #include <ecto/util.hpp> //name_of
41 #include <ecto/except.hpp>
42 
43 #include <ecto/python.hpp>
44 #include <ecto/python/repr.hpp>
45 
46 #include <vector>
47 #include <string>
48 #include <bitset>
49 
50 namespace ecto
51 {
52  namespace registry{
53  namespace tendril{
54  bool add(const ecto::tendril& t);
55  const ecto::tendril& get(const std::string& type_name);
56  std::vector<std::string> type_names();
57  template<typename T>
58  struct entry{
59  entry(const ecto::tendril& t)
60  {
61  add(t);
62  }
63  };
64  template<typename T>
65  void add(const ecto::tendril& t){
66  static entry<T> e(t);
67  }
68  }
69  }
85  {
86  public:
87  typedef boost::function1<void, tendril&> TendrilJob;
88 
89  enum {
90  DEFAULT_VALUE=0,
95  N_FLAGS
96  };
97 
98  struct empty_t { };
99  const static empty_t empty;
100 
105  tendril();
106 
107  ~tendril();
108 
109  tendril(const tendril& rhs);
110  tendril& operator=(const tendril& rhs);
111 
119  template <typename T>
120  tendril (const T& t, const std::string& doc)
121  : flags_()
122  , converter(&ConverterImpl<T>::instance)
123  {
124  flags_[DEFAULT_VALUE]=true;
125  set_holder<T>(t);
126  set_doc(doc);
127  }
128 
136  std::string
137  type_name() const;
138  const char* type_id() const {return type_ID_;}
139 
146  std::string
147  doc() const;
148 
153  void
154  set_doc(const std::string& doc_str);
155 
160  template<typename T>
161  void
162  set_default_val(const T& val = T())
163  {
164  enforce_type<T>();
165  flags_[DEFAULT_VALUE] = true;
166  set_holder<T>(val);
167  }
168 
169  void required(bool b);
170 
171  bool required() const;
172 
177  template<typename T>
178  inline const T&
179  get() const
180  {
181  enforce_type<T>();
182  return unsafe_get<T>();
183  }
184 
185  template<typename T>
186  inline T&
187  get()
188  {
189  enforce_type<T>();
190  return unsafe_get<T>();
191  }
192 
193  template <typename T>
194  void
195  operator<<(const T& val)
196  {
197  if(is_type<none>()) //handle none case.
198  {
199  set_holder<T>(val);
200  }else
201  {
202  //throws on failure
203  get<T>() = val;
204  }
205  }
206 
207  void operator<<(const boost::python::object& obj);
208 
209  tendril& operator<<(const tendril& rhs);
210 
215  template<typename T>
216  bool
217  is_type() const
218  {
219  return name_of<T>() == type_name();
220  }
221 
227  bool
228  same_type(const tendril& rhs) const;
229 
230  bool
231  compatible_type(const tendril& rhs) const;
232 
233  void
234  enforce_compatible_type(const tendril& rhs) const;
235 
239  template<typename T>
240  inline void
241  enforce_type() const
242  {
243  if (!is_type<T>())
244  BOOST_THROW_EXCEPTION(except::TypeMismatch()
245  << except::from_typename(type_name())
246  << except::to_typename(name_of<T>()));
247  }
248 
250  bool
251  user_supplied() const;
252 
253  void user_supplied(bool v);
254 
256  bool
257  has_default() const;
258 
260  struct none {
261  none& operator=(const none&) { return *this; }
262  const none& operator=(const none&) const { return *this; } // funny const assignment operator
263  friend bool operator==(const none&, const none&) { return true; }
264  friend std::ostream& operator<<(std::ostream& os, const none&)
265  {
266  os << "ecto::tendril::none"; return os;
267  }
268  };
269 
270  template<typename T>
271  struct Caller
272  {
273  typedef typename boost::function1<void, T> CbT;
274  Caller(CbT cb)
275  : cb(cb)
276  { }
277 
278  void
280  {
281  cb(t.get<T>());
282  }
283  CbT cb;
284  };
285 
286  template<typename Signature>
287  boost::signals2::connection connect(Signature slot)
288  {
289  return jobs_.connect(slot);
290  }
291 
297  template<typename T>
298  tendril&
299  set_callback(typename boost::function1<void, T> cb)
300  {
301  typedef Caller<T> CallerT;
302  enforce_type<T>();
303  connect(CallerT(cb));
304  return *this;
305  }
306 
308  void
309  notify();
310 
313  bool
314  dirty() const;
315 
317  void
318  dirty(bool);
319 
320  private:
321 
322  template<typename T>
323  inline const T& unsafe_get() const
324  {
325  return *boost::unsafe_any_cast<const T>(&holder_);
326  }
327 
328  template<typename T>
329  inline T& unsafe_get()
330  {
331  return *boost::unsafe_any_cast<T>(&holder_);
332  }
333 
334  struct Converter
335  {
336  virtual void operator()(tendril& t, const boost::python::object& o) const = 0;
337  virtual void operator()(boost::python::object& o, const tendril& t) const = 0;
338  };
339 
340  template <typename T, typename _=void>
342  {
344  void
345  operator()(tendril& t, const boost::python::object& obj) const
346  {
348  boost::python::extract<T> get_T(obj);
349  if (get_T.check())
350  t << get_T();
351  else
352  BOOST_THROW_EXCEPTION(except::FailedFromPythonConversion()
353  << except::pyobject_repr(ecto::py::repr(obj))
354  << except::cpp_typename(t.type_name()));
355  }
356 
357  void
358  operator()(boost::python::object& o, const tendril& t) const
359  {
361  const T& v = t.get<T>();
362  boost::python::object obj(v);
363  o = obj;
364  }
365  };
366 
367  template <typename _>
369  {
371  void
372  operator()(tendril& t, const boost::python::object& obj) const
373  {
374  t << obj;
375  }
376 
377  void
378  operator()(boost::python::object& o, const tendril& t) const
379  {
381  o = boost::python::object();
382  }
383  };
384 
385  template <typename T>
386  void set_holder(const T& t = T())
387  {
388  holder_ = t;
389  type_ID_ = name_of<T>().c_str();
390  converter = &ConverterImpl<T>::instance;
391  registry::tendril::add<T>(*this);
392  }
393  void copy_holder(const tendril& rhs);
394 
395  boost::any holder_;
396  const char* type_ID_;
397  std::string doc_;
398  std::bitset<N_FLAGS> flags_;
399  typedef boost::signals2::signal<void(tendril&)> job_signal_t;
400  job_signal_t jobs_;
402 
403  public:
404 
405 
406  template <typename T>
407  void operator>>(T& val) const
408  {
409  val = get<T>();
410  }
411 
412  void operator>>(boost::python::object& obj) const
413  {
414  (*converter)(obj, *this);
415  }
416 
417  void operator>>(const tendril_ptr& rhs) const
418  {
419  *rhs << *this;
420  }
421 
422  void operator>>(tendril_ptr& rhs) const
423  {
424  *rhs << *this;
425  }
426 
427  void operator>>(tendril& rhs) const
428  {
429  rhs << *this;
430  }
431 
432  template<typename T>
433  friend void
434  operator>>(const tendril_cptr& rhs, T& val)
435  {
436  if (!rhs)
437  BOOST_THROW_EXCEPTION(except::NullTendril()
438  << except::from_typename("(null)")
439  << except::to_typename(name_of<T>()));
440  *rhs >> val;
441  }
442 
443  // This is to avoid ambiguous conversion due to boost python funkiness.
444  // e.g. ISO C++ says that these are ambiguous, even...
445  friend void
446  operator>>(const tendril_ptr& rhs, boost::python::object& obj);
447 
448  // This is to avoid ambiguous conversion due to boost python funkiness.
449  // e.g. ISO C++ says that these are ambiguous, even...
450  friend void
451  operator>>(const tendril_cptr& rhs, boost::python::object& obj);
452 
453  template<typename T>
454  friend void
455  operator<<(const tendril_ptr& lhs, const T& rhs)
456  {
457  if (!lhs)
458  BOOST_THROW_EXCEPTION(except::NullTendril()
459  << except::to_typename("(null)")
460  << except::from_typename(name_of<T>()));
461  *lhs << rhs;
462  }
463 
464  friend void
465  operator<<(const tendril_ptr& lhs, const tendril_ptr& rhs);
466 
467  friend void
468  operator<<(const tendril_ptr& lhs, const tendril_cptr& rhs);
469 
470 
471  template <typename Archive>
472  void serialize(Archive& ar, const unsigned int);
473 
474  //my version of clang
475  //can't handle the friend impl inside the class.
476  template <typename T>
477  friend tendril_ptr make_tendril();
478 
479  };
480 
481  template <typename T>
483  {
484  tendril_ptr t(new tendril());
485  t->set_holder<T>();
486  return t;
487  }
488 
489  template <typename T, typename _>
492 
493  template <typename _>
496 
497 }
498 
boost::function1< void, T > CbT
Definition: tendril.hpp:273
void operator>>(tendril &rhs) const
Definition: tendril.hpp:427
std::string type_name() const
This is an unmangled type name for what ever tendril is holding.
CbT cb
Definition: tendril.hpp:283
Definition: tendril.hpp:341
boost::function1< void, tendril & > TendrilJob
Definition: tendril.hpp:87
std::vector< std::string > type_names()
tendril & set_callback(typename boost::function1< void, T > cb)
Definition: tendril.hpp:299
Definition: tendril.hpp:93
void set_holder(const T &t=T())
Definition: tendril.hpp:386
const char * type_ID_
Definition: tendril.hpp:396
const none & operator=(const none &) const
Definition: tendril.hpp:262
tendril(const T &t, const std::string &doc)
A convenience constructor for creating a tendril that holds the given type.
Definition: tendril.hpp:120
void operator()(tendril &t, const boost::python::object &obj) const
Definition: tendril.hpp:372
void set_default_val(const T &val=T())
This sets the default value of the tendril. This is a.
Definition: tendril.hpp:162
boost::shared_ptr< const tendril > tendril_cptr
Definition: forward.hpp:36
#define ECTO_EXPORT
Definition: util.hpp:49
bool is_type() const
runtime check if the tendril is of the given type.
Definition: tendril.hpp:217
A none type for tendril when the tendril is uninitialized.
Definition: tendril.hpp:260
Definition: parameters.hpp:11
Definition: tendril.hpp:94
const char * type_id() const
Definition: tendril.hpp:138
Definition: tendril.hpp:98
bool add(const ecto::tendril &t)
Definition: tendril.hpp:65
std::bitset< N_FLAGS > flags_
Definition: tendril.hpp:398
void operator()(tendril &t, const boost::python::object &obj) const
Definition: tendril.hpp:345
void operator>>(const tendril_ptr &rhs) const
Definition: tendril.hpp:417
tendril_ptr make_tendril()
Definition: tendril.hpp:482
void operator>>(boost::python::object &obj) const
Definition: tendril.hpp:412
static ConverterImpl< none, _ > instance
Definition: tendril.hpp:370
std::string repr(const boost::python::object &obj)
Converter * converter
Definition: tendril.hpp:401
Definition: tendril.hpp:271
#define ECTO_SCOPED_CALLPYTHON()
Definition: python.hpp:88
friend void operator>>(const tendril_cptr &rhs, T &val)
Definition: tendril.hpp:434
T & unsafe_get()
Definition: tendril.hpp:329
void operator>>(tendril_ptr &rhs) const
Definition: tendril.hpp:422
none & operator=(const none &)
Definition: tendril.hpp:261
const T & unsafe_get() const
Definition: tendril.hpp:323
void enforce_type() const
runtime check if the tendril is of the given type, this will throw.
Definition: tendril.hpp:241
Definition: tendril.hpp:91
boost::signals2::connection connect(Signature slot)
Definition: tendril.hpp:287
friend std::ostream & operator<<(std::ostream &os, const none &)
Definition: tendril.hpp:264
boost::shared_ptr< tendril > tendril_ptr
Definition: forward.hpp:34
Caller(CbT cb)
Definition: tendril.hpp:274
std::string doc_
Definition: tendril.hpp:397
job_signal_t jobs_
Definition: tendril.hpp:400
Definition: tendril.hpp:58
void operator()(boost::python::object &o, const tendril &t) const
Definition: tendril.hpp:378
A tendril is the slender, winding organ of the ecto::cell that gives it its awesome type erasure and ...
Definition: tendril.hpp:84
boost::any holder_
Definition: tendril.hpp:395
Definition: tendril.hpp:368
boost::signals2::signal< void(tendril &)> job_signal_t
Definition: tendril.hpp:399
E const & operator<<(E const &x, error_info< ::ecto::except::detail::wrap< Tag >, T > const &v)
void operator()(tendril &t)
Definition: tendril.hpp:279
const T & get() const
Definition: tendril.hpp:179
static const empty_t empty
Definition: tendril.hpp:99
void operator>>(T &val) const
Definition: tendril.hpp:407
void operator()(boost::python::object &o, const tendril &t) const
Definition: tendril.hpp:358
static ConverterImpl< T, _ > instance
Definition: tendril.hpp:343
friend bool operator==(const none &, const none &)
Definition: tendril.hpp:263
Definition: tendril.hpp:334
entry(const ecto::tendril &t)
Definition: tendril.hpp:59
Definition: tendril.hpp:92