00001 /** @file tcl/vecdispatch.cc apply vectorized dispatching to a 00002 tcl::command */ 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 2001-2004 California Institute of Technology 00006 // Copyright (c) 2004-2007 University of Southern California 00007 // Rob Peters <rjpeters at usc dot edu> 00008 // 00009 // created: Thu Jul 12 12:15:46 2001 00010 // commit: $Id: vecdispatch.cc 11876 2009-10-22 15:53:06Z icore $ 00011 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/vecdispatch.cc $ 00012 // 00013 // -------------------------------------------------------------------- 00014 // 00015 // This file is part of GroovX 00016 // [http://ilab.usc.edu/rjpeters/groovx/] 00017 // 00018 // GroovX is free software; you can redistribute it and/or modify it 00019 // under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation; either version 2 of the License, or 00021 // (at your option) any later version. 00022 // 00023 // GroovX is distributed in the hope that it will be useful, but 00024 // WITHOUT ANY WARRANTY; without even the implied warranty of 00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00026 // General Public License for more details. 00027 // 00028 // You should have received a copy of the GNU General Public License 00029 // along with GroovX; if not, write to the Free Software Foundation, 00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00031 // 00032 /////////////////////////////////////////////////////////////////////// 00033 00034 #ifndef GROOVX_TCL_VECDISPATCH_CC_UTC20050628162420_DEFINED 00035 #define GROOVX_TCL_VECDISPATCH_CC_UTC20050628162420_DEFINED 00036 00037 #include "tcl/vecdispatch.h" 00038 00039 #include "tcl/command.h" 00040 #include "tcl/list.h" 00041 00042 #include "rutz/error.h" 00043 #include "rutz/shared_ptr.h" 00044 00045 #include <vector> 00046 00047 #include "rutz/trace.h" 00048 #include "rutz/debug.h" 00049 GVX_DBG_REGISTER 00050 00051 namespace tcl 00052 { 00053 class vec_context; 00054 } 00055 00056 /////////////////////////////////////////////////////////////////////// 00057 // 00058 // tcl::vec_context implements the tcl::call_context interface in such 00059 // a way as to treat each of the arguments as lists, and provide 00060 // access to slices across those lists, thus allowing "vectorized" 00061 // command invocations. 00062 // 00063 /////////////////////////////////////////////////////////////////////// 00064 00065 class tcl::vec_context : public tcl::call_context 00066 { 00067 public: 00068 vec_context(tcl::interpreter& interp, unsigned int objc, 00069 Tcl_Obj* const objv[]) : 00070 call_context(interp, objc, objv), 00071 m_arg0(objv[0]), 00072 m_args(), 00073 m_result() 00074 { 00075 for (unsigned int i = 1; i < objc; ++i) 00076 { 00077 tcl::list arg(objv[i]); 00078 if (arg.length() == 0) 00079 { 00080 throw rutz::error("argument was empty", SRC_POS); 00081 } 00082 m_args.push_back( arg.begin<Tcl_Obj*>() ); 00083 } 00084 } 00085 00086 virtual ~vec_context() throw() {} 00087 00088 void flush_result() 00089 { 00090 tcl::call_context::set_obj_result(m_result.as_obj()); 00091 } 00092 00093 void next() 00094 { 00095 for (unsigned int i = 0; i < m_args.size(); ++i) 00096 { 00097 if (m_args[i].has_more()) 00098 ++(m_args[i]); 00099 } 00100 } 00101 00102 protected: 00103 virtual Tcl_Obj* get_objv(unsigned int argn) throw() 00104 { 00105 if (argn == 0) return m_arg0; 00106 00107 return *(m_args.at(argn-1)); 00108 } 00109 00110 virtual void set_obj_result(const tcl::obj& obj) 00111 { 00112 m_result.append(obj); 00113 } 00114 00115 private: 00116 typedef tcl::list::iterator<Tcl_Obj*> Iter; 00117 00118 Tcl_Obj* m_arg0; 00119 std::vector<Iter> m_args; 00120 tcl::list m_result; 00121 }; 00122 00123 namespace tcl 00124 { 00125 class vec_dispatcher; 00126 } 00127 00128 /////////////////////////////////////////////////////////////////////// 00129 /** 00130 * 00131 * \c tcl::vec_dispatcher reimplements dispatch() to use a specialized 00132 * \c tcl::call_context class that treats each of the arguments as 00133 * lists, and provide access to slices across those lists, thus 00134 * allowing "vectorized" command invocations. 00135 * 00136 **/ 00137 /////////////////////////////////////////////////////////////////////// 00138 00139 class tcl::vec_dispatcher : public tcl::arg_dispatcher 00140 { 00141 public: 00142 vec_dispatcher(unsigned int key_argn) : m_key_argn(key_argn) {} 00143 00144 virtual ~vec_dispatcher() throw() {} 00145 00146 virtual void dispatch(tcl::interpreter& interp, 00147 unsigned int objc, Tcl_Obj* const objv[], 00148 tcl::function& callback); 00149 00150 private: 00151 unsigned int m_key_argn; 00152 }; 00153 00154 00155 void tcl::vec_dispatcher::dispatch(tcl::interpreter& interp, 00156 unsigned int objc, 00157 Tcl_Obj* const objv[], 00158 tcl::function& callback) 00159 { 00160 GVX_TRACE("tcl::vec_dispatcher::dispatch"); 00161 00162 const unsigned int ncalls 00163 = tcl::list::get_obj_list_length(objv[m_key_argn]); 00164 00165 if (ncalls > 1) 00166 { 00167 vec_context cx(interp, objc, objv); 00168 00169 for (unsigned int c = 0; c < ncalls; ++c) 00170 { 00171 callback.invoke(cx); 00172 cx.next(); 00173 } 00174 00175 cx.flush_result(); 00176 } 00177 else if (ncalls == 1) 00178 { 00179 tcl::call_context cx(interp, objc, objv); 00180 callback.invoke(cx); 00181 } 00182 else // (ncalls == 0) 00183 { 00184 ;// do nothing, so we gracefully handle empty lists 00185 } 00186 } 00187 00188 00189 void tcl::use_vec_dispatch(tcl::command& cmd, unsigned int key_argn) 00190 { 00191 cmd.set_dispatcher(rutz::make_shared(new vec_dispatcher(key_argn))); 00192 } 00193 00194 static const char __attribute__((used)) vcid_groovx_tcl_vecdispatch_cc_utc20050628162420[] = "$Id: vecdispatch.cc 11876 2009-10-22 15:53:06Z icore $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/vecdispatch.cc $"; 00195 #endif // !GROOVX_TCL_VECDISPATCH_CC_UTC20050628162420_DEFINED