My Project
object.h
1 /*************************************************************************\
2 * Copyright (c) 2011 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * Copyright (c) 2015 Paul Scherrer Institute (PSI), Villigen, Switzerland
5 * mrfioc2 is distributed subject to a Software License Agreement found
6 * in file LICENSE that is included with this distribution.
7 \*************************************************************************/
40 #ifndef MRFOBJECT_H
41 #define MRFOBJECT_H
42 
43 #ifdef _MSC_VER
44 /*
45  * The warnings C4251 and C4275 happen because all objects have a DLL
46  * interface when compiled on VC++ but derive from standard STL objects
47  * that don't have a DLL interface. This can be safely ignored when
48  * deriving from STL objects but not otherwise. See [1] and [2] for
49  * more information.
50  *
51  * [1]: https://msdn.microsoft.com/en-us/library/3tdb471s.aspx
52  * [2]: https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
53  */
54 #pragma warning( disable: 4251 )
55 #pragma warning( disable: 4275 )
56 /*
57  * The warning C4661 is happening due to separate code instantiation
58  * that happens with macros defined in this file (OBJECT_START,
59  * OBJECT_PROP1, OBJECT_PROP2 and OBJECT_END). The objects define
60  * custom instances of generic templates which means that in some code
61  * files where these macros are missing the compiler assumes that
62  * specific instances of functions are missing.
63  */
64 #pragma warning( disable: 4661 )
65 #endif
66 
67 // dmm: the old gcc v2.96 appears to have problems to find the "new" version of <ostream>
68 #if (defined __GNUC__ && __GNUC__ < 3)
69  #include <ostream.h>
70 #else
71  #include <ostream>
72 #endif
73 #include <iostream>
74 #include <sstream>
75 #include <map>
76 #include <set>
77 #include <cstring>
78 #include <string>
79 #include <memory>
80 #include <stdexcept>
81 #include <typeinfo>
82 
83 #include <compilerDependencies.h>
84 #include <epicsThread.h>
85 #include <epicsTypes.h>
86 
87 #ifndef EPICS_UNUSED
88 # define EPICS_UNUSED
89 #endif
90 
91 #include "mrfCommon.h"
92 
93 // when dset should signal alarm w/o printing a message
94 class epicsShareClass alarm_exception : public std::exception
95 {
96  const short sevr, stat;
97 public:
98  explicit alarm_exception(short sevr = INVALID_ALARM, short stat = COMM_ALARM) : sevr(sevr), stat(stat) {}
99  virtual ~alarm_exception() throw() {}
100  virtual const char *what() throw();
101  inline short severity() const { return sevr; }
102  inline short status() const { return stat; }
103 };
104 
105 namespace mrf {
106 
108 class epicsShareClass opNotImplemented : public std::runtime_error
109 {
110 public:
111  explicit opNotImplemented(const std::string& m) : std::runtime_error(m) {}
112 };
113 
120 struct epicsShareClass propertyBase
121 {
122  virtual ~propertyBase()=0;
123  virtual const char* name() const=0;
124  virtual const std::type_info& type() const=0;
126  virtual void show(std::ostream&) const;
127 };
128 
129 static inline
130 bool operator==(const propertyBase& a, const propertyBase& b)
131 {
132  return a.type()==b.type() && strcmp(a.name(),b.name())==0;
133 }
134 static inline
135 bool operator!=(const propertyBase& a, const propertyBase& b)
136 { return !(a==b); }
137 
139 template<typename P>
140 struct property : public propertyBase
141 {
142  virtual ~property(){}
144  virtual void set(P)=0;
145  virtual P get() const=0;
146 };
147 
149 template<typename P>
150 struct property<P[1]> : public propertyBase
151 {
152  virtual ~property(){}
158  virtual void set(const P* arr, epicsUInt32 L)=0;
165  virtual epicsUInt32 get(P*, epicsUInt32) const=0;
166 };
167 
169 template<>
170 struct property<void> : public propertyBase
171 {
172  virtual ~property(){}
173  virtual void exec()=0;
174 };
175 
176 namespace detail {
177 
183 template<class C>
185 {
186  virtual ~unboundPropertyBase(){};
187  virtual const std::type_info& type() const=0;
188 
190  virtual propertyBase* bind(C*)=0;
191 };
192 
194 template<class C, typename P>
195 class epicsShareClass unboundProperty : public unboundPropertyBase<C>
196 {
197 public:
198  typedef void (C::*setter_t)(P);
199  typedef P (C::*getter_t)() const;
200 
201  const char * const name;
202  getter_t const getter;
203  setter_t const setter;
204 
205  unboundProperty(const char* n, getter_t g, setter_t s)
206  :name(n), getter(g), setter(s) {}
207 
208  virtual const std::type_info& type() const{return typeid(P);}
209  inline virtual property<P>* bind(C*);
210 };
211 
212 template<class C, typename P>
213 static inline
215 makeUnboundProperty(const char* n, P (C::*g)() const, void (C::*s)(P)=0)
216 {
217  return new unboundProperty<C,P>(n,g,s);
218 }
219 
221 template<class C, typename P>
222 class epicsShareClass unboundProperty<C,P[1]> : public unboundPropertyBase<C>
223 {
224 public:
225  typedef void (C::*setter_t)(const P*, epicsUInt32);
226  typedef epicsUInt32 (C::*getter_t)(P*, epicsUInt32) const;
227 
228  const char * const name;
229  getter_t const getter;
230  setter_t const setter;
231 
232  unboundProperty(const char* n, getter_t g, setter_t s)
233  :name(n), getter(g), setter(s) {}
234 
235  virtual const std::type_info& type() const{return typeid(P[1]);}
236  inline virtual property<P[1]>* bind(C*);
237 };
238 
239 template<class C, typename P>
240 static inline
242 makeUnboundProperty(const char* n,
243  epicsUInt32 (C::*g)(P*, epicsUInt32) const,
244  void (C::*s)(const P*, epicsUInt32)=0)
245 {
246  return new unboundProperty<C,P[1]>(n,g,s);
247 }
248 
250 template<class C>
251 class epicsShareClass unboundProperty<C,void> : public unboundPropertyBase<C>
252 {
253 public:
254  typedef void (C::*exec_t)();
255 
256  const char * const name;
257  exec_t const execer;
258 
259  unboundProperty(const char *n, exec_t e) :name(n), execer(e) {}
260  virtual const std::type_info& type() const{return typeid(void);}
261  inline virtual property<void>* bind(C*);
262 };
263 
264 template<class C>
265 static inline
267 makeUnboundProperty(const char* n,
268  void (C::*e)())
269 {
270  return new unboundProperty<C,void>(n,e);
271 }
272 
274 template<class C, typename P>
275 class epicsShareClass propertyInstance : public property<P>
276 {
277  C *inst;
279 public:
280 
281  propertyInstance(C* c, const unboundProperty<C,P>& p)
282  :inst(c)
283  ,prop(p)
284  {}
285  virtual ~propertyInstance() {}
286 
287  virtual const char* name() const{return prop.name;}
288  virtual const std::type_info& type() const{return prop.type();}
289  virtual void set(P v)
290  {
291  if(!prop.setter)
292  throw opNotImplemented("void set(T) not implemented");
293  (inst->*(prop.setter))(v);
294  }
295  virtual P get() const{
296  if(!prop.getter)
297  throw opNotImplemented("T get() not implemented");
298  return (inst->*(prop.getter))();
299  }
300  virtual void show(std::ostream& strm) const
301  {
302  strm<<get();
303  }
304 };
305 
307 template<class C, typename P>
310 {
311  return new propertyInstance<C,P>(inst,*this);
312 }
313 
315 template<class C, typename P>
316 class epicsShareClass propertyInstance<C,P[1]> : public property<P[1]>
317 {
318  C *inst;
320 public:
321 
322  propertyInstance(C* c, const unboundProperty<C,P[1]>& p)
323  :inst(c)
324  ,prop(p)
325  {}
326  virtual ~propertyInstance() {}
327 
328  virtual const char* name() const{return prop.name;}
329  virtual const std::type_info& type() const{return prop.type();}
330  virtual void set(const P* a, epicsUInt32 l)
331  { (inst->*(prop.setter))(a,l); }
332  virtual epicsUInt32 get(P* a, epicsUInt32 l) const
333  { return (inst->*(prop.getter))(a,l); }
334 };
335 
337 template<class C, typename P>
340 {
341  return new propertyInstance<C,P[1]>(inst,*this);
342 }
343 
344 template<class C>
345 class epicsShareClass propertyInstance<C,void> : public property<void>
346 {
347  C *inst;
349 public:
350 
352  :inst(c), prop(p) {}
353  virtual ~propertyInstance() {}
354 
355  virtual const char* name() const{return prop.name;}
356  virtual const std::type_info& type() const{return prop.type();}
357  virtual void exec() {
358  (inst->*prop.execer)();
359  }
360 };
361 
363 template<class C>
364 property<void>*
366 {
367  return new propertyInstance<C,void>(inst,*this);
368 }
369 
370 } // namespace detail
371 
378 class epicsShareClass Object
379 {
380 public:
381  struct _compName {
382  bool operator()(const Object* a, const Object* b) const{return a->name()<b->name();}
383  };
384 private:
385  const std::string m_obj_name;
386  const Object * const m_obj_parent;
387  typedef std::set<Object*,_compName> m_obj_children_t;
388  mutable m_obj_children_t m_obj_children;
389 protected:
390  Object(const std::string& n, const Object *par=0);
391  virtual ~Object()=0;
392 public:
393  const std::string& name() const{return m_obj_name;}
394  const Object* parent() const{return m_obj_parent;}
395 
396  virtual void lock() const =0;
397  virtual void unlock() const =0;
398 
399  typedef m_obj_children_t::const_iterator child_iterator;
400  child_iterator beginChild() const{return m_obj_children.begin();}
401  child_iterator endChild() const{return m_obj_children.end();}
402 
403  virtual propertyBase* getPropertyBase(const char*, const std::type_info&)=0;
404  template<typename P>
405  mrf::auto_ptr<property<P> > getProperty(const char* pname)
406  {
407  propertyBase *b=getPropertyBase(pname, typeid(P));
408  if(!b)
409  return mrf::auto_ptr<property<P> >();
410  property<P> *p=dynamic_cast<property<P> *>(b);
411  if(!p)
412  return mrf::auto_ptr<property<P> >();
413  return mrf::auto_ptr<property<P> >(p);
414  }
415 
416  virtual void visitProperties(bool (*)(propertyBase*, void*), void*)=0;
417 
420  static Object* getObject(const std::string& name);
421 
422  typedef std::map<std::string, std::string> create_args_t;
423 
426  static Object* getCreateObject(const std::string& name, const std::string& klass, const create_args_t& args = create_args_t());
427 
428  typedef Object* (*create_factory_t)(const std::string& name, const std::string& klass, const create_args_t& args);
429 
430  static void addFactory(const std::string& klass, create_factory_t fn);
431 
432  static void visitObjects(bool (*)(Object*, void*), void*);
433 };
434 
458 template<class C, typename Base = Object>
459 class epicsShareClass ObjectInst : public Base
460 {
461  typedef std::multimap<std::string, detail::unboundPropertyBase<C>*> m_props_t;
462  static m_props_t *m_props;
463 public:
464  static int initObject();
465 protected:
466  explicit ObjectInst(const std::string& n) : Base(n) {}
467  template<typename A>
468  ObjectInst(const std::string& n, A& a) : Base(n, a) {}
469  virtual ~ObjectInst(){}
470 public:
471 
472  virtual propertyBase* getPropertyBase(const char* pname, const std::type_info& ptype)
473  {
474  std::string emsg;
475  if(!m_props)
476  throw std::runtime_error(emsg);
477  typename m_props_t::const_iterator it=m_props->lower_bound(pname),
478  end=m_props->upper_bound(pname);
479  for(;it!=end;++it) {
480  if(it->second->type()==ptype)
481  return it->second->bind(static_cast<C*>(this));
482  }
483  // continue checking for Base class properties
484  return Base::getPropertyBase(pname, ptype);
485  }
486 
487  virtual void visitProperties(bool (*cb)(propertyBase*, void*), void* arg)
488  {
489  std::string emsg;
490  if(!m_props)
491  throw std::runtime_error(emsg);
492 
493  mrf::auto_ptr<propertyBase> cur;
494  for(typename m_props_t::const_iterator it=m_props->begin();
495  it!=m_props->end(); ++it)
496  {
497  cur.reset(it->second->bind(static_cast<C*>(this)));
498  if(!cur.get())
499  continue;
500  if(!(*cb)(cur.get(), arg))
501  break;
502  }
503  Base::visitProperties(cb, arg);
504  }
505 };
506 
507 #define OBJECT_BEGIN2(klass, Base) namespace mrf {\
508 template<> ObjectInst<klass, Base>::m_props_t* ObjectInst<klass, Base>::m_props = 0; \
509 template<> int ObjectInst<klass, Base>::initObject() { \
510  const char *klassname = #klass; (void)klassname; \
511  try { mrf::auto_ptr<m_props_t> props(new m_props_t); {
512 
513 #define OBJECT_BEGIN(klass) OBJECT_BEGIN2(klass, Object)
514 
515 #define OBJECT_PROP1(NAME, GET) \
516  props->insert(std::make_pair(static_cast<const char*>(NAME), detail::makeUnboundProperty(NAME, GET) ))
517 
518 #define OBJECT_PROP2(NAME, GET, SET) \
519  props->insert(std::make_pair(static_cast<const char*>(NAME), detail::makeUnboundProperty(NAME, GET, SET) ))
520 
521 #define OBJECT_FACTORY(FN) addFactory(klassname, FN)
522 
523 #define OBJECT_END(klass) \
524 } m_props = props.release(); return 1; \
525 } catch(std::exception& e) { \
526 std::cerr<<"Failed to build property table for "<<typeid(klass).name()<<"\n"<<e.what()<<"\n"; \
527 throw std::runtime_error("Failed to build"); \
528  }}} \
529 static int done_##klass EPICS_UNUSED = klass::initObject();
530 
531 } // namespace mrf
532 
533 #endif // MRFOBJECT_H
User implementation hook.
Definition: object.h:460
Base object inspection.
Definition: object.h:379
final array implementation
Definition: object.h:317
final scalar implementation
Definition: object.h:276
virtual void show(std::ostream &strm) const
Print the value of the field w/o leading or trailing whitespace.
Definition: object.h:300
virtual void set(P v)
The setter for this property.
Definition: object.h:289
An un-bound, typed array property.
Definition: object.h:223
An un-bound momentary/command.
Definition: object.h:252
An un-bound, typed scalar property.
Definition: object.h:196
virtual property< P > * bind(C *)
Binder for scalar instances.
Definition: object.h:309
Requested operation is not implemented by the property.
Definition: object.h:109
An un-typed, un-bound property for class C.
Definition: object.h:185
virtual propertyBase * bind(C *)=0
Create a bound property with the given instance.
An un-typed property.
Definition: object.h:121
A bound, typed array property.
Definition: object.h:151
A momentary/command.
Definition: object.h:171
A bound, typed scalar property.
Definition: object.h:141
virtual void set(P)=0
The setter for this property.