From: Sean Woods on 9 Aug 2010 18:02 Well Tclers, I have an interesting problem, and feel free to tell me "Hypnotoad, that's not what NRE was designed for!" To speed up my Tcl code, I have several what I call "containers" that map C data structures to Key/Value lists and back again. One of the features I've found most handy are routines evaluates a script over the entire table of data structures I have loaded. For a trivial example of what's going on at the Tcl level: set fout [open dumpfile.csv w] entity foreach { puts $fout [join [list $id $typeid $object_shape] ,] } close $fout I'm exploring using NRE to implement the foreach method. (I have a reference implementation that uses Tcl_EvalObj). And thusfar I've gotten it to play well with NRE. Except for one annoying show stopper. NRE only seems to pay attention to the last item I've loaded as a callback. Here's the foreach method in C: static int Entity_nodeeval_finalize( ClientData data[], Tcl_Interp *interp, int result ) { Entity *p; Tcl_Obj *pValueDict; int i; Tcl_Obj **varv; int varc; p=data[0]; pValueDict=data[1]; if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (body of \"Entity with/foreach \")"); } if(result!=TCL_OK) { if(pValueDict) { Tcl_DecrRefCount(pValueDict); } return result; } if (pValueDict) { int changed=0; if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) != TCL_OK) { return TCL_ERROR; } /* ** Read values back into the dict ** For now, we limit writeback to state variables ** And we don't care about garbage values */ for(i=0;i<varc;i+=2) { Tcl_Obj *newValue; int offset; int type; newValue=Tcl_ObjGetVar2(interp,varv[i],(Tcl_Obj *)NULL,0); if(newValue==varv[i+1]) { /* Undocumented, unsanctioned, but it works in practice ** If the pointer hasn't changed, neither has the value */ continue; } if(!newValue) { /* Variable must have been unset... move along */ continue; } if( Entity_ValueOffset(0, varv[i], &offset, &type) == TCL_OK ) { Entity_StructSet(interp,p,offset,newValue); changed=1; } else { Entity_DictPut(p,varv[i],newValue); } } if(changed) { Entity_ApplySettings(p); } } if(pValueDict) { Tcl_DecrRefCount(pValueDict); } return TCL_OK; } /* ** title: */ int Entity_nodeeval( Tcl_Interp *interp, Entity *p, Tcl_Obj *body ) { Tcl_Obj *pValueDict=NULL,*pIDDict=NULL,*pTypeDict=NULL; int i; Tcl_Obj **varv; int varc,result; pValueDict=Entity_ToDict(interp,p); if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) != TCL_OK) { return TCL_ERROR; } for(i=0;i<varc;i+=2) { Tcl_ObjSetVar2(interp, varv[i], (Tcl_Obj *)NULL, varv[i+1], 0); } pIDDict=Entity_Identify(p); pTypeDict=Entity_TypeId(p); Tcl_IncrRefCount(pValueDict); Tcl_ObjSetVar2(interp,constant_stringObj(interp,"id"),NULL,pIDDict, 0); Tcl_ObjSetVar2(interp,constant_stringObj(interp,"typeid"),NULL,pTypeDict, 0); Tcl_NRAddCallback(interp, Entity_nodeeval_finalize, p, pValueDict, NULL, NULL); return Tcl_NREvalObj(interp, body, 0); } So what is happening is when I open that dumpfile.csv I see N (where N is the number of objects in the container) lines of on element repeated. e212412,10121,box e212412,10121,box e212412,10121,box e212412,10121,box .... I'm guessing the problem is that my calls to Tcl_NRAddCallback are replacing each other. Is that the way it's supposed to work? --The Hypnotoad
From: Sean Woods on 9 Aug 2010 18:47 After some discussion, it turns out the problem was actually upstream of this C code. I was trying to call NRE from an old-style c function linked with Tcl_CreateCommand. If the upstream function were linked to the interpreter with Tcl_NRCreateCommand, it probably would have worked. (Barring some additional stupidity of mine in the calling routines.) On Aug 9, 6:02 pm, Sean Woods <y...(a)etoyoc.com> wrote: > Well Tclers, I have an interesting problem, and feel free to tell me > "Hypnotoad, that's not what NRE was designed for!" > > To speed up my Tcl code, I have several what I call "containers" that > map C data structures to Key/Value lists and back again. One of the > features I've found most handy are routines evaluates a script over > the entire table of data structures I have loaded. > > For a trivial example of what's going on at the Tcl level: > > set fout [open dumpfile.csv w] > entity foreach { puts $fout [join [list $id $typeid > $object_shape] ,] } > close $fout > > I'm exploring using NRE to implement the foreach method. (I have a > reference implementation that uses Tcl_EvalObj). And thusfar I've > gotten it to play well with NRE. Except for one annoying show stopper. > NRE only seems to pay attention to the last item I've loaded as a > callback. > > Here's the foreach method in C: > > static int Entity_nodeeval_finalize( > ClientData data[], > Tcl_Interp *interp, > int result > ) { > Entity *p; > Tcl_Obj *pValueDict; > int i; > Tcl_Obj **varv; > int varc; > > p=data[0]; > pValueDict=data[1]; > > if (result == TCL_ERROR) { > Tcl_AddErrorInfo(interp, "\n (body of \"Entity with/foreach > \")"); > } > if(result!=TCL_OK) { > if(pValueDict) { > Tcl_DecrRefCount(pValueDict); > } > return result; > } > if (pValueDict) { > int changed=0; > if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) != > TCL_OK) { > return TCL_ERROR; > } > /* > ** Read values back into the dict > ** For now, we limit writeback to state variables > ** And we don't care about garbage values > */ > for(i=0;i<varc;i+=2) { > Tcl_Obj *newValue; > int offset; > int type; > newValue=Tcl_ObjGetVar2(interp,varv[i],(Tcl_Obj *)NULL,0); > if(newValue==varv[i+1]) { > /* Undocumented, unsanctioned, but it works in practice > ** If the pointer hasn't changed, neither has the value > */ > continue; > } > if(!newValue) { > /* Variable must have been unset... move along */ > continue; > } > if( Entity_ValueOffset(0, varv[i], &offset, &type) == TCL_OK ) { > Entity_StructSet(interp,p,offset,newValue); > changed=1; > } else { > Entity_DictPut(p,varv[i],newValue); > } > } > if(changed) { > Entity_ApplySettings(p); > } > } > if(pValueDict) { > Tcl_DecrRefCount(pValueDict); > } > return TCL_OK; > > } > > /* > ** title: > */ > int Entity_nodeeval( > Tcl_Interp *interp, > Entity *p, > Tcl_Obj *body > ) { > Tcl_Obj *pValueDict=NULL,*pIDDict=NULL,*pTypeDict=NULL; > int i; > Tcl_Obj **varv; > int varc,result; > > pValueDict=Entity_ToDict(interp,p); > > if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) != > TCL_OK) { > return TCL_ERROR; > } > for(i=0;i<varc;i+=2) { > Tcl_ObjSetVar2(interp, varv[i], (Tcl_Obj *)NULL, varv[i+1], 0); > } > pIDDict=Entity_Identify(p); > pTypeDict=Entity_TypeId(p); > Tcl_IncrRefCount(pValueDict); > > Tcl_ObjSetVar2(interp,constant_stringObj(interp,"id"),NULL,pIDDict, > 0); > > Tcl_ObjSetVar2(interp,constant_stringObj(interp,"typeid"),NULL,pTypeDict, > 0); > > Tcl_NRAddCallback(interp, Entity_nodeeval_finalize, p, pValueDict, > NULL, NULL); > > return Tcl_NREvalObj(interp, body, 0); > > } > > So what is happening is when I open that dumpfile.csv I see N (where N > is the number of objects in the container) lines of on element > repeated. > > e212412,10121,box > e212412,10121,box > e212412,10121,box > e212412,10121,box > ... > > I'm guessing the problem is that my calls to Tcl_NRAddCallback are > replacing each other. Is that the way it's supposed to work? > > --The Hypnotoad
From: Robert Heller on 9 Aug 2010 20:30 At Mon, 9 Aug 2010 15:47:15 -0700 (PDT) Sean Woods <yoda(a)etoyoc.com> wrote: > > After some discussion, it turns out the problem was actually upstream > of this C code. > > I was trying to call NRE from an old-style c function linked with > Tcl_CreateCommand. > > If the upstream function were linked to the interpreter with > Tcl_NRCreateCommand, > it probably would have worked. (Barring some additional stupidity of > mine in the > calling routines.) I've implemented 'foreach' style loops over STL container objects (eg STL <map>, <vector>, etc.) in C++, using TclObj commands. They are interfaced to Tcl via SWIG (using C++/TclObj) and are part of my Model Railroad System. They work quite well. The Model Railroad System is open source and you are welcome to look at the code to see how I did things. The code is even reasonably documented. The URL is in my signature. > > On Aug 9, 6:02=A0pm, Sean Woods <y...(a)etoyoc.com> wrote: > > Well Tclers, I have an interesting problem, and feel free to tell me > > "Hypnotoad, that's not what NRE was designed for!" > > > > To speed up my Tcl code, I have several what I call "containers" that > > map C data structures to Key/Value lists and back again. One of the > > features I've found most handy are routines evaluates a script over > > the entire table of data structures I have loaded. > > > > For a trivial example of what's going on at the Tcl level: > > > > set fout [open dumpfile.csv w] > > entity foreach { puts $fout [join [list $id $typeid > > $object_shape] ,] } > > close $fout > > > > I'm exploring using NRE to implement the foreach method. (I have a > > reference implementation that uses Tcl_EvalObj). And thusfar I've > > gotten it to play well with NRE. Except for one annoying show stopper. > > NRE only seems to pay attention to the last item I've loaded as a > > callback. > > > > Here's the foreach method in C: > > > > static int =A0Entity_nodeeval_finalize( > > =A0 =A0 ClientData data[], > > =A0 =A0 Tcl_Interp *interp, > > =A0 =A0 int result > > ) { > > =A0 Entity *p; > > =A0 Tcl_Obj *pValueDict; > > =A0 int i; > > =A0 Tcl_Obj **varv; > > =A0 int varc; > > > > =A0 p=3Ddata[0]; > > =A0 pValueDict=3Ddata[1]; > > > > =A0 if (result =3D=3D TCL_ERROR) { > > =A0 =A0 Tcl_AddErrorInfo(interp, "\n =A0 =A0(body of \"Entity with/foreac= > h > > \")"); > > =A0 } > > =A0 if(result!=3DTCL_OK) { > > =A0 =A0 if(pValueDict) { > > =A0 =A0 =A0 Tcl_DecrRefCount(pValueDict); > > =A0 =A0 } > > =A0 =A0 return result; > > =A0 } > > =A0 if (pValueDict) { > > =A0 =A0 int changed=3D0; > > =A0 =A0 if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) !=3D > > TCL_OK) { > > =A0 =A0 =A0 return TCL_ERROR; > > =A0 =A0 } > > =A0 =A0 /* > > =A0 =A0 ** Read values back into the dict > > =A0 =A0 ** For now, we limit writeback to state variables > > =A0 =A0 ** And we don't care about garbage values > > =A0 =A0 */ > > =A0 =A0 for(i=3D0;i<varc;i+=3D2) { > > =A0 =A0 =A0 Tcl_Obj *newValue; > > =A0 =A0 =A0 int offset; > > =A0 =A0 =A0 int type; > > =A0 =A0 =A0 newValue=3DTcl_ObjGetVar2(interp,varv[i],(Tcl_Obj *)NULL,0); > > =A0 =A0 =A0 if(newValue=3D=3Dvarv[i+1]) { > > =A0 =A0 =A0 =A0 =A0/* Undocumented, unsanctioned, but it works in practic= > e > > =A0 =A0 =A0 =A0 =A0** If the pointer hasn't changed, neither has the valu= > e > > =A0 =A0 =A0 =A0 =A0*/ > > =A0 =A0 =A0 =A0 =A0continue; > > =A0 =A0 =A0 } > > =A0 =A0 =A0 if(!newValue) { > > =A0 =A0 =A0 =A0 /* Variable must have been unset... move along */ > > =A0 =A0 =A0 =A0 continue; > > =A0 =A0 =A0 } > > =A0 =A0 =A0 if( Entity_ValueOffset(0, varv[i], &offset, &type) =3D=3D TCL= > _OK ) { > > =A0 =A0 =A0 =A0 =A0 Entity_StructSet(interp,p,offset,newValue); > > =A0 =A0 =A0 =A0 =A0 changed=3D1; > > =A0 =A0 =A0 } else { > > =A0 =A0 =A0 =A0 Entity_DictPut(p,varv[i],newValue); > > =A0 =A0 =A0 } > > =A0 =A0 } > > =A0 =A0 if(changed) { > > =A0 =A0 =A0 Entity_ApplySettings(p); > > =A0 =A0 } > > =A0 } > > =A0 if(pValueDict) { > > =A0 =A0 Tcl_DecrRefCount(pValueDict); > > =A0 } > > =A0 return TCL_OK; > > > > } > > > > /* > > ** title: > > */ > > int Entity_nodeeval( > > =A0 Tcl_Interp *interp, > > =A0 Entity *p, > > =A0 Tcl_Obj *body > > ) { > > =A0 Tcl_Obj *pValueDict=3DNULL,*pIDDict=3DNULL,*pTypeDict=3DNULL; > > =A0 int i; > > =A0 Tcl_Obj **varv; > > =A0 int varc,result; > > > > =A0 pValueDict=3DEntity_ToDict(interp,p); > > > > =A0 if (Tcl_ListObjGetElements(interp, pValueDict, &varc, &varv) !=3D > > TCL_OK) { > > =A0 =A0 =A0 return TCL_ERROR; > > =A0 } > > =A0 for(i=3D0;i<varc;i+=3D2) { > > =A0 =A0 Tcl_ObjSetVar2(interp, varv[i], (Tcl_Obj *)NULL, varv[i+1], 0); > > =A0 } > > =A0 pIDDict=3DEntity_Identify(p); > > =A0 pTypeDict=3DEntity_TypeId(p); > > =A0 Tcl_IncrRefCount(pValueDict); > > > > =A0 Tcl_ObjSetVar2(interp,constant_stringObj(interp,"id"),NULL,pIDDict, > > 0); > > > > Tcl_ObjSetVar2(interp,constant_stringObj(interp,"typeid"),NULL,pTypeDict, > > 0); > > > > =A0 Tcl_NRAddCallback(interp, Entity_nodeeval_finalize, p, pValueDict, > > NULL, NULL); > > > > =A0 return Tcl_NREvalObj(interp, body, 0); > > > > } > > > > So what is happening is when I open that dumpfile.csv I see N (where N > > is the number of objects in the container) lines of on element > > repeated. > > > > e212412,10121,box > > e212412,10121,box > > e212412,10121,box > > e212412,10121,box > > ... > > > > I'm guessing the problem is that my calls to Tcl_NRAddCallback are > > replacing each other. Is that the way it's supposed to work? > > > > --The Hypnotoad > > -- Robert Heller -- 978-544-6933 Deepwoods Software -- Download the Model Railroad System http://www.deepsoft.com/ -- Binaries for Linux and MS-Windows heller(a)deepsoft.com -- http://www.deepsoft.com/ModelRailroadSystem/
From: Alexandre Ferrieux on 10 Aug 2010 07:33 On Aug 10, 12:02 am, Sean Woods <y...(a)etoyoc.com> wrote: > Well Tclers, I have an interesting problem, and feel free to tell me > "Hypnotoad, that's not what NRE was designed for!" > Hypnotoad, that's not what NRE was designed for ;-) Joke aside, are you sure NR-enabling will give you a huge speed ? Or do you have realistic scenarios with deeply nested operators ? -Alex
|
Pages: 1 Prev: namespace export and pkg_mkIndex Next: Expect & plink returnes special symbol |