TCL_obj_base.h
Go to the documentation of this file.
1 /*
2  @copyright Russell Standish 2000-2013
3  @author Russell Standish
4  This file is part of EcoLab
5 
6  Open source licensed under the MIT license. See LICENSE for details.
7 */
8 
9 /* a series of TCL commands for accessing members of a C++
10 object. Accessed by the macro make_model(x), where x is the
11 name of a C++ object.
12 
13 */
18 #ifndef TCL_OBJ_BASE_H
19 #define TCL_OBJ_BASE_H
20 #include "tcl++.h"
21 #include "pack_base.h"
22 #include "pack_stl.h"
23 #include "ref.h"
24 #include "error.h"
25 #include "accessor.h"
26 
27 #include "isa_base.h"
28 #include "function.h"
29 #include <iostream>
30 #include <sstream>
31 
32 /* define this macro to x to track TCL_obj registrations */
33 #define TCL_OBJ_DBG(x)
34 
35 // ensure TCL_obj_templates is included, or linktime failure
36 namespace
37 {
38  int TCL_obj_template_not_included();
39  int dummyXXX=TCL_obj_template_not_included();
40 }
41 
42 namespace ecolab
43 {
44  using namespace classdesc;
47  using functional::Return;
48  /* classes for wrapping C++ functions, suitable for passing to
49  Tcl_CreateCommand */
50 
51  template <class T>
52  void ensure_exists(T*& x)
53  {if (x==NULL) x=new T;}
54 
55  /* utility macro for declaring references to objects referred to in TCL
56  arguments */
57 
58 #define declare(name, typename, tcl_name) \
59  typename *name##_entry; \
60  if (TCL_obj_properties().count(const_cast<char*>(tcl_name))==0) \
61  throw error("%s does not exist!",tcl_name); \
62  name##_entry=TCL_obj_properties()[tcl_name]->memberPtrCasted<typename>(); \
63  if (!name##_entry) \
64  throw error("Incorrect argument %s assigned to %s",tcl_name,#name); \
65  typename& name=*name##_entry;
66 
67  int TCL_proc(ClientData cd, Tcl_Interp *interp, int argc, CONST84 char **argv);
68  int TCL_oproc(ClientData cd, Tcl_Interp *interp, int argc,
69  Tcl_Obj *const argv[]);
70  void TCL_delete(ClientData cd);
71 
72  inline void TCL_cmd_data_delete(ClientData cd)
73  {
74  delete static_cast<cmd_data*>(cd);
75  }
76 
77  /* TCL_args - support for TCL object types:
78  Use >> notation to extract arguments */
79 
80 #if (TCL_MAJOR_VERSION<8)
81 #error TCL 8.x or greater supported. Please upgrade your TCL
82 #endif
83 
84  /* used for testing whether simple or compound type */
85 
86 #ifdef _CLASSDESC
87 #pragma omit pack ecolab::TCL_args
88 #pragma omit unpack ecolab::TCL_args
89 #pragma omit TCL_obj ecolab::TCL_args
90 #endif
91 
93  class TCLObjRef
94  {
95  Tcl_Obj* ref;
96  public:
97  TCLObjRef(): ref(Tcl_NewStringObj("",0)) {Tcl_IncrRefCount(ref);}
98  TCLObjRef(Tcl_Obj* x): ref(x) {Tcl_IncrRefCount(x);}
99  ~TCLObjRef() {Tcl_DecrRefCount(ref);}
100  TCLObjRef(const TCLObjRef& x): ref(x.ref) {Tcl_IncrRefCount(ref);}
101  TCLObjRef& operator=(const TCLObjRef& x) {
102  ref=x.ref;
103  Tcl_IncrRefCount(ref);
104  return *this;
105  }
106  Tcl_Obj* get() const {return ref;}
107  };
108 
109 
138  class TCL_args
139  {
140  int nextArg;
141  int m_count;
142  std::vector<TCLObjRef> argv;
143  Tcl_Obj * pop_arg()
144  {
145  if (m_count>0)
146  {m_count--; return argv[nextArg++].get();}
147  else
148  throw error("too few arguments");
149  }
151 
152  public:
153  const int& count;
154  TCL_args(): nextArg(1), m_count(0), argv(1), count(m_count) {}
155  TCL_args(int a, Tcl_Obj *const *v): nextArg(1), m_count(a), count(m_count)
156  {
157  m_count--;
158  for (int i=0; i<a; ++i)
159  argv.push_back(v[i]);
160  }
161  TCL_args operator[](int i) const
162  {
163  if (count<=i)
164  throw error("too few arguments");
165  else
166  {
168  r.pushObj(argv[i+nextArg].get());
169  return r;
170  }
171  }
172 
173  void pushObj(Tcl_Obj* obj) {argv.push_back(obj); m_count++;}
174  const char* str();
175 
176  TCL_args& operator<<(const std::string& x)
177  {pushObj(Tcl_NewStringObj(x.c_str(),-1)); return *this;}
178  TCL_args& operator<<(const char* x)
179  {pushObj(Tcl_NewStringObj(x,-1)); return *this;}
180  TCL_args& operator<<(bool x) {pushObj(Tcl_NewBooleanObj(x)); return *this;}
181  TCL_args& operator<<(int x) {pushObj(Tcl_NewIntObj(x)); return *this;}
182  TCL_args& operator<<(unsigned x) {pushObj(Tcl_NewIntObj(x)); return *this;}
183  TCL_args& operator<<(long x) {pushObj(Tcl_NewLongObj(x)); return *this;}
184  TCL_args& operator<<(double x) {pushObj(Tcl_NewDoubleObj(x)); return *this;}
185 
186 
187  TCL_args& operator>>(std::string& x) {x=str(); return *this;}
188  TCL_args& operator>>(const char*& x) {x=str(); return *this;}
189  TCL_args& operator>>(bool& x) {
190  int tmp;
191  if (Tcl_GetBooleanFromObj(interp(),pop_arg(),&tmp)!=TCL_OK)
192  throw error("argument error");
193  x=tmp;
194  return *this;
195  }
196  TCL_args& operator>>(int& x) {
197  if (Tcl_GetIntFromObj(interp(),pop_arg(),&x)!=TCL_OK)
198  throw error("argument error");
199  return *this;
200  }
201  TCL_args& operator>>(unsigned& x) {
202  int tmp;
203  if (Tcl_GetIntFromObj(interp(),pop_arg(),&tmp)!=TCL_OK)
204  throw error("argument error");
205  if (tmp>=0) x=tmp;
206  else throw error("assigning %d to an unsigned variable",tmp);
207  return *this;
208  }
209  TCL_args& operator>>(long& x) {
210  if (Tcl_GetLongFromObj(interp(),pop_arg(),&x)!=TCL_OK)
211  throw error("argument error");
212  return *this;
213  }
214  TCL_args& operator>>(double& x) {
215  if (Tcl_GetDoubleFromObj(interp(),pop_arg(),&x)!=TCL_OK)
216  throw error("argument error");
217  return *this;
218  }
219  // TCL_args& operator>>(float& x) {x=*this; return *this;}
220  template <class T>
221  typename enable_if<is_rvalue<T>, T>::T
222  get(dummy<0> d=0) {T x; *this>>x; return x;}
223 
224  template <class T>
225  typename enable_if<Not<is_rvalue<T> >, T>::T
226  get(dummy<1> d=0)
227  {throw error("calling get on %s", typeName<T>().c_str());}
229  template <class T> operator T() {return get<T>();}
230  };
231 
232  template <class T> TCL_args& operator>>(TCL_args& a, T& x);
233  template <> inline TCL_args& operator>>(TCL_args& a, char*& x) {x=const_cast<char*>(a.str()); return a;}
234  template <> inline TCL_args& operator>>(TCL_args& a, const char*& x) {x=a.str(); return a;}
235 
236 
238  inline void parallel(TCL_args args)
239  {
240 #ifdef MPI_SUPPORT
241  if (myid==0)
242  {
244  s << (char*)args[-1];
245  while (args.count) s << (char*)args;
246  parsend(s.str());
247  }
248 #endif
249  }
252  {
253  virtual void get() {throw error("get() not implemented");}
254  virtual void put(const char *s) {throw error("put not implemented");}
255  void proc(int argc, CONST84 char **argv)
256  {
257  if (argc>1) put(argv[1]);
258  else get();
259  if (hook) {hook(argc,argv);}
260  }
262  virtual void proc(int argc, Tcl_Obj *const argv[]) {
263  cmd_data::proc(argc,argv);
264  if (thook) thook(argc,argv);
265  }
268  void (*hook)(int argc, CONST84 char **argv);
269  void (*thook)(int argc, Tcl_Obj *const argv[]);
270  member_entry_base(): hook(NULL), thook(NULL) {is_setterGetter=true;}
272  // std::type_info does not provide an overload for std::Less, so provide one here
274  {
275  bool operator()(const std::type_info* x, const std::type_info* y) const {
276  return x->before(*y);
277  }
278  };
279 
281  typedef std::map<const std::type_info*,void*,TypeInfoLess> BasePtrs;
282  BasePtrs basePtrs;
284  template <class T> T* memberPtrCasted() const;
285  };
286 #ifdef _CLASSDESC
287 #pragma omit pack ecolab::member_entry_base
288 #pragma omit unpack ecolab::member_entry_base
289 #pragma omit pack TCL_obj_member_entry::member_entry
290 #pragma omit unpack TCL_obj_member_entry::member_entry
291 #pragma omit pack ecolab::member_entry
292 #pragma omit unpack ecolab::member_entry
293 #endif
295 #include <string>
296  // fix shared_ptr type to prevent inconsistency in C++11 build environments
297  // TODO convert to std::shared_ptr once EcoLab is C++11 only
298  typedef std::map<string,classdesc::shared_ptr<member_entry_base> > TCL_obj_hash;
299 
300  TCL_obj_hash& TCL_obj_properties();
301 
302  // erase all object properties starting with \a name
303  inline void eraseAllNamesStartingWith(const string& name)
304  {
305  for (TCL_obj_hash::iterator it=TCL_obj_properties().find(name);
306  it!=TCL_obj_properties().end() && it->first.find(name)!=string::npos;)
307  {
308  TCL_obj_hash::iterator toErase=it++;
309  TCL_obj_properties().erase(toErase);
310  }
311 
312  }
313 
314 
316  {
317  virtual void pack(classdesc::pack_t&)=0;
318  virtual void unpack(classdesc::pack_t&)=0;
319  virtual ~TCL_obj_checkr_base() {}
320  };
321 
322 } // namespace ecolab
323 
324 namespace classdesc
325 {
327  struct TCL_obj_t
328  {
329  ecolab::TCL_obj_checkr_base *check_functor;
331  bool xdr_check;
333  typedef void (*Member_entry_hook)(int argc, CONST84 char **argv);
334  Exclude<Member_entry_hook> member_entry_hook;
335  typedef void (*Member_entry_thook)(int argc, Tcl_Obj *const argv[]);
336  Exclude<Member_entry_thook> member_entry_thook;
337 
339  void checkpoint(int argc, char *argv[]);
341  void restart(int argc, char *argv[]);
343  void get_vars(int argc, char *argv[]);
345  void data_server(int argc, char *argv[]);
346  TCL_obj_t(): xdr_check(false), member_entry_hook((Member_entry_hook)NULL),
347  member_entry_thook((Member_entry_thook)NULL){}
348  };
349 }
350 
351 #ifdef _CLASSDESC
352 #pragma omit pack classdesc::TCL_obj_t
353 #pragma omit unpack classdesc::TCL_obj_t
354 #endif
355 
357 {
358  template <> struct access_pack<classdesc::TCL_obj_t>:
359  public classdesc::NullDescriptor<classdesc::pack_t> {};
360  template <> struct access_unpack<classdesc::TCL_obj_t>:
361  public classdesc::NullDescriptor<classdesc::unpack_t> {};
362 
364  template <class T> struct access_TCL_obj
365  {
366  /* by default, do nothing (unstructured types are just registered in TCL_obj()) */
367  template <class U>
368  void operator()(classdesc::TCL_obj_t& t,const classdesc::string& desc, U& arg) {}
369  };
371  // const type version
372  template <class T> struct access_TCL_obj<const T>
373  {
374  /* by default, do nothing (unstructured types are just registered in TCL_obj()) */
375  void operator()(classdesc::TCL_obj_t& t,const classdesc::string& desc,
376  const T& arg)
377  {
378  access_TCL_obj<T>()(t,desc,arg);
379  }
380  };
381 }
382 
383 namespace ecolab
384 {
385 
388 
389  using classdesc::TCL_obj_t;
390  using classdesc::pack;
392  using classdesc::string;
393 
394  template <class T> void TCL_obj(TCL_obj_t&, const string&, T&);
395  template <class T> void TCL_obj_onbase(TCL_obj_t&, const string&, T&);
396 
397 #include "ref.h"
400  template <class T>
401  struct ref: public classdesc::ref<T>
402  {
403  classdesc::string name;
404  T& operator*() {
405  if (this->nullref()) {
406  TCL_obj(null_TCL_obj,name,classdesc::ref<T>::operator*());
407  }
409  }
410  const T& operator*() const {return classdesc::ref<T>::operator*();}
411  T* operator->() {return &operator*();}
412  const T* operator->() const {return &operator*();}
413  ref() {}
414  ref(const ref& x): classdesc::ref<T>(static_cast<const classdesc::ref<T>&>(x)) {}
415  template <class U> ref(const U& x): classdesc::ref<T>(x) {}
416  ref& operator=(const ref& x) {
417  classdesc::ref<T>::operator=(static_cast<const classdesc::ref<T>&>(x));
418  eraseAllNamesStartingWith(name);
419  TCL_obj(null_TCL_obj,name,**this);
420  return *this;
421  }
422  template <class U> ref& operator=(const U& x) {
424  eraseAllNamesStartingWith(name);
425  TCL_obj(null_TCL_obj,name,**this);
426  return *this;
427  }
428  void swap(ref& x) {
430  eraseAllNamesStartingWith(name);
431  TCL_obj(null_TCL_obj,name,**this);
432  eraseAllNamesStartingWith(x->name);
433  TCL_obj(null_TCL_obj,x->name,*x);
434  }
435  template <class U>
436  bool operator==(const U& x) {return classdesc::ref<T>::operator==(x);}
437  template <class U>
438  bool operator!=(const U& x) {return !operator==(x);}
439  };
440 
448  template <class T>
450  {
451  T* datum;
452  std::string name;
453  TCL_obj_ref(T& x, const char* nm): datum(&x), name(nm) {}
454  public:
455  TCL_obj_ref(): datum(NULL) {}
456  TCL_obj_ref(const char* nm): datum(NULL) {set(nm);}
457  T* operator->() {return datum;}
458  T& operator*() {return *datum;}
459  const T* operator->() const {assert(datum); return datum;}
460  const T& operator*() const {assert(datum); return *datum;}
461  operator bool() const {return datum;}
463  void set(const char *s);
464  void pack(classdesc::pack_t& buf);
465  void unpack(classdesc::pack_t& buf);
466  };
468 #ifdef _CLASSDESC
469 #pragma omit pack ecolab::TCL_obj_ref
470 #pragma omit unpack ecolab::TCL_obj_ref
471 #pragma omit TCL_obj ecolab::TCL_obj_ref
472 #pragma omit TCL_obj classdesc::ref
473 #pragma omit TCL_obj ecolab::ref
474 #endif
475 
476  template <class T> class ref;
478  /* member_entry is defined in its own namespace, as
479  template<class T> void operator<<(ostream& x,const T& y)
480  conflicts with hash_map */
481 
482 
483  // template<class T> inline eco_strstream& operator|(eco_strstream& x,const T& y);
484  template<class T, class CharT, class Traits>
485  typename enable_if<
487  std::basic_istream<CharT,Traits>&>::T
488  operator>>(std::basic_istream<CharT,Traits>& x,T& y);
489 
490  template<class T, class CharT, class Traits>
491  typename enable_if<is_sequence<T>, std::basic_istream<CharT,Traits>&>::T
492  operator>>(std::basic_istream<CharT,Traits>& x,T& y);
493 
494  template<class T, class CharT, class Traits>
495  typename enable_if<is_associative_container<T>, std::basic_istream<CharT,Traits>&>::T
496  operator>>(std::basic_istream<CharT,Traits>& x,T& y);
497 
498  template<class T, class CharT, class Traits>
499  typename enable_if<is_enum<T>, std::basic_istream<CharT,Traits>&>::T
500  operator>>(std::basic_istream<CharT,Traits>& x,T& y);
501 
502  template<class T, class CharT, class Traits>
503  typename enable_if<is_enum<T>, std::basic_istream<CharT,Traits>&>::T
504  operator>>(std::basic_istream<CharT,Traits>& x,T& y);
505 
507  template<class T, class CharT, class Traits>
508  inline std::basic_istream<CharT,Traits>&
509  operator>>(std::basic_istream<CharT,Traits>&, ref<T>& y);
511  template <class T> struct member_entry: public member_entry_base
512  {
513  T *memberptr;
514  member_entry(): memberptr(0) {}
515  member_entry(T& x) {memberptr=&x;}
516  void get();
517  void put(const char *s);
518  };
519 
520  template <class T> T* member_entry_base::memberPtrCasted() const
521  {
522  if (const member_entry<T>* m=dynamic_cast<const member_entry<T>*>(this))
523  return m->memberptr;
524  else
525  {
526  BasePtrs::const_iterator i=basePtrs.find(&typeid(T));
527  if (i!=basePtrs.end())
528  return (T*)(i->second);
529  else
530  return NULL;
531  }
532  }
535  template <class T> struct member_entry<const classdesc::Enum_handle<T> >:
536  public member_entry_base
537  {
538  Enum_handle<T> *memberptr;
539  member_entry(): memberptr(0) {}
540  member_entry(const Enum_handle<T>& x) {memberptr=new Enum_handle<T>(x);}
541  ~member_entry() {delete memberptr;}
542  void get();
543  void put(const char *s);
544  };
546  template <class T> struct member_entry<const classdesc::Enum_handle<const T> >:
547  public member_entry_base
548  {
550  member_entry(): memberptr(0) {}
551  member_entry(const Enum_handle<const T>& x) {memberptr=new Enum_handle<const T>(x);}
552  ~member_entry() {delete memberptr;}
553  void get() {tclreturn()<<string(*memberptr);}
554  void put(const char *s) {throw error("cannot change const attribute");}
555  };
557 
558  template <class T> struct member_entry<const T>: public member_entry_base
559  {
560  const T data; // holds copy of data, in case a temporary is passed
561  const T *memberptr;
562  member_entry(): memberptr(0) {}
563  member_entry(const T& x): data(x), memberptr(&data) {}
564  void get();
565  void put(const char *s) {throw error("cannot change const attribute");}
566  };
567 
568  template <class T>
570  {
571  TCL_obj_ref<T> *memberptr;
572  member_entry(): memberptr(0) {}
573  member_entry(TCL_obj_ref<T>& x) {memberptr=&x;}
574  /* You can assign registered TCL_objs to TCL_obj_ref<T> */
575  void put(const char *s) {memberptr->set(s); tclreturn() << s;}
576  };
577 
578  template <class T>
579  struct member_entry<T*>: public member_entry_base
580  {
581  T **memberptr;
582  member_entry(): memberptr(0) {}
583  member_entry(T*& x) {memberptr=&x;}
584  /* You can assign registered TCL_objs to pointers */
585  void put(const char *s)
586  {
587  if (!memberptr)
588  throw error("missing reference to assign %s to",s);
589  // member_entry<T> *object_entry;
590  /*ensure_exists(TCL_obj_properties());*/
591  if (TCL_obj_properties().count(s)==0)
592  throw error("%s does not exist!",s);
593  if (T *object=TCL_obj_properties()[s]->memberPtrCasted<T>())
594  {
595  *memberptr=object;
596  tclreturn() << s;
597  }
598  else
599  throw error("Incorrect argument type %s",s);
600  }
601  };
602 
603  template <>
604  struct member_entry<void*>: public member_entry_base
605  {
606  void *memberptr;
607  member_entry(): memberptr(0) {}
608  member_entry(void*& x) {memberptr=x;}
609  };
610 
611  template <>
612  struct member_entry<const void*>: public member_entry_base
613  {
614  const void *memberptr;
615  member_entry(): memberptr(0) {}
616  member_entry(const void*& x) {memberptr=x;}
617  };
618 
619  template <>
620  struct member_entry<void>: public member_entry_base
621  {
622  void *memberptr;
623  member_entry(): memberptr(0) {}
624  member_entry(void*& x) {memberptr=x;}
625  };
626 
628  template <class T>
629  void TCL_obj_ref<T>::set(const char *s) {
630  if (TCL_obj_properties().count(s)==0)
631  throw error("%s does not exist!",s);
632  if (T* object= TCL_obj_properties()[s]->memberPtrCasted<T>())
633  {
634  datum=object;
635  name=s;
636  }
637  else
638  throw error("Incorrect argument type %s",s);
639  }
640 
641  template <class T>
642  void TCL_obj_register(const TCL_obj_t& targ, const string& desc, T& arg,
643  bool base=false)
644  {
645  TCL_obj_hash::iterator it=TCL_obj_properties().find(desc);
646  if (!base || it==TCL_obj_properties().end())
647  {
648  member_entry<T> *m=new member_entry<T>(arg);
649  m->hook=targ.member_entry_hook;
650  m->thook=targ.member_entry_thook;
651  m->name=desc;
652  TCL_OBJ_DBG(printf("registering %s, with entry %x\n",desc.c_str(),m));
653  // assert(TCL_newcommand(desc)); /* we just want the latest resgistration */
654  Tcl_CreateCommand(interp(),desc.c_str(),(Tcl_CmdProc*)TCL_proc,(ClientData)m,TCL_delete);
655  TCL_obj_properties()[desc].reset(m);
656  }
657  else // registering a base class
658  {
659  assert(it->second);
660  // this is presumably a base class registration
661  it->second->basePtrs[&typeid(T)]=(void*)&arg;
662  }
663  }
664 
665  void TCL_obj_deregister(const string& desc );
666 
668  template <class T> void TCL_obj_custom_register(const string& desc, T& arg) {}
669 
670 
671  template <class T>
672  void TCL_obj(TCL_obj_t& targ, const string& desc, classdesc::is_array ia,
673  T &arg,int dims,...);
674 
675  template <class T>
676  void TCL_obj(TCL_obj_t& targ, const string& desc, classdesc::is_const_static s, const T& t)
677  {
678  TCL_obj(targ, desc, t);
679  }
680 
682  template <class T, class U>
683  void TCL_obj(TCL_obj_t& targ, const string& desc, classdesc::is_const_static s, const T& t, U u)
684  {
685  TCL_obj(targ, desc, u);
686  }
687 
688  /* deal with treenode pointers */
689  template <class T>
690  void TCL_obj(TCL_obj_t& targ, const string& desc, classdesc::is_treenode dum, T& arg);
691 
692  template <class T>
693  void TCL_obj(TCL_obj_t& targ, const string& desc, classdesc::is_graphnode dum, T& arg);
694 
695 #ifdef _CLASSDESC
696 #pragma omit pack ecolab::TCL_obj_functor
697 #pragma omit unpack ecolab::TCL_obj_functor
698 #pragma omit TCL_obj ecolab::TCL_obj_functor
699 #pragma omit isa ecolab::TCL_obj_functor
700 #endif
701  template<class C, class T>
702  struct TCL_obj_functor: public cmd_data
703  {
704  C *o;
705  functor_class c;
706  union {
707  T (C::*mbrvoid) ();
708  T (C::*mbr)(int,char**);
709  T (C::*mbrobj)(TCL_args);
710  T (*fptr)(...);
711  T (*ofptr)(const TCL_args&);
712  };
713  void (*hook)(int argc, CONST84 char **argv);
714  void (*thook)(int argc, Tcl_Obj *const argv[]);
715 
716  TCL_obj_functor(): hook(NULL), thook(NULL) {c=invalid;}
717  void init(C& oo, T (C::*m) ()) {o=&oo; mbrvoid=m; c=memvoid;}
718  void init(C& oo, T (C::*m) (int,char**)) {o=&oo; mbr=m; c=mem;}
719  void init(C& oo, T (C::*m) (TCL_args)) {o=&oo; mbrobj=m; c=mem;}
720  void init(C& oo, T (*f) (...)) {o=&oo; fptr=f; c=func;}
721  void init(C& oo, T (*f) (const TCL_args&)) {o=&oo; ofptr=f; c=func;}
722  void proc(int argc, CONST84 char **argv)
723  {
724  tclreturn r;
725  switch (c)
726  {
727  case memvoid: r<<(o->*mbrvoid)(); break;
728  case mem: r<<(o->*mbr)(argc,const_cast<char**>(argv)); break;
729  case func: r<<fptr(argc,const_cast<char**>(argv)); break;
730  case nonconst: throw error("non const method called on const object");
731  default: break;
732  }
733  if (hook) hook(argc, argv);
734  }
735  void proc(int argc, Tcl_Obj *const argv[])
736  {
737  tclreturn r;
738  switch (c)
739  {
740  case mem: r<<(o->*mbrobj)(TCL_args(argc,argv)); break;
741  case func: r<<ofptr(TCL_args(argc,argv)); break;
742  case nonconst: throw error("non const method called on const object");
743  default: break;
744  }
745  if (thook) thook(argc, argv);
746  }
747  };
748 
749  template<class C, class T>
750  struct TCL_obj_functor<const C,T>: public cmd_data
751  {
752  const C *o;
753  functor_class c;
754  union {
755  T (C::*mbrvoid) () const;
756  T (C::*mbr)(int,char**) const;
757  T (C::*mbrobj)(TCL_args) const;
758  T (*fptr)(...);
759  T (*ofptr)(const TCL_args&);
760  };
761  void (*hook)(int argc, CONST84 char **argv);
762  void (*thook)(int argc, Tcl_Obj *const argv[]);
764  TCL_obj_functor(): hook(NULL), thook(NULL) {c=invalid;}
765  void init(const C& oo, T (C::*m) () const) {o=&oo; mbrvoid=m; c=memvoid;}
766  void init(const C& oo, T (C::*m) (int,char**) const) {o=&oo; mbr=m; c=mem;}
767  void init(const C& oo, T (C::*m) (TCL_args) const ) {o=&oo; mbrobj=m; c=mem;}
768  void init(const C& oo, T (C::*m) ()) {o=&oo; c=nonconst;}
769  void init(const C& oo, T (C::*m) (int,char**)) {o=&oo; c=nonconst;}
770  void init(const C& oo, T (C::*m) (TCL_args)) {o=&oo; c=nonconst;}
771  void init(const C& oo, T (*f) (...)) {o=&oo; fptr=f; c=func;}
772  void init(const C& oo, T (*f) (const TCL_args&)) {o=&oo; ofptr=f; c=func;}
773  void proc(int argc, CONST84 char **argv)
774  {
775  tclreturn r;
776  switch (c)
777  {
778  case memvoid: r<<(o->*mbrvoid)(); break;
779  case mem: r<<(o->*mbr)(argc,const_cast<char**>(argv)); break;
780  case func: r<<fptr(argc,const_cast<char**>(argv)); break;
781  }
782  if (hook) hook(argc, argv);
783  }
784  void proc(int argc, Tcl_Obj *const argv[])
785  {
787  switch (c)
788  {
789  case mem: r<<(o->*mbrobj)(TCL_args(argc,argv)); break;
790  case func: r<<ofptr(TCL_args(argc,argv)); break;
791  }
792  if (thook) thook(argc, argv);
793  }
794  };
796 
797 
798  template<class C>
799  struct TCL_obj_functor<C,void>: public cmd_data
800  {
801  C *o;
802  functor_class c;
803  union {
804  void (C::*mbrvoid) ();
805  void (C::*mbr)(int,char**);
806  void (C::*mbrobj)(TCL_args);
807  void (*fptr)(...);
808  void (*ofptr)(const TCL_args&);
809  };
810  void (*hook)(int argc, CONST84 char **argv);
811  void (*thook)(int argc, Tcl_Obj *const argv[]);
812 
813  TCL_obj_functor(): hook(NULL), thook(NULL) {c=invalid;}
814  void init(C& oo, void (C::*m) ()) {o=&oo; mbrvoid=m; c=memvoid;}
815  void init(C& oo, void (C::*m) (int,char**)) {o=&oo; mbr=m; c=mem;}
816  void init(C& oo, void (C::*m) (TCL_args)) {o=&oo; mbrobj=m; c=mem;}
817  void init(C& oo, void (*f) (...)) {o=&oo; fptr=f; c=func;}
818  void init(C& oo, void (*f) (const TCL_args&)) {o=&oo; ofptr=f; c=func;}
819  void proc(int argc, CONST84 char **argv)
820  {
821  switch (c)
822  {
823  case memvoid: (o->*mbrvoid)(); break;
824  case mem: (o->*mbr)(argc,const_cast<char**>(argv)); break;
825  case func: fptr(argc,const_cast<char**>(argv)); break;
826  default: break;
827  }
828  if (hook) hook(argc, argv);
829  }
830  void proc(int argc, Tcl_Obj *const argv[])
831  {
832  switch (c)
833  {
834  case mem: (o->*mbrobj)(TCL_args(argc,argv)); break;
835  case func: ofptr(TCL_args(argc,argv)); break;
836  default: break;
837  }
838  if (thook) thook(argc, argv);
839  }
840  };
841 
843  template <class B> struct BoundMethodCallable: public false_type {};
844 
845  template <class C, class M>
846  struct BoundMethodCallable<functional::bound_method<C,M> >: public
847  And<Or<Not<is_const<C> >, functional::is_const_method<M> >,
848  functional::AllArgs<functional::bound_method<C,M>, is_rvalue> > {};
849 
850 #ifdef _CLASSDESC
851 #pragma omit pack ecolab::BoundMethodCallable
852 #pragma omit unpack ecolab::BoundMethodCallable
853 #pragma omit TCL_obj ecolab::BoundMethodCallable
854 #pragma omit isa ecolab::BoundMethodCallable
855 #endif
856 
857  // for methods returning a value
858  template <class B, class A>
859  typename enable_if
861  newTCL_obj_functor_proc(B bm, A args, dummy<0> x=0)
862  {
863  tclreturn() << functional::apply_nonvoid_fn(bm, args);
864  }
865 
866  // for ones that don't
867  template <class B, class A>
868  typename enable_if
869  <And<is_void<typename Return<B>::T>, BoundMethodCallable<B> >,void>::T
870  newTCL_obj_functor_proc(B bm, A args, dummy<1> x=0)
871  {
872  functional::apply_void_fn(bm, args);
873  }
874 
875  // and ones that have lvalue arguments, or are not const-correctly callable
876  template <class B, class A>
877  typename enable_if<Not<BoundMethodCallable<B> >, void>::T
878  newTCL_obj_functor_proc(B bm, A args, dummy<2> x=0)
879  {
880  throw error("cannot call %s",args[-1].str());
881  }
883  /* what to do about member functions */
884  template <class C, class M>
886  {
888  TCL_obj_t::Member_entry_thook thook;
889  public:
890  NewTCL_obj_functor(const TCL_obj_t& targ,C& obj, M member):
891  bm(obj, member), thook(targ.member_entry_thook) {
893  is_const=true;
894  }
895  void proc(int argc, Tcl_Obj *const argv[]) {
896  newTCL_obj_functor_proc(bm, TCL_args(argc, argv));
897  if (thook) thook(argc, argv);
898  }
899  void proc(int, const char **) {}
900  };
901 
902  template<class C, class M>
903  typename enable_if<is_member_function_pointer<M>, void>::T
904  TCL_obj(TCL_obj_t& targ, const string& desc, C& c, M m)
905  {
907  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()));
908  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
909  }
910 
911  // static methods
912  template <class F>
914  {
915  F f;
916  TCL_obj_t::Member_entry_thook thook;
917  public:
918  NewTCL_static_functor(const TCL_obj_t& targ,F f):
919  f(f), thook(targ.member_entry_thook) {is_const=true;}
920  void proc(int argc, Tcl_Obj *const argv[]) {
921  newTCL_obj_functor_proc(f, TCL_args(argc, argv));
922  if (thook) thook(argc, argv);
923  }
924  void proc(int, const char **) {}
925  };
927  template<class C, class M>
929  TCL_obj(TCL_obj_t& targ, const string& desc, C& c, M m)
930  {
932  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()));
933  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
934  }
935 
941  template<class C, class T>
942  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
943  T (C::*arg)(int,const char**))
944  {
946  t->init(obj,arg); t->name=desc;
947  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
948  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
949  Tcl_CreateCommand(interp(),desc.c_str(),(Tcl_CmdProc*)TCL_proc,(ClientData)t,TCL_cmd_data_delete);
950  }
951 
952  template<class C, class T>
953  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
954  T (C::*arg)(int,const char**) const)
955  {
956  typedef T (C::*mptr)(int,const char**);
957  TCL_obj(targ,desc,obj,(mptr)arg);
958  TCL_obj_properties()[desc]->is_const=true;
959  }
960 
961  template<class C, class T>
962  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
963  T (C::*arg)(int,char**))
964  {
966  t->init(obj,arg); t->name=desc;
967  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
968  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
969  Tcl_CreateCommand(interp(),desc.c_str(),(Tcl_CmdProc*)TCL_proc,(ClientData)t,TCL_cmd_data_delete);
970  }
971 
972  template<class C, class T>
973  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
974  T (C::*arg)(int,char**) const)
975  {
976  typedef T (C::*mptr)(int,char**);
977  TCL_obj(targ,desc,obj,(mptr)arg);
978  TCL_obj_properties()[desc]->is_const=true;
979  }
980 
981  template<class C, class T>
982  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj, T (*arg)(int argc, const char**))
983  {
985  t->init(obj,arg); t->name=desc;
986  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
987  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
988  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
989  }
990 
991  template<class C, class T>
992  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj, T (*arg)(int argc, char**))
993  {
995  t->init(obj,arg); t->name=desc;
996  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
997  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
998  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
999  }
1001  template<class C, class T>
1002  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
1003  T (C::*arg)(TCL_args))
1004  {
1006  t->init(obj,arg); t->name=desc;
1007  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
1008  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
1009  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
1010  }
1011 
1012  template<class C, class T>
1013  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj,
1014  T (C::*arg)(TCL_args) const)
1015  {
1016  typedef T (C::*mptr)(TCL_args);
1017  TCL_obj(targ,desc,obj,(mptr)arg);
1018  TCL_obj_properties()[desc]->is_const=true;
1019  }
1020 
1021  template<class C, class T>
1022  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj, T (*arg)(TCL_args))
1023  {
1025  t->init(obj,arg); t->name=desc;
1026  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
1027  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
1028  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
1029  }
1030 
1031  template<class C, class T>
1032  void TCL_obj(TCL_obj_t& targ, const string& desc, C& obj, T (*arg)(const TCL_args&))
1033  {
1035  t->init(obj,arg); t->name=desc;
1036  t->hook=targ.member_entry_hook; t->thook=targ.member_entry_thook;
1037  TCL_OBJ_DBG(printf("registering %s\n",desc.c_str()););
1038  Tcl_CreateObjCommand(interp(),desc.c_str(),TCL_oproc,(ClientData)t,TCL_cmd_data_delete);
1039  }
1040 
1041 #ifdef _CLASSDESC
1042 #pragma omit TCL_obj string
1043 #pragma omit TCL_obj eco_strstream
1045  /* these classes cause problems because they don't have copy constructors */
1046 #pragma omit TCL_obj ostream
1047 #pragma omit TCL_obj ecolab::member_entry_base
1048 #pragma omit TCL_obj _ios_fields
1049 
1050 #pragma omit TCL_obj GRAPHCODE_NS::omap
1051 #pragma omit TCL_obj graphcode::GraphMaps
1052 #pragma omit TCL_obj graphcode::Graph
1053 #pragma omit TCL_obj ref
1054 #endif
1055 
1056  template <class T>
1057  void TCL_obj(TCL_obj_t& t, const string& d, const Enum_handle<T>& a)
1058  {TCL_obj_register(t,d, a);}
1059 }
1060 
1061 using ecolab::TCL_obj;
1062 using ecolab::TCL_obj_onbase;
1063 
1064 namespace classdesc_access
1065 {
1066  namespace cd=classdesc;
1067 
1068  template <class T>
1070  {
1071  template <class U>
1072  void operator()(cd::TCL_obj_t& t, const cd::string& d, U& a)
1073  {
1074  a.name=d;
1075  // an EcoLab ref always has a target once it has been TCL_obj'd
1076  TCL_obj(t,d,*a);
1077  }
1078  };
1079 
1080  template <class T>
1081  struct access_TCL_obj<classdesc::shared_ptr<T> >
1082  {
1083  template <class U>
1084  void operator()(cd::TCL_obj_t& t, const cd::string& d, U& a)
1085  {
1086  if (a) TCL_obj(t,d,*a);
1087  }
1088  };
1089 
1090  template <class T>
1092  {
1093  template <class U>
1094  void operator()(cd::TCL_obj_t& t, const cd::string& d, U& a)
1095  {TCL_obj_register(d, a, t.member_entry_hook, t.member_entry_thook);}
1096  };
1098 
1099 
1100 namespace ecolab
1103  template <class F>
1104  struct TCL_accessor: public cmd_data
1105  {
1106  const F& f;
1107  TCL_accessor(const F& f): f(f) {}
1108  void proc(int argc, Tcl_Obj *const argv[]) {
1109  tclreturn r;
1110  if (argc<=1)
1111  r << f();
1112  else
1113  r << f(TCL_args(argc, argv));
1114  }
1115  void proc(int, const char **) {}
1116  };
1117 
1119  template <class F>
1120  struct TCL_accessor<const F>: public cmd_data
1121  {
1122  const F f;
1123  TCL_accessor(F f): f(f) {}
1124  void proc(int argc, Tcl_Obj *const argv[]) {
1125  tclreturn() << f();
1126  }
1127  void proc(int, const char **) {}
1128  };
1129 
1131  template <class T> struct is_map;
1132 }
1133 
1135 {
1136  namespace cd=classdesc;
1137  template <class T, class G, class S>
1138  struct access_TCL_obj<ecolab::Accessor<T,G,S> >
1139  {
1140  template <class U>
1141  void operator()(cd::TCL_obj_t& t, const cd::string& d, U& a)
1142  {
1143  TCL_OBJ_DBG(printf("registering %s\n",d.c_str()););
1144  Tcl_CreateObjCommand(ecolab::interp(),d.c_str(),ecolab::TCL_oproc,
1145  (ClientData)new ecolab::TCL_accessor<U>(a),
1146  ecolab::TCL_cmd_data_delete);
1147  }
1148  };
1150 
1151 
1152 #if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
1153 #pragma GCC diagnostic push
1154 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
1155 #endif
1156 
1157 #include "TCL_obj_base.cd"
1158 
1159 #if defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
1160 #pragma GCC diagnostic pop
1161 #endif
1162 
1163 #endif /* TCL_OBJ_BASE_H */
Metaprogramming support for processing functions of multiple arguments.
Definition: TCL_obj_base.h:251
An RAII class for returning values to TCL.
Definition: tcl++.h:563
a slightly safer way of referring to registered objects than bare pointers
Definition: TCL_obj_base.h:449
bool xdr_check
whether to use xdr_pack or binary pack in checkpoint/restart
Definition: TCL_obj_base.h:331
whether B&#39;s method is callable due to the rules of const-correctness, or due to having lvalue argumen...
Definition: TCL_obj_base.h:843
unsigned myid
main window of application
is_const_method::value is true if F is a pointer to a const method
Definition: TCL_obj_base.h:40
Definition: ref.h:27
Definition: TCL_obj_base.h:273
An EcoLab string stream class.
Definition: eco_strstream.h:64
EcoLab exception class.
Definition: error.h:25
Tcl_Interp * interp()
default interpreter. Set to NULL when interp() is destroyed
Definition: tcl++.h:222
T * memberPtrCasted() const
returns reference to base object of type T, if this is castable, null otherwise
Definition: TCL_obj_base.h:520
Basic C++ TCL access.
RAII TCL_Obj ref.
Definition: TCL_obj_base.h:93
T & operator*()
dereference - creates default object if null
Definition: TCL_obj_base.h:65
Reference counted smart pointer classes.
classdesc::TCL_obj_t null_TCL_obj
a null TCL_obj_t suitable for nothing if needed.
Definition: TCL_obj_base.h:627
serialisation descriptor
Definition: TCL_obj_base.h:624
Definition: TCL_obj_base.h:330
Definition: TCL_obj_base.h:267
Definition: tcl++.h:272
EcoLab exception class.
class to allow access to private members
Definition: classdesc_access.h:21
Definition: TCL_obj_base.h:632
void set(const char *s)
set object to refer to registered object s.
Definition: TCL_obj_base.h:629
Definition: TCL_obj_base.h:327
std::map< const std::type_info *, void *, TypeInfoLess > BasePtrs
map of pointers to base class objects of the referred object
Definition: TCL_obj_base.h:281
helper for constructing null descriptors
Definition: classdesc.h:784
Definition: TCL_obj_base.h:885
Definition: TCL_obj_base.h:511
virtual void proc(int argc, Tcl_Obj *const argv[])
just to stop some compiler warning
Definition: TCL_obj_base.h:262
class to allow access to private members
Definition: classdesc_access.h:22
void TCL_obj_custom_register(const string &desc, T &arg)
a &#39;hook&#39; to allow registrations to occur for TCL_objects (overriding base classes) ...
Definition: TCL_obj_base.h:668
#define CLASSDESC_ACCESS(type)
add friend statements for each accessor function
Definition: classdesc_access.h:36
Definition: TCL_obj_base.h:589
Definition: object.h:28
controlled template specialisation: stolen from boost::enable_if.
Definition: TCL_obj_base.h:250
void pack(pack_t &targ, const string &desc, is_treenode dum, const T *const &arg)
serialise a tree (or DAG)
Definition: pack_graph.h:28
Represent arguments to TCL commands.
Definition: TCL_obj_base.h:138
Definition: classdesc.h:588
Definition: TCL_obj_base.h:315
Definition: TCL_obj_base.h:913
distinguish between maps and sets based on value_type of container
Definition: TCL_obj_base.h:1131
for accessors (overloaded getter/setters that pretend to be attributes)
Definition: TCL_obj_base.h:1104
Return::T (or ::type) is the return type of F
Definition: TCL_obj_base.h:33
serialisation for standard containers
Definition: TCL_obj_base.h:364
inheritance relationship descriptor
Contains definitions related to classdesc functionality.
Definition: arrays.h:2514
Definition: TCL_obj_base.h:124
void parallel(TCL_args args)
parallel declarator support for TCL_args
Definition: TCL_obj_base.h:238
controlled template specialisation: stolen from boost::enable_if.
Definition: classdesc.h:249
_OPENMP
Definition: accessor.h:16
TCL_obj descriptor object.
Definition: TCL_obj_base.h:327
Definition: TCL_obj_base.h:27
Definition: TCL_obj_base.h:70
Contains access_* structs, and nothing else. These structs are used to gain access to private members...
Definition: accessor.h:55
Definition: TCL_obj_base.h:631
Definition: TCL_obj_base.h:702
Definition: accessor.h:32
void unpack(unpack_t &targ, const string &desc, is_treenode dum, T *&arg)
unserialise a tree.
Definition: pack_graph.h:44
void(* hook)(int argc, CONST84 char **argv)
Definition: TCL_obj_base.h:268