TCL_obj_stl.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 
13 #ifndef TCL_OBJ_STL_H
14 #define TCL_OBJ_STL_H
15 #include <string>
16 #include <iostream>
17 
18 #include <set>
19 #include "TCL_obj_base.h"
20 
21 #include "TCL_obj_stl.h"
22 
23 #include <vector>
24 #include <utility>
25 
26 namespace ecolab
27 {
28  inline int null_proc() {return TCL_OK;}
29 
31  {
32  public:
33  virtual ~TCL_obj_of_base(){}
34  virtual string operator()(const char* index)=0;
35  virtual void keys_of()=0;
36  };
37 
38  static void del_obj(ClientData c)
39  { delete (TCL_obj_of_base*)c;}
40 
41  template <class T> std::string quoteTCL(const T& x);
42 
43 
44  // template <class T> void pushout(std::ostream& o, const T& c) {o<<c;}
45  template <class F, class S>
46  std::ostream& operator<<(std::ostream& o, const std::pair<F,S>& p)
47  {return o<<quoteTCL(p.first)<<" "<<quoteTCL(p.second);}
48 
49  template <class T>
50  std::ostream& ContainerOut(std::ostream& o, const T& c)
51  {
52  for (typename T::const_iterator i=c.begin(); i!=c.end(); i++)
53  {
54  if (i!=c.begin()) o<<" ";
55  o << quoteTCL(*i);
56  }
57  return o;
58  }
59 
60  // TODO: handle spaces and active characters?
61  template <class T>
62  std::istream& ContainerIn(std::istream& i, T& c)
63  {
64  c.clear();
65  typename T::value_type v;
66  while (i>>v)
67  {
68 #if defined(__cplusplus) && __cplusplus>=201103L
69  c.push_back(std::move(v));
70 #else
71  c.push_back(v);
72 #endif
73  }
74  return i;
75  }
76 
77 
78  template <class T, class CharT, class Traits>
79  typename enable_if<is_container<T>, std::ostream&>::T
80  operator<<(std::basic_ostream<CharT,Traits>& o, const T& v)
81  {return ContainerOut(o,v);}
82 
83  template<class T>
85  operator|(eco_strstream& s,const T& x)
86  {
87  std::ostringstream tmp;
88  ContainerOut(tmp,x);
89  s<<tmp.str();
90  return s;
91  }
92 
93 
94  template <class T, class CharT, class Traits>
95  typename enable_if<is_sequence<T>, std::basic_istream<CharT,Traits>&>::T
96  operator>>(std::basic_istream<CharT,Traits>& i, T& v)
97  {return ContainerIn(i,v);}
98 
99  // values need quoting if they contain spaces, and special chars need escaping
100  template <class T>
101  std::string quoteTCL(const T& x)
102  {
103  eco_strstream os;
104  os | x;
105  std::string r;
106  for (size_t i=0; i<os.str().length(); ++i)
107  {
108  if (strchr("{}\\\"", os.str()[i])!=NULL)
109  r+='\\';
110  r+=os.str()[i];
111  }
112  if (r.find(' ')!=std::string::npos)
113  r="{"+r+"}";
114  return r;
115  }
116 
118  template <class T> struct is_map: public false_type
119  {
120  static string keys() {return ".#members";}
121  static string type() {return ".@is_set";}
122  };
123 
124  struct is_map_map: public true_type
125  {
126  static string keys() {return ".#keys";}
127  static string type() {return ".@is_map";}
128  };
129 
130 
131  template <class K, class V, class C, class A> struct is_map<std::map<K,V,C,A> >:
132  public is_map_map {};
133 
134 #if defined(__cplusplus) && __cplusplus>=201103L
135  template <class K, class V, class C, class A> struct is_map<std::unordered_map<K,V,C,A> >:
136  public is_map_map {};
137 #endif
138 
139  template <class T>
140  typename enable_if<Not<is_map<T> >, typename T::value_type>::T
141  readIn(std::istream& i)
142  {typename T::value_type v; i>>v; return v;}
143 
144  template <class T>
145  typename enable_if<is_map<T>, typename T::value_type>::T
146  readIn(std::istream& i)
147  {
148  typename remove_const<typename T::value_type::first_type>::type k;
149  typename T::value_type::second_type v;
150  i>>k>>v;
151  return typename T::value_type(k,v);
152  }
153 
154  template <class T, class CharT, class Traits>
155  typename enable_if<is_associative_container<T>, std::basic_istream<CharT,Traits>&>::T
156  operator>>(std::basic_istream<CharT,Traits>& i, T& s)
157  {
158  s.clear();
159  while (i)
160  {
161  typename T::value_type v=readIn<T>(i);
162  if (i)
163  s.insert(v);
164  }
165  return i;
166  }
167 
168  static int elem(ClientData v, Tcl_Interp *interp, int argc,
169  CONST84 char** argv)
170  {
171  tclreturn r;
172  if (argc<2)
173  {
174  r << "insufficient arguments";
175  return TCL_ERROR;
176  }
177  r << (*(TCL_obj_of_base*)v)(argv[1]);
178  return TCL_OK;
179  }
180 
181  static int keys(ClientData v, Tcl_Interp *interp, int argc,
182  CONST84 char** argv)
183  {((TCL_obj_of_base*)v)->keys_of(); return TCL_OK;}
184 
185  template <class T> struct idx
186  {T operator()(const char *x) {throw error("invalid index type");}};
187 
188  template <> struct idx<int>
189  {int operator()(const char *x){return atoi(x);}};
190 
191  template <> struct idx<unsigned int>
192  {int operator()(const char *x){return atoi(x);}};
193 
194  template <> struct idx<long>
195  {long operator()(const char *x){return atol(x);}};
196 
197  template <> struct idx<unsigned long>
198  {long operator()(const char *x){return atol(x);}};
199 
200  template <> struct idx<const char *>
201  {const char* operator()(const char *x){return x;}};
202 
203  template <> struct idx<std::string>
204  {std::string operator()(const char *x){return std::string(x);}};
205 
206  template <class T> struct idx<const T>: public idx<T> {};
207 
208 
209  /* support for extracting a list of keys in keyed data types (eg maps) */
210 
211  template <class T>
212  typename enable_if<is_map<T>, void>::T
213  keys_of(const T& o)
214  {
215  tclreturn r;
216  for (typename T::const_iterator i=o.begin(); i!=o.end(); i++)
217  r<<i->first;
218  }
219 
220  template <class T>
221  typename enable_if<Not<is_map<T> >, void>::T
222  keys_of(const T& o)
223  {
224  tclreturn r;
225  for (typename T::const_iterator i=o.begin(); i!=o.end(); i++)
226  r<<*i;
227  }
228 
229 
230 
231  //handle vector<bool> as a special case
232  template <> struct member_entry<std::vector<bool>::reference>: public member_entry_base
233  {
234  typedef std::vector<bool>::reference R;
235  std::vector<bool> defaultDummy;
236  R memberptr;
237  member_entry(): defaultDummy(1), memberptr(defaultDummy[0]) {}
238  member_entry(R& x): memberptr(x) {}
239  inline void get() {tclreturn() << (bool)memberptr;}
240  inline void put(const char *s) {tclreturn() << s; memberptr=atoi(s);}
241  };
242 
243  template <class T, class idx_t>
245  {
246  T& obj;
247  string desc;
248  public:
249  TCL_obj_of(T& o, const string& d): obj(o), desc(d) {}
250  string operator()(const char* index)
251  {
252  string elname=desc+"("+index+")";
253  // because TCL_obj_register assumes second time around calls are
254  // base class registrations, we need to erase the member_entry
255  // before registering the new handler, in case the element's
256  // address has changed due to container resizing or whatever
257  TCL_obj_properties().erase(elname);
258  TCL_obj(ecolab::null_TCL_obj,elname,obj[idx<idx_t>()(index)]);
259  return elname;
260  }
261  void keys_of() {ecolab::keys_of(obj);}
262  };
263 
264  template <class T, class idx_t>
266  {
267  T& obj;
268  string desc;
269  public:
270  TCL_obj_of_vector_bool(T& o, const string& d): obj(o), desc(d) {}
271  string operator()(const char* index)
272  {
273  string elname=desc+"("+index+")";
274  TCL_obj_properties().erase(elname);
275  typename T::reference r(obj[idx<idx_t>()(index)]);
276  TCL_obj(ecolab::null_TCL_obj,elname,r);
277  return elname;
278  }
279  void keys_of() {ecolab::keys_of(obj);}
280  };
281 
282  template <class idx_t>
283  struct TCL_obj_of<std::vector<bool>,idx_t>:
284  public TCL_obj_of_vector_bool<std::vector<bool>,idx_t>
285  {
286  TCL_obj_of(std::vector<bool>& o, const string& d):
288  };
289 
290  template <class idx_t>
291  struct TCL_obj_of<const std::vector<bool>,idx_t>:
292  public TCL_obj_of_vector_bool<const std::vector<bool>,idx_t>
293  {
294  TCL_obj_of(const std::vector<bool>& o, const string& d):
296  };
297 
298  /* special case when only forward iterators are available */
299  class iter {};
300  template <class T>
302  {
303  T& obj;
304  string desc;
305  public:
306  TCL_obj_of(T& o, const string& d): obj(o), desc(d) {}
307  string operator()(const char* index)
308  {
309  string elname=desc+"("+index+")";
310  TCL_obj_properties().erase(elname);
311  typename T::iterator j;
312  int i;
313  for (i=0, j=obj.begin(); i<atoi(index); i++, j++);
314  TCL_obj(ecolab::null_TCL_obj,elname,*j);
315  return elname;
316  }
317  void keys_of() {ecolab::keys_of(obj);}
318  };
319 
320  // for distingushing between sets and maps with @elem functionality
321  template <class T>
323  makeTCL_obj_of(T& o, const string& d)
324  {return new TCL_obj_of<T,typename T::key_type>(o,d);}
325 
326  template <class T>
328  makeTCL_obj_of(T& o, const string& d)
329  {return new TCL_obj_of<T,iter>(o,d);}
330 
331  /* special case to handle count method */
332  template <class T, class idx_t>
334  {
335  const T& obj;
336  string desc;
337  public:
338  TCL_obj_of_count(const T& o, const string& d): obj(o), desc(d) {}
339  string operator()(const char* index)
340  {return (eco_strstream() << obj.count(idx<idx_t>()(index))).str();}
341  void keys_of() {ecolab::keys_of(obj);}
342  };
343 
344  // specialised functor for calling resize, as it may be overloaded,
345  // or may have a default second argument
346  template <class S> struct ResizeFunctor: public cmd_data
347  {
348  S& x;
349  ResizeFunctor(S& x): x(x) {}
350  void proc(int argc, Tcl_Obj *const argv[]) {
351  x.resize((size_t)TCL_args(argc, argv));
352  }
353  static void createInTCL(S& x, const string& d) {
354  Tcl_CreateObjCommand(interp(),(d+".resize").c_str(), TCL_oproc,
355  (ClientData)new ResizeFunctor<S>(x),
356  TCL_cmd_data_delete);
357  }
358  void proc(int, const char **) {}
359  };
360 
361  template <class V>
362  void TCL_obj_const_sequence(TCL_obj_t& targ, const string& desc, V& arg)
363  {
364  TCL_obj_register(targ,desc,arg);
365  TCL_obj(targ,desc+".size",arg,&V::size);
366  Tcl_CreateCommand(interp(),(desc+".@is_sequence").c_str(),
367  (Tcl_CmdProc*)null_proc,NULL,NULL);
368  ClientData c=(ClientData)new TCL_obj_of<V,iter>(arg,desc);
369  Tcl_CreateCommand(interp(),(desc+".@elem").c_str(),(Tcl_CmdProc*)elem,c,
370  (Tcl_CmdDeleteProc*)del_obj);
371  }
372 
373  // specialisation for vectors that exploits operator[]
374  template <class V>
375  void TCL_obj_const_vector(TCL_obj_t& targ, const string& desc, V& arg)
376  {
377  TCL_obj_register(targ,desc,arg);
378  TCL_obj(targ,desc+".size",arg,&V::size);
379  Tcl_CreateCommand(interp(),(desc+".@is_vector").c_str(),
380  (Tcl_CmdProc*)null_proc,NULL,NULL);
381  ClientData c=(ClientData)new TCL_obj_of<V,typename V::size_type>(arg,desc);
382  Tcl_CreateCommand(interp(),(desc+".@elem").c_str(),(Tcl_CmdProc*)elem,c,
383  (Tcl_CmdDeleteProc*)del_obj);
384  }
385 
386  template <class V>
387  void TCL_obj_sequence(TCL_obj_t& targ, const string& desc, V& arg)
388  {
389  ecolab::TCL_obj_const_sequence(targ,desc,arg);
391  TCL_obj(targ,desc+".clear",arg,&V::clear);
392  }
393 
394  template <class T, class A>
395  void TCL_obj_sequence(TCL_obj_t& targ, const string& desc, std::vector<T,A>& arg)
396  {
397  ecolab::TCL_obj_const_vector(targ,desc,arg);
398  ecolab::ResizeFunctor<std::vector<T,A> >::createInTCL(arg,desc);
399  TCL_obj(targ,desc+".clear",arg,&std::vector<T,A>::clear);
400  }
401 
402  template <class T, class A>
403  void TCL_obj_sequence(TCL_obj_t& targ, const string& desc, const std::vector<T,A>& arg)
404  {
405  ecolab::TCL_obj_const_vector(targ,desc,arg);
406  }
407 
408 
409  template <class VT> struct KeyName: public std::string
410  {KeyName(): std::string(".#members") {}};
411  template <class K,class V> struct KeyName<std::pair<K,V> >: public std::string
412  {KeyName(): std::string(".#keys") {}};
413 
414  template <class T>
415  void TCL_obj_associative_container(TCL_obj_t& targ, const string& desc, T& arg)
416  {
417  TCL_obj_register(targ,desc,arg);
418  TCL_obj(targ,desc+".size",arg,&T::size);
419  Tcl_CreateCommand(interp(),(desc+is_map<T>::type()).c_str(),
420  (Tcl_CmdProc*)null_proc,NULL,NULL);
421  ClientData c=(ClientData)makeTCL_obj_of(arg,desc);
422  Tcl_CreateCommand(interp(),(desc+".@elem").c_str(),(Tcl_CmdProc*)elem,c,
423  (Tcl_CmdDeleteProc*)del_obj);
424  c=(ClientData)makeTCL_obj_of(arg,desc);
425  Tcl_CreateCommand(interp(),(desc+is_map<T>::keys()).c_str(),(Tcl_CmdProc*)keys,c,
426  (Tcl_CmdDeleteProc*)del_obj);
427  c=(ClientData)new TCL_obj_of_count<T,typename T::key_type>(arg,desc);
428  Tcl_CreateCommand(interp(),(desc+".count").c_str(),(Tcl_CmdProc*)elem,c,
429  (Tcl_CmdDeleteProc*)del_obj);
430  }
431 
432  template <class T>
433  typename enable_if<is_sequence<T>, void>::T
434  TCL_objp(TCL_obj_t& t,const classdesc::string& desc, T& arg, dummy<1> d=0)
435  {
436  TCL_obj_sequence(t,desc,arg);
437  }
438 
439  template <class T>
440  typename enable_if<is_associative_container<T>, void>::T
441  TCL_objp(TCL_obj_t& t,const classdesc::string& desc, T& arg, dummy<2> d=0)
442  {
443  TCL_obj_associative_container(t,desc,arg);
444  }
445 
446 }
447 using ecolab::TCL_obj;
448 
449 namespace eco_strstream_ns
450 {
451  using ecolab::operator<<;
452 }
453 
454 
455 #endif
Definition: TCL_obj_stl.h:333
Definition: TCL_obj_base.h:251
An RAII class for returning values to TCL.
Definition: tcl++.h:563
Definition: TCL_obj_stl.h:346
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
Definition: graph.h:537
Definition: TCL_obj_stl.h:301
classdesc::TCL_obj_t null_TCL_obj
a null TCL_obj_t suitable for nothing if needed.
Definition: TCL_obj_base.h:267
Definition: TCL_obj_stl.h:30
Definition: tcl++.h:272
Definition: TCL_obj_stl.h:299
Definition: TCL_obj_stl.h:409
TCL_obj support for STL containers.
Definition: TCL_obj_stl.h:185
Definition: TCL_obj_base.h:511
Represent arguments to TCL commands.
Definition: TCL_obj_base.h:138
TCL access descriptor.
Definition: TCL_obj_stl.h:449
distinguish between maps and sets based on value_type of container
Definition: TCL_obj_base.h:1131
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_stl.h:244
Definition: TCL_obj_stl.h:265
Definition: TCL_obj_stl.h:124