我想在Critcl中表达如下内容:
void setter(int* grid, int value, int x, int y) {
grid[xy2addr(x,y)] = value;
}
我特别关注如何处理Critcl中的int* grid
。 object
? bytes
?可能是自定义类型?
与this question有关。
答案 0 :(得分:2)
这种情况不能很好地映射到Tcl的价值模型。问题是grid
是(指向)可更新的值集合。通常,在Tcl中有两种建模方法:
我将在下面描述如何完成这两项操作,但是我猜想您将把这些zOrder事物视为一种独特的可变类型,并且使定制类型产生的额外适度的一次性开销将会更适合您。
在处理不透明对象时,将句柄传递给它们(基本上只是一个名称),然后将它们解压缩为custom Critcl type。诀窍是在C中创建一些辅助函数来进行映射(可以在critcl::ccode
命令中进行),该映射完成名称和指针之间的映射。这样做有点杂乱无章,但只是要构建几个哈希表。
critcl::ccode {
static Tcl_HashTable *zOrderMap = NULL, *zOrderRevMap = NULL;
static Tcl_Obj *
MakeZOrderObj(int *zOrder) {
/* Initialize the two maps, if needed */
if (zOrderMap == NULL) {
zOrderMap = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(zOrderMap);
zOrderRevMap = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(zOrderRevMap, TCL_ONE_WORD_KEYS);
}
int isNew;
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(zOrderRevMap, (char*) zOrder, &isNew);
if (!isNew) {
return Tcl_GetHashValue(hPtr);
}
/* make a handle! */
Tcl_Obj *handle = Tcl_ObjPrintf("zOrder%ld", (long) zOrder);
Tcl_SetHashValue(hPtr, handle);
Tcl_IncrRefCount(handle);
hPtr = Tcl_CreateHashEntry(zOrderMap, (char*) handle, &isNew);
Tcl_SetHashValue(hPtr, zOrder);
return handle;
}
static int
GetZOrderFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int **zOrderPtr) {
Tcl_HashTable *hPtr;
if (!zOrderMap || (hPtr = Tcl_FindHashEntry(zOrderMap, (char *) objPtr)) == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("no such zOrder \"%s\"",
Tcl_GetString(objPtr)));
return TCL_ERROR;
}
*zOrderPtr = (int *) Tcl_GetHashValue(hPtr);
return TCL_OK;
}
}
使用该辅助代码后,您可以定义一个自定义Critcl类型,如下所示:
critcl::argtype zOrder {
if (GetZOrderFromObj(interp, @@, @A) != TCL_OK) {
return TCL_ERROR;
}
} int*
critcl::resulttype zOrder {
if (rv == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, MakeZOrderObj(rv));
return TCL_OK;
} int*
然后,您可以像这样写真实的代码。请注意,grid
被定义为zOrder
(自定义)类型,并且只能由返回zOrder
作为其结果的某些代码来制造。
critcl::cproc setter {zOrder grid int value int x int y} void {
grid[xy2addr(x,y)] = value;
}
(练习中保留了从哈希表中删除条目并删除C数组的删除功能。)
另一种方法是使zOrder值作为整数列表保存在Tcl变量中。这样做很不错,因为它使您可以轻松地查看内部,但是在其他方面也可能不太理想,因为代码没有受到约束的约束以使用适当的值,并且您将cproc暴露给更多细节Tcl中发生的事情。
critcl::cproc setter {Tcl_Interp* interp object varName int value int x int y} ok {
/* Unpack the list of ints from the variable */
Tcl_Obj *listObj = Tcl_ObjGetVar2(interp, varName, NULL, TCL_LEAVE_ERR_MSG);
if (listObj == NULL)
return TCL_ERROR;
Tcl_Obj **listv; int listc;
if (Tcl_ListObjGetElements(interp, listObj, &listc, &listv) != TCL_OK)
return TCL_ERROR;
int *grid = alloca(sizeof(int) * listc);
for (int i=0; i<listc; i++)
if (Tcl_GetIntFromObj(interp, listv[i], &grid[i]) != TCL_OK)
return TCL_ERROR;
/* The core of the functionality */
grid[xy2addr(x,y)] = value;
/* Repack the list of ints from the variable; this code could be optimized in this case! */
for (int i=0; i<listc; i++)
listv[i] = Tcl_NewIntObj(grid[i]);
listObj = Tcl_NewListObj(listc, listv);
Tcl_ObjSetVar2(interp, varName, NULL, listObj, 0);
return TCL_OK;
}