00001 /** @file tcl/makecmd.h construct tcl commands from c++ functions via 00002 templatized argument deduction and conversion between tcl and 00003 c++ */ 00004 00005 /////////////////////////////////////////////////////////////////////// 00006 // 00007 // Copyright (c) 2001-2004 California Institute of Technology 00008 // Copyright (c) 2004-2007 University of Southern California 00009 // Rob Peters <rjpeters at usc dot edu> 00010 // 00011 // created: Fri Jun 22 09:07:27 2001 00012 // commit: $Id: makecmd.h 11876 2009-10-22 15:53:06Z icore $ 00013 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/makecmd.h $ 00014 // 00015 // -------------------------------------------------------------------- 00016 // 00017 // This file is part of GroovX 00018 // [http://ilab.usc.edu/rjpeters/groovx/] 00019 // 00020 // GroovX is free software; you can redistribute it and/or modify it 00021 // under the terms of the GNU General Public License as published by 00022 // the Free Software Foundation; either version 2 of the License, or 00023 // (at your option) any later version. 00024 // 00025 // GroovX is distributed in the hope that it will be useful, but 00026 // WITHOUT ANY WARRANTY; without even the implied warranty of 00027 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00028 // General Public License for more details. 00029 // 00030 // You should have received a copy of the GNU General Public License 00031 // along with GroovX; if not, write to the Free Software Foundation, 00032 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00033 // 00034 /////////////////////////////////////////////////////////////////////// 00035 00036 #ifndef GROOVX_TCL_MAKECMD_H_UTC20050628162421_DEFINED 00037 #define GROOVX_TCL_MAKECMD_H_UTC20050628162421_DEFINED 00038 00039 #include "nub/ref.h" 00040 00041 #include "tcl/argspec.h" 00042 #include "tcl/conversions.h" 00043 #include "tcl/command.h" 00044 #include "tcl/commandgroup.h" 00045 #include "tcl/vecdispatch.h" 00046 00047 #include "rutz/functors.h" 00048 #include "rutz/shared_ptr.h" 00049 00050 namespace rutz 00051 { 00052 struct file_pos; 00053 00054 /// Specialization of func_traits for mem_functor. 00055 template <class MF> 00056 struct func_traits<mem_functor<MF> > : public func_traits<MF> 00057 { 00058 typedef nub::soft_ref<typename mem_functor<MF>::C> arg1_t; 00059 }; 00060 } 00061 00062 namespace tcl 00063 { 00064 /// Overload of aux_convert_to for nub::ref. 00065 /** This allows us to receive nub::ref objects from Tcl via the 00066 nub::uid's of the referred-to objects. */ 00067 template <class T> 00068 inline nub::ref<T> aux_convert_to(Tcl_Obj* obj, nub::ref<T>*) 00069 { 00070 nub::uid uid = tcl::convert_to<nub::uid>(obj); 00071 return nub::ref<T>(uid); 00072 } 00073 00074 /// Overload of aux_convert_from for nub::ref. 00075 /** This allows us to pass nub::ref objects to Tcl via the 00076 nub::uid's of the referred-to objects. */ 00077 template <class T> 00078 inline tcl::obj aux_convert_from(nub::ref<T> obj) 00079 { 00080 return convert_from<nub::uid>(obj.id()); 00081 } 00082 00083 /// Overload of aux_convert_to for nub::soft_ref. 00084 /** This allows us to receive nub::soft_ref objects from Tcl via the 00085 nub::uid's of the referred-to objects. */ 00086 template <class T> 00087 inline nub::soft_ref<T> aux_convert_to(Tcl_Obj* obj, nub::soft_ref<T>*) 00088 { 00089 nub::uid uid = tcl::convert_to<nub::uid>(obj); 00090 return nub::soft_ref<T>(uid); 00091 } 00092 00093 /// Overload of aux_convert_from for nub::soft_ref. 00094 /** This allows us to pass nub::soft_ref objects to Tcl via the 00095 nub::uid's of the referred-to objects. */ 00096 template <class T> 00097 inline tcl::obj aux_convert_from(nub::soft_ref<T> obj) 00098 { 00099 return convert_from<nub::uid>(obj.id()); 00100 } 00101 00102 00103 /////////////////////////////////////////////////////////////////////// 00104 // 00105 // func_wrapper<> template definitions. Each specialization takes a 00106 // C++-style functor (could be a free function, or struct with 00107 // operator()), and transforms it into a functor with an 00108 // operator()(tcl::call_context&) which can be called from a 00109 // tcl::command. This transformation requires extracting the 00110 // appropriate parameters from the tcl::call_context, passing them to 00111 // the C++ functor, and returning the result back to the 00112 // tcl::call_context. 00113 // 00114 /////////////////////////////////////////////////////////////////////// 00115 00116 #ifdef EXTRACT_PARAM 00117 # error EXTRACT_PARAM macro already defined 00118 #endif 00119 00120 #define EXTRACT_PARAM(N) \ 00121 typename rutz::func_traits<Func>::arg##N##_t p##N = \ 00122 ctx.template get_arg<typename rutz::func_traits<Func>::arg##N##_t>(N); 00123 00124 /// Generic tcl::func_wrapper definition. 00125 template <unsigned int N, class R, class Func> 00126 class func_wrapper 00127 {}; 00128 } 00129 00130 namespace rutz 00131 { 00132 /// Specialization of func_traits for tcl::func_wrapper. 00133 template <unsigned int N, class F, class Func> 00134 struct func_traits<tcl::func_wrapper<N, F, Func> > 00135 { 00136 typedef typename rutz::func_traits<Func>::retn_t retn_t; 00137 }; 00138 } 00139 00140 namespace tcl 00141 { 00142 00143 00144 // ######################################################## 00145 /// tcl::func_wrapper<0> -- zero arguments 00146 00147 template <class R, class Func> 00148 struct func_wrapper<0, R, Func> 00149 { 00150 private: 00151 Func m_held_func; 00152 00153 public: 00154 func_wrapper<0, R, Func>(Func f) : m_held_func(f) {} 00155 00156 ~func_wrapper() throw() {} 00157 00158 R operator()(tcl::call_context& /*ctx*/) 00159 { 00160 return m_held_func(); 00161 } 00162 }; 00163 00164 00165 // ######################################################## 00166 /// tcl::func_wrapper<1> -- one argument 00167 00168 template <class R, class Func> 00169 struct func_wrapper<1, R, Func> 00170 { 00171 private: 00172 Func m_held_func; 00173 00174 public: 00175 func_wrapper<1, R, Func>(Func f) : m_held_func(f) {} 00176 00177 ~func_wrapper() throw() {} 00178 00179 R operator()(tcl::call_context& ctx) 00180 { 00181 EXTRACT_PARAM(1); 00182 return m_held_func(p1); 00183 } 00184 }; 00185 00186 00187 // ######################################################## 00188 /// tcl::func_wrapper<2> -- two arguments 00189 00190 template <class R, class Func> 00191 struct func_wrapper<2, R, Func> 00192 { 00193 private: 00194 Func m_held_func; 00195 00196 public: 00197 func_wrapper<2, R, Func>(Func f) : m_held_func(f) {} 00198 00199 ~func_wrapper() throw() {} 00200 00201 R operator()(tcl::call_context& ctx) 00202 { 00203 EXTRACT_PARAM(1); EXTRACT_PARAM(2); 00204 return m_held_func(p1, p2); 00205 } 00206 }; 00207 00208 00209 // ######################################################## 00210 /// tcl::func_wrapper<3> -- three arguments 00211 00212 template <class R, class Func> 00213 struct func_wrapper<3, R, Func> 00214 { 00215 private: 00216 Func m_held_func; 00217 00218 public: 00219 func_wrapper<3, R, Func>(Func f) : m_held_func(f) {} 00220 00221 ~func_wrapper() throw() {} 00222 00223 R operator()(tcl::call_context& ctx) 00224 { 00225 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00226 return m_held_func(p1, p2, p3); 00227 } 00228 }; 00229 00230 00231 // ######################################################## 00232 /// tcl::func_wrapper<4> -- four arguments 00233 00234 template <class R, class Func> 00235 struct func_wrapper<4, R, Func> 00236 { 00237 private: 00238 Func m_held_func; 00239 00240 public: 00241 func_wrapper<4, R, Func>(Func f) : m_held_func(f) {} 00242 00243 ~func_wrapper() throw() {} 00244 00245 R operator()(tcl::call_context& ctx) 00246 { 00247 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00248 EXTRACT_PARAM(4); 00249 return m_held_func(p1, p2, p3, p4); 00250 } 00251 }; 00252 00253 00254 // ######################################################## 00255 /// tcl::func_wrapper<5> -- five arguments 00256 00257 template <class R, class Func> 00258 struct func_wrapper<5, R, Func> 00259 { 00260 private: 00261 Func m_held_func; 00262 00263 public: 00264 func_wrapper<5, R, Func>(Func f) : m_held_func(f) {} 00265 00266 ~func_wrapper() throw() {} 00267 00268 R operator()(tcl::call_context& ctx) 00269 { 00270 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00271 EXTRACT_PARAM(4); EXTRACT_PARAM(5); 00272 return m_held_func(p1, p2, p3, p4, p5); 00273 } 00274 }; 00275 00276 00277 // ######################################################## 00278 /// tcl::func_wrapper<6> -- six arguments 00279 00280 template <class R, class Func> 00281 struct func_wrapper<6, R, Func> 00282 { 00283 private: 00284 Func m_held_func; 00285 00286 public: 00287 func_wrapper<6, R, Func>(Func f) : m_held_func(f) {} 00288 00289 ~func_wrapper() throw() {} 00290 00291 R operator()(tcl::call_context& ctx) 00292 { 00293 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00294 EXTRACT_PARAM(4); EXTRACT_PARAM(5); EXTRACT_PARAM(6); 00295 return m_held_func(p1, p2, p3, p4, p5, p6); 00296 } 00297 }; 00298 00299 // ######################################################## 00300 /// tcl::func_wrapper<7> -- seven arguments 00301 00302 template <class R, class Func> 00303 struct func_wrapper<7, R, Func> 00304 { 00305 private: 00306 Func m_held_func; 00307 00308 public: 00309 func_wrapper<7, R, Func>(Func f) : m_held_func(f) {} 00310 00311 ~func_wrapper() throw() {} 00312 00313 R operator()(tcl::call_context& ctx) 00314 { 00315 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00316 EXTRACT_PARAM(4); EXTRACT_PARAM(5); EXTRACT_PARAM(6); 00317 EXTRACT_PARAM(7); 00318 return m_held_func(p1, p2, p3, p4, p5, p6, p7); 00319 } 00320 }; 00321 00322 // ######################################################## 00323 /// tcl::func_wrapper<8> -- eight arguments 00324 00325 template <class R, class Func> 00326 struct func_wrapper<8, R, Func> 00327 { 00328 private: 00329 Func m_held_func; 00330 00331 public: 00332 func_wrapper<8, R, Func>(Func f) : m_held_func(f) {} 00333 00334 ~func_wrapper() throw() {} 00335 00336 R operator()(tcl::call_context& ctx) 00337 { 00338 EXTRACT_PARAM(1); EXTRACT_PARAM(2); EXTRACT_PARAM(3); 00339 EXTRACT_PARAM(4); EXTRACT_PARAM(5); EXTRACT_PARAM(6); 00340 EXTRACT_PARAM(7); EXTRACT_PARAM(8); 00341 return m_held_func(p1, p2, p3, p4, p5, p6, p7, p8); 00342 } 00343 }; 00344 00345 #undef EXTRACT_PARAM 00346 00347 // ######################################################## 00348 /// Factory function to make tcl::func_wrapper's from any functor or function ptr. 00349 00350 template <class Fptr> 00351 inline func_wrapper<rutz::func_traits<Fptr>::num_args, 00352 typename rutz::func_traits<Fptr>::retn_t, 00353 typename rutz::functor_of<Fptr>::type> 00354 build_func_wrapper(Fptr f) 00355 { 00356 return rutz::build_functor(f); 00357 } 00358 00359 00360 // ######################################################## 00361 /// generic_function implements tcl::command using a held functor. 00362 00363 template <class R, class func_wrapper> 00364 class generic_function : public tcl::function 00365 { 00366 protected: 00367 generic_function<R, func_wrapper>(func_wrapper f) : m_held_func(f) {} 00368 00369 public: 00370 static rutz::shared_ptr<tcl::function> make(func_wrapper f) 00371 { 00372 return rutz::shared_ptr<tcl::function>(new generic_function(f)); 00373 } 00374 00375 virtual ~generic_function() throw() {} 00376 00377 protected: 00378 virtual void invoke(tcl::call_context& ctx) 00379 { 00380 R res(m_held_func(ctx)); ctx.set_result(res); 00381 } 00382 00383 private: 00384 func_wrapper m_held_func; 00385 }; 00386 00387 // ######################################################## 00388 /// Specialization for functors with void return types. 00389 00390 template <class func_wrapper> 00391 class generic_function<void, func_wrapper> : public tcl::function 00392 { 00393 protected: 00394 generic_function<void, func_wrapper>(func_wrapper f) : m_held_func(f) {} 00395 00396 public: 00397 static rutz::shared_ptr<tcl::function> make(func_wrapper f) 00398 { 00399 return rutz::shared_ptr<tcl::function>(new generic_function(f)); 00400 } 00401 00402 virtual ~generic_function() throw() {} 00403 00404 protected: 00405 virtual void invoke(tcl::call_context& ctx) 00406 { 00407 m_held_func(ctx); 00408 } 00409 00410 private: 00411 func_wrapper m_held_func; 00412 }; 00413 00414 00415 // ######################################################## 00416 /// Factory function for tcl::command's from functors. 00417 00418 template <class func_wrapper> 00419 inline void 00420 make_generic_command(tcl::interpreter& interp, 00421 func_wrapper f, 00422 const char* cmd_name, 00423 const char* usage, 00424 const arg_spec& spec, 00425 const rutz::file_pos& src_pos) 00426 { 00427 typedef typename rutz::func_traits<func_wrapper>::retn_t retn_t; 00428 tcl::command_group::make(interp, 00429 generic_function<retn_t, func_wrapper>::make(f), 00430 cmd_name, usage, spec, src_pos); 00431 } 00432 00433 00434 // ######################################################## 00435 /// Factory function for vectorized tcl::command's from functors. 00436 00437 template <class func_wrapper> 00438 inline void 00439 make_generic_vec_command(tcl::interpreter& interp, 00440 func_wrapper f, 00441 const char* cmd_name, 00442 const char* usage, 00443 const arg_spec& spec, 00444 unsigned int keyarg, 00445 const rutz::file_pos& src_pos) 00446 { 00447 typedef typename rutz::func_traits<func_wrapper>::retn_t retn_t; 00448 rutz::shared_ptr<tcl::command> cmd = 00449 tcl::command_group::make(interp, 00450 generic_function<retn_t, func_wrapper>::make(f), 00451 cmd_name, usage, spec, src_pos); 00452 tcl::use_vec_dispatch(*cmd, keyarg); 00453 } 00454 00455 /////////////////////////////////////////////////////////////////////// 00456 // 00457 // And finally... make_command 00458 // 00459 /////////////////////////////////////////////////////////////////////// 00460 00461 // ######################################################## 00462 /// Factory function for tcl::command's from function pointers. 00463 00464 template <class Func> 00465 inline void 00466 make_command(tcl::interpreter& interp, 00467 Func f, 00468 const char* cmd_name, 00469 const char* usage, 00470 const rutz::file_pos& src_pos) 00471 { 00472 make_generic_command 00473 (interp, build_func_wrapper(f), cmd_name, usage, 00474 arg_spec(rutz::func_traits<Func>::num_args + 1, -1, true), 00475 src_pos); 00476 } 00477 00478 // ######################################################## 00479 /// Factory function for vectorized tcl::command's from function pointers. 00480 00481 template <class Func> 00482 inline void 00483 make_vec_command(tcl::interpreter& interp, 00484 Func f, 00485 const char* cmd_name, 00486 const char* usage, 00487 unsigned int keyarg /*default is 1*/, 00488 const rutz::file_pos& src_pos) 00489 { 00490 make_generic_vec_command 00491 (interp, build_func_wrapper(f), cmd_name, usage, 00492 arg_spec(rutz::func_traits<Func>::num_args + 1, -1, true), 00493 keyarg, src_pos); 00494 } 00495 00496 } // end namespace tcl 00497 00498 static const char __attribute__((used)) vcid_groovx_tcl_makecmd_h_utc20050628162421[] = "$Id: makecmd.h 11876 2009-10-22 15:53:06Z icore $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/makecmd.h $"; 00499 #endif // !GROOVX_TCL_MAKECMD_H_UTC20050628162421_DEFINED