如何使用Critcl设置参数指向的数据?

如何使用Critcl设置参数指向的数据?,tcl,Tcl,我想用这样的话来表达: 我特别关注如何在Critcl中处理int*grid对象字节?也许是定制的 与相关。该案例与Tcl的价值模型不太吻合。问题在于grid是(指向)可更新值集合的指针。在Tcl中,通常有两种建模方法: 作为不透明的物体 作为包含Tcl列表的变量(因为在模型术语中,Tcl值被认为是不可变的,而Tcl变量是可变的) 我将在下面描述如何实现这两种功能,但我猜您将把这些zOrder功能看作是一种独特的可变类型,而定制类型的额外一次性开销将更适合您 不透明(可变)对象 在处理不透明对象时

我想用这样的话来表达:

我特别关注如何在Critcl中处理
int*grid
<代码>对象<代码>字节?也许是定制的


与相关。

该案例与Tcl的价值模型不太吻合。问题在于
grid
是(指向)可更新值集合的指针。在Tcl中,通常有两种建模方法:

  • 作为不透明的物体
  • 作为包含Tcl列表的变量(因为在模型术语中,Tcl值被认为是不可变的,而Tcl变量是可变的)
  • 我将在下面描述如何实现这两种功能,但我猜您将把这些zOrder功能看作是一种独特的可变类型,而定制类型的额外一次性开销将更适合您

    不透明(可变)对象 在处理不透明对象时,将句柄传递给它们(基本上只是一个名称),然后将它们作为一个对象进行解压缩。诀窍是在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数组的删除函数留作练习。)

    Tcl列表变量 另一种方法是将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;
    }
    
    critcl::cproc setter{Tcl_Interp*Interp object varName int value int x int y}确定{
    /*从变量中解压缩整数列表*/
    Tcl_Obj*listObj=Tcl_ObjGetVar2(interp,varName,NULL,Tcl_LEAVE_ERR_MSG);
    if(listObj==NULL)
    返回TCL_错误;
    Tcl_Obj**listv;int listc;
    if(Tcl_ListObjGetElements(interp、listObj、listc和listv)!=Tcl_确定)
    返回TCL_错误;
    int*grid=alloca(sizeof(int)*listc);
    
    对于(inti=0;iYes),这需要我编写大量代码。将可变性映射到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;
    }