libqi-api  2.4.3.28
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
genericobject.hpp
Go to the documentation of this file.
1 #pragma once
2 /*
3 ** Copyright (C) 2013 Aldebaran Robotics
4 ** See COPYING for the license
5 */
6 
7 #ifndef _QI_TYPE_DETAIL_GENERIC_OBJECT_HPP_
8 #define _QI_TYPE_DETAIL_GENERIC_OBJECT_HPP_
9 
10 #include <map>
11 #include <string>
12 
13 #include <boost/smart_ptr/enable_shared_from_this.hpp>
14 
15 #include <qi/api.hpp>
18 #include <qi/future.hpp>
19 #include <qi/signal.hpp>
20 #include <qi/type/typeobject.hpp>
21 
22 #ifdef _MSC_VER
23 # pragma warning( push )
24 # pragma warning( disable: 4251 )
25 #endif
26 
27 namespace qi
28 {
29 
30 /* ObjectValue
31  * static version wrapping class C: Type<C>
32  * dynamic version: Type<DynamicObject>
33  *
34  * All the methods are convenience wrappers that bounce to the ObjectTypeInterface,
35  * except Event Loop management
36  * This class has pointer semantic. Do not use directly, use AnyObject,
37  * obtained through Session, DynamicObjectBuilder or ObjectTypeBuilder.
38  */
40  : public Manageable
41  , public boost::enable_shared_from_this<GenericObject>
42 {
43 public:
44  GenericObject(ObjectTypeInterface *type, void *value);
45  ~GenericObject();
46  const MetaObject &metaObject();
47 
48 #ifdef DOXYGEN
49  // Help doxygen and the header reader a bit.
50  template<typename R>
51  R call(
52  const std::string& eventName,
61 
62  template<typename R>
64  const std::string& eventName,
73 #else
74  // Declare genCall, using overloads for all argument count instead of default values.
75  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
76  template<typename R> R call( \
77  const std::string& methodName comma \
78  QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference));
80  #undef genCall
81 
82  #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
83  template<typename R> qi::Future<R> async( \
84  const std::string& methodName comma \
85  QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference));
87  #undef genCall
88 #endif // DOXYGEN
89 
90  qi::Future<AnyReference> metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
91 
94  int findMethod(const std::string& name, const GenericFunctionParameters& parameters);
95 
103  qi::Future<AnyReference> metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
104 
105  void post(const std::string& eventName,
114 
115  void metaPost(unsigned int event, const GenericFunctionParameters& params);
116  void metaPost(const std::string &nameWithOptionalSignature, const GenericFunctionParameters &in);
117 
123  template <typename FUNCTOR_TYPE>
124  qi::FutureSync<SignalLink> connect(const std::string& eventName, FUNCTOR_TYPE callback,
125  MetaCallType threadingModel = MetaCallType_Direct);
126 
127 
128  qi::FutureSync<SignalLink> connect(const std::string &name, const SignalSubscriber& functor);
129 
131  qi::FutureSync<SignalLink> connect(unsigned int signal, const SignalSubscriber& subscriber);
132 
140  qi::FutureSync<SignalLink> connect(unsigned int signal, AnyObject target, unsigned int slot);
141 
143  qi::FutureSync<void> disconnect(SignalLink linkId);
144 
145  template<typename T>
146  qi::FutureSync<T> property(const std::string& name);
147 
148  template<typename T>
149  qi::FutureSync<void> setProperty(const std::string& name, const T& val);
150 
151  //Low Level Properties
152  qi::FutureSync<AnyValue> property(unsigned int id);
153  qi::FutureSync<void> setProperty(unsigned int id, const AnyValue &val);
154 
155 
156  bool isValid() { return type && value;}
158  void* value;
159 };
160 
161 namespace detail
162 {
163 
164 // Storage type used by Object<T>, and Proxy.
165 typedef boost::shared_ptr<class GenericObject> ManagedObjectPtr;
166 
167 }
168 
169 // C4251
170 template <typename FUNCTION_TYPE>
172  FUNCTION_TYPE callback,
173  MetaCallType model)
174 {
175  return connect(eventName,
176  SignalSubscriber(AnyFunction::from(callback), model));
177 }
178 
179 namespace detail
180 {
181 
182 template <typename T>
183 struct isFuture : boost::false_type {};
184 template <typename T>
185 struct isFuture<qi::Future<T> > : boost::true_type {};
186 template <typename T>
187 struct isFuture<qi::FutureSync<T> > : boost::true_type {};
188 
189 }
190 
191 /* Generate R GenericObject::call(methodname, args...)
192  * for all argument counts
193  * The function packs arguments in a vector<AnyReference>, computes the
194  * signature and bounce those to metaCall.
195  */
196 
197 #define pushi(z, n,_) params.push_back(p ## n);
198 
199 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
200  template <typename R> \
201  R GenericObject::call(const std::string& methodName comma \
202  QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
203  { \
204  BOOST_STATIC_ASSERT_MSG(!detail::isFuture<R>::value, \
205  "return type of call must not be a Future"); \
206  if (!value || !type) \
207  { \
208  throw std::runtime_error("Invalid GenericObject"); \
209  } \
210  std::vector<qi::AnyReference> params; \
211  params.reserve(n); \
212  BOOST_PP_REPEAT(n, pushi, _) \
213  qi::Future<AnyReference> fmeta = metaCall( \
214  methodName, params, MetaCallType_Direct, typeOf<R>()->signature()); \
215  return detail::extractFuture<R>(fmeta); \
216  } \
217  template <typename R> \
218  qi::Future<R> GenericObject::async( \
219  const std::string& methodName comma \
220  QI_GEN_ARGSDECLSAMETYPE(n, qi::AutoAnyReference)) \
221  { \
222  BOOST_STATIC_ASSERT_MSG(!detail::isFuture<R>::value, \
223  "return type of async must not be a Future"); \
224  if (!value || !type) \
225  { \
226  return makeFutureError<R>("Invalid GenericObject"); \
227  } \
228  std::vector<qi::AnyReference> params; \
229  params.reserve(n); \
230  BOOST_PP_REPEAT(n, pushi, _) \
231  qi::Promise<R> res(&qi::PromiseNoop<R>); \
232  qi::Future<AnyReference> fmeta = metaCall( \
233  methodName, params, MetaCallType_Queued, typeOf<R>()->signature()); \
234  qi::adaptFutureUnwrap(fmeta, res); \
235  return res.future(); \
236  }
238 #undef genCall
239 
240 #undef pushi
241 
242 template<typename T>
244 {
245  int pid = metaObject().propertyId(name);
246  if (pid < 0)
247  return makeFutureError<T>("Property not found");
249  qi::Promise<T> p;
250  f.connect(boost::bind(&detail::futureAdapterVal<T>,_1, p),
252  return p.future();
253 }
254 
255 template<typename T>
256 qi::FutureSync<void> GenericObject::setProperty(const std::string& name, const T& val)
257 {
258  int pid = metaObject().propertyId(name);
259  if (pid < 0)
260  return makeFutureError<void>("Property not found");
261  return setProperty(pid, AnyValue::from(val));
262 }
263 
264 /* An AnyObject is actually of a Dynamic type: The underlying TypeInterface*
265  * is not allways the same.
266  * Override backend shared_ptr<GenericObject>
267 */
268 template<>
269 class QI_API TypeImpl<boost::shared_ptr<GenericObject> > :
270  public DynamicTypeInterface
271 {
272 public:
273  virtual AnyReference get(void* storage)
274  {
275  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(&storage);
276  AnyReference result;
277  if (!*val)
278  {
279  return AnyReference();
280  }
281  return AnyReference((*val)->type, (*val)->value);
282  }
283 
284  virtual void set(void** storage, AnyReference source)
285  {
286  qiLogCategory("qitype.object");
287  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(storage);
288  if (source.type()->info() == info())
289  { // source is objectptr
290  detail::ManagedObjectPtr* src = source.ptr<detail::ManagedObjectPtr>(false);
291  if (!*src)
292  qiLogWarning() << "NULL Object";
293  *val = *src;
294  }
295  else if (source.kind() == TypeKind_Dynamic)
296  { // try to dereference dynamic type in case it contains an object
297  set(storage, source.content());
298  }
299  else if (source.kind() == TypeKind_Object)
300  { // wrap object in objectptr: we do not keep it alive,
301  // but source type offers no tracking capability
302  detail::ManagedObjectPtr op(new GenericObject(static_cast<ObjectTypeInterface*>(source.type()), source.rawValue()));
303  *val = op;
304  }
305  else if (source.kind() == TypeKind_Pointer)
306  {
307  PointerTypeInterface* ptype = static_cast<PointerTypeInterface*>(source.type());
308  // FIXME: find a way!
309  if (ptype->pointerKind() == PointerTypeInterface::Shared)
310  qiLogInfo() << "Object will *not* track original shared pointer";
311  set(storage, *source);
312  }
313  else
314  throw std::runtime_error((std::string)"Cannot assign non-object " + source.type()->infoString() + " to Object");
315  }
316 
317  typedef DefaultTypeImplMethods<detail::ManagedObjectPtr, TypeByPointerPOD<detail::ManagedObjectPtr> > Methods;
318  _QI_BOUNCE_TYPE_METHODS(Methods);
319 };
320 
321 }
322 
323 #ifdef _MSC_VER
324 # pragma warning( pop )
325 #endif
326 
327 #endif
#define QI_API
Definition: api.hpp:34
static AnyFunction from(F func)
qi::FutureSync< SignalLink > connect(const std::string &eventName, FUNCTOR_TYPE callback, MetaCallType threadingModel=MetaCallType_Direct)
qi::Future< AnyReference > metaCall(ExecutionContext *ec, ObjectThreadingModel objectThreadingModel, MetaCallType methodThreadingModel, MetaCallType callType, AnyObject manageable, unsigned int methodId, AnyFunction func, const GenericFunctionParameters &params, bool noCloneFirst=false, unsigned int callerId=0, qi::os::timeval postTimestamp=qi::os::timeval())
#define qiLogCategory(Cat)
Definition: log.hpp:46
boost::function< RF > bind(const AF &fun,...)
int propertyId(const std::string &name) const
static AnyValue from(const T &r)
Definition: anyvalue.hpp:87
Honor the default behavior.
Definition: typeobject.hpp:21
dll import/export and compiler message
#define qiLogWarning(...)
Log in warning mode.
Definition: log.hpp:102
Future< T > future() const
Get a future linked to this promise. Can be called multiple times.
Definition: future_fwd.hpp:708
boost::shared_ptr< class GenericObject > ManagedObjectPtr
Future< R > async(boost::function< R()> callback, uint64_t usDelay=0)
Definition: eventloop.hpp:176
Force a synchronous call.
Definition: typeobject.hpp:23
#define qiLogInfo(...)
Log in info mode.
Definition: log.hpp:91
#define _QI_BOUNCE_TYPE_METHODS(Bounce)
Implement all methods of Type as bouncers to Bouncer.
Definition: typeimpl.hxx:275
qi::FutureSync< void > setProperty(const std::string &name, const T &val)
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)
ObjectTypeInterface * type
qi::FutureSync< T > property(const std::string &name)
MetaCallType
Definition: typeobject.hpp:19
const MetaObject & metaObject()
qi::uint64_t SignalLink
Definition: signal.hpp:33
#define QI_GEN(f)
Definition: preproc.hpp:476
Description of the signals and methods accessible on an ObjectTypeInterface.
Definition: metaobject.hpp:25