libqi-api  release-2.5.3-2016-11-18
 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  // Help doxygen and the header reader a bit.
49  template <typename R, typename... Args>
50  R call(const std::string& methodName, Args&&... args);
51 
52  template <typename R, typename... Args>
53  qi::Future<R> async(const std::string& methodName, Args&&... args);
54 
55  qi::Future<AnyReference> metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
56 
59  int findMethod(const std::string& name, const GenericFunctionParameters& parameters);
60 
68  qi::Future<AnyReference> metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters& params, MetaCallType callType = MetaCallType_Auto, Signature returnSignature = Signature());
69 
70  void post(const std::string& eventName,
79 
80  void metaPost(unsigned int event, const GenericFunctionParameters& params);
81  void metaPost(const std::string &nameWithOptionalSignature, const GenericFunctionParameters &in);
82 
88  template <typename FUNCTOR_TYPE>
89  qi::FutureSync<SignalLink> connect(const std::string& eventName, FUNCTOR_TYPE callback,
90  MetaCallType threadingModel = MetaCallType_Direct);
91 
92 
93  qi::FutureSync<SignalLink> connect(const std::string &name, const SignalSubscriber& functor);
94 
96  qi::FutureSync<SignalLink> connect(unsigned int signal, const SignalSubscriber& subscriber);
97 
105  qi::FutureSync<SignalLink> connect(unsigned int signal, AnyObject target, unsigned int slot);
106 
108  qi::FutureSync<void> disconnect(SignalLink linkId);
109 
110  template<typename T>
111  qi::FutureSync<T> property(const std::string& name);
112 
113  template<typename T>
114  qi::FutureSync<void> setProperty(const std::string& name, const T& val);
115 
116  //Low Level Properties
117  qi::FutureSync<AnyValue> property(unsigned int id);
118  qi::FutureSync<void> setProperty(unsigned int id, const AnyValue &val);
119 
120 
121  bool isValid() { return type && value;}
123  void* value;
124 };
125 
126 namespace detail
127 {
128 
129 // Storage type used by Object<T>, and Proxy.
130 using ManagedObjectPtr = boost::shared_ptr<class GenericObject>;
131 
132 }
133 
134 // C4251
135 template <typename FUNCTION_TYPE>
137  FUNCTION_TYPE callback,
138  MetaCallType model)
139 {
140  return connect(eventName,
141  SignalSubscriber(AnyFunction::from(callback), model));
142 }
143 
144 namespace detail
145 {
146 
147 template <typename T>
148 struct isFuture : boost::false_type {};
149 template <typename T>
150 struct isFuture<qi::Future<T> > : boost::true_type {};
151 template <typename T>
152 struct isFuture<qi::FutureSync<T> > : boost::true_type {};
153 
154 }
155 
156 /* Generate R GenericObject::call(methodname, args...)
157  * for all argument counts
158  * The function packs arguments in a vector<AnyReference>, computes the
159  * signature and bounce those to metaCall.
160  */
161 
162 template <typename R, typename... Args>
163 R GenericObject::call(const std::string& methodName, Args&&... args)
164 {
165  static_assert(!detail::isFuture<R>::value, "return type of call must not be a Future");
166  if (!value || !type)
167  throw std::runtime_error("Invalid GenericObject");
168  std::vector<qi::AnyReference> params = {qi::AnyReference::from(args)...};
169  qi::Future<AnyReference> fmeta = metaCall(methodName, params, MetaCallType_Direct, typeOf<R>()->signature());
170  return detail::extractFuture<R>(fmeta);
171 }
172 
173 template <typename R, typename... Args>
174 qi::Future<R> GenericObject::async(const std::string& methodName, Args&&... args)
175 {
176  static_assert(!detail::isFuture<R>::value, "return type of async must not be a Future");
177  if (!value || !type)
178  return makeFutureError<R>("Invalid GenericObject");
179  std::vector<qi::AnyReference> params = {qi::AnyReference::from(args)...};
180  qi::Promise<R> res(&qi::PromiseNoop<R>);
181  qi::Future<AnyReference> fmeta = metaCall(methodName, params, MetaCallType_Queued, typeOf<R>()->signature());
182  qi::adaptFutureUnwrap(fmeta, res);
183  return res.future();
184 }
185 
186 template<typename T>
188 {
189  int pid = metaObject().propertyId(name);
190  if (pid < 0)
191  return makeFutureError<T>("Property not found");
193  qi::Promise<T> p;
194  f.connect(boost::bind(&detail::futureAdapterVal<T>,_1, p),
196  return p.future();
197 }
198 
199 template<typename T>
200 qi::FutureSync<void> GenericObject::setProperty(const std::string& name, const T& val)
201 {
202  int pid = metaObject().propertyId(name);
203  if (pid < 0)
204  return makeFutureError<void>("Property not found");
205  return setProperty(pid, AnyValue::from(val));
206 }
207 
208 /* An AnyObject is actually of a Dynamic type: The underlying TypeInterface*
209  * is not allways the same.
210  * Override backend shared_ptr<GenericObject>
211 */
212 template<>
213 class QI_API TypeImpl<boost::shared_ptr<GenericObject>> :
214  public DynamicTypeInterface
215 {
216 public:
217  AnyReference get(void* storage) override
218  {
219  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(&storage);
220  AnyReference result;
221  if (!*val)
222  {
223  return AnyReference();
224  }
225  return AnyReference((*val)->type, (*val)->value);
226  }
227 
228  void set(void** storage, AnyReference source) override
229  {
230  qiLogCategory("qitype.object");
231  detail::ManagedObjectPtr* val = (detail::ManagedObjectPtr*)ptrFromStorage(storage);
232  if (source.type()->info() == info())
233  { // source is objectptr
234  detail::ManagedObjectPtr* src = source.ptr<detail::ManagedObjectPtr>(false);
235  if (!*src)
236  qiLogWarning() << "NULL Object";
237  *val = *src;
238  }
239  else if (source.kind() == TypeKind_Dynamic)
240  { // try to dereference dynamic type in case it contains an object
241  set(storage, source.content());
242  }
243  else if (source.kind() == TypeKind_Object)
244  { // wrap object in objectptr: we do not keep it alive,
245  // but source type offers no tracking capability
246  detail::ManagedObjectPtr op(new GenericObject(static_cast<ObjectTypeInterface*>(source.type()), source.rawValue()));
247  *val = op;
248  }
249  else if (source.kind() == TypeKind_Pointer)
250  {
251  PointerTypeInterface* ptype = static_cast<PointerTypeInterface*>(source.type());
252  // FIXME: find a way!
253  if (ptype->pointerKind() == PointerTypeInterface::Shared)
254  qiLogInfo() << "Object will *not* track original shared pointer";
255  set(storage, *source);
256  }
257  else
258  throw std::runtime_error((std::string)"Cannot assign non-object " + source.type()->infoString() + " to Object");
259  }
260 
261  using Methods = DefaultTypeImplMethods<detail::ManagedObjectPtr, TypeByPointerPOD<detail::ManagedObjectPtr>>;
262  _QI_BOUNCE_TYPE_METHODS(Methods);
263 };
264 
265 }
266 
267 #ifdef _MSC_VER
268 # pragma warning( pop )
269 #endif
270 
271 #endif
qi::Future< R > async(const std::string &methodName, Args &&...args)
#define QI_API
Definition: api.hpp:33
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:45
int propertyId(const std::string &name) const
static AnyValue from(const T &r)
Definition: anyvalue.hpp:90
Honor the default behavior.
Definition: typeobject.hpp:23
dll import/export and compiler message
#define qiLogWarning(...)
Log in warning mode.
Definition: log.hpp:101
Future< T > future() const
Get a future linked to this promise. Can be called multiple times.
Definition: future_fwd.hpp:786
boost::shared_ptr< class GenericObject > ManagedObjectPtr
R call(const std::string &methodName, Args &&...args)
Future< R > async(boost::function< R()> callback, uint64_t usDelay)
Definition: eventloop.hpp:186
Force a synchronous call.
Definition: typeobject.hpp:25
#define qiLogInfo(...)
Log in info mode.
Definition: log.hpp:90
#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)
ObjectTypeInterface * type
qi::FutureSync< T > property(const std::string &name)
MetaCallType
Definition: typeobject.hpp:21
const MetaObject & metaObject()
static AnyFunction from(F &&func)
static AnyReference from(const T &ref)
qi::uint64_t SignalLink
Definition: signal.hpp:35
qi::Future< AnyReference > metaCall(unsigned int method, const GenericFunctionParameters &params, MetaCallType callType=MetaCallType_Auto, Signature returnSignature=Signature())
Force an asynchronous call in an other thread.
Definition: typeobject.hpp:27
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Definition: trackable.hxx:327
Description of the signals and methods accessible on an ObjectTypeInterface.
Definition: metaobject.hpp:25
void adaptFutureUnwrap(Future< AnyReference > &f, Promise< R > &p)
Feed a promise from a generic future which may be unwrapped if it contains itself a future...
Definition: future.hxx:663