diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tcl.h | 8 | ||||
-rw-r--r-- | generic/tclAbstractList.c | 73 | ||||
-rw-r--r-- | generic/tclAbstractList.h | 7 | ||||
-rwxr-xr-x | generic/tclArithSeries.c | 3 | ||||
-rw-r--r-- | generic/tclInt.h | 65 | ||||
-rw-r--r-- | generic/tclListObj.c | 5 |
6 files changed, 130 insertions, 31 deletions
diff --git a/generic/tcl.h b/generic/tcl.h index 203cfa6..0aaafb5 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -746,11 +746,15 @@ typedef void (Tcl_ALToStringRep) (struct Tcl_Obj *listPtr); typedef struct Tcl_Obj* (Tcl_ALSetElement) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, struct Tcl_Obj *indicies, struct Tcl_Obj *valueObj); +typedef int (Tcl_ALReplaceProc) (Tcl_Interp *interp, struct Tcl_Obj *listObj, + Tcl_WideInt first, Tcl_WideInt numToDelete, + Tcl_WideInt numToInsert, + struct Tcl_Obj *const insertObjs[]); typedef enum { TCL_ABSL_NEW, TCL_ABSL_DUPREP, TCL_ABSL_LENGTH, TCL_ABSL_INDEX, TCL_ABSL_SLICE, TCL_ABSL_REVERSE, TCL_ABSL_GETELEMENTS, TCL_ABSL_FREEREP, - TCL_ABSL_TOSTRING, TCL_ABSL_SETELEMENT + TCL_ABSL_TOSTRING, TCL_ABSL_SETELEMENT, TCL_ABSL_REPLACE } Tcl_AbstractListProcType; typedef struct Tcl_AbstractListVersion_ *Tcl_AbstractListVersion; @@ -873,6 +877,8 @@ typedef struct Tcl_AbstractListType { ** for updating the string rep */ Tcl_ALSetElement *setElementProc; /* Replace the element at the indicie ** with the given valueObj. */ + Tcl_ALReplaceProc *replaceProc; /* Replace subset with subset */ + } Tcl_AbstractListType; /* diff --git a/generic/tclAbstractList.c b/generic/tclAbstractList.c index 209e9ac..12dfe1f 100644 --- a/generic/tclAbstractList.c +++ b/generic/tclAbstractList.c @@ -663,6 +663,79 @@ Tcl_AbstractListSetElement( } return returnObj; } + +/* + *---------------------------------------------------------------------- + * + * Tcl_AbstractListObjReplace -- + * + * This function mimics the Tcl_ListObjReplace operation, iff the + * concrete abstract list type supports the Replace operation, and if + * not, it will return with an error. + * + * This function replaces zero or more elements of the abstract list + * referenced by listObj with the objects from an (objc,objv) array. The + * objc elements of the array referenced by objv replace the count + * elements in listPtr starting at first. + * + * If the argument first is zero or negative, it refers to the first + * element. If first is greater than or equal to the number of elements + * in the list, then no elements are deleted; the new elements are + * appended to the list. Count gives the number of elements to replace. + * If count is zero or negative then no elements are deleted; the new + * elements are simply inserted before first. + * + * The argument objv refers to an array of objc pointers to the new + * elements to be added to listPtr in place of those that were deleted. + * If objv is NULL, no new elements are added. + * + * Results: + * The return value is normally TCL_OK. If listPtr does not support the + * Replace opration then TCL_ERROR is returned and an error message will + * be left in the interpreter's result if interp is not NULL. + * + * Side effects: + * The ref counts of the objc elements in objv maybe incremented iff the + * concrete type retains a reference to the element(s), otherwise there + * will be no change to the ref counts. Similarly, the ref counts for + * replaced objects are decremented. listObj's old string representation, + * if any, is freed. + * + *---------------------------------------------------------------------- + */ +int Tcl_AbstractListObjReplace( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + Tcl_Obj *objPtr, /* List object whose elements to replace. */ + ListSizeT first, /* Index of first element to replace. */ + ListSizeT numToDelete, /* Number of elements to replace. */ + ListSizeT numToInsert, /* Number of objects to insert. */ + Tcl_Obj *const insertObjs[]) /* Tcl objects to insert */ +{ + int status; + if (TclHasInternalRep(objPtr,&tclAbstractListType)) { + Tcl_AbstractListType *typePtr = Tcl_AbstractListGetType(objPtr); + if (TclAbstractListHasProc(objPtr, TCL_ABSL_REPLACE)) { + status = typePtr->replaceProc(interp, objPtr, first, numToDelete, numToInsert, insertObjs); + } else { + if (interp) { + Tcl_SetObjResult( + interp, + Tcl_NewStringObj("Replace not supported!", -1)); + Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + } + status = TCL_ERROR; + } + } else { + if (interp != NULL) { + Tcl_SetObjResult( + interp, + Tcl_ObjPrintf("value is not an abstract list")); + Tcl_SetErrorCode(interp, "TCL", "VALUE", "UNKNOWN", NULL); + } + status = TCL_ERROR; + } + return status; +} /* * Local Variables: diff --git a/generic/tclAbstractList.h b/generic/tclAbstractList.h index 1c92b42..824a53d 100644 --- a/generic/tclAbstractList.h +++ b/generic/tclAbstractList.h @@ -43,6 +43,13 @@ Tcl_Obj * Tcl_AbstractListObjCopy(Tcl_Interp *interp, Tcl_Obj *listPtr); void * Tcl_AbstractListGetConcreteRep(Tcl_Obj *objPtr); Tcl_Obj * Tcl_AbstractListSetElement(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *indicies, Tcl_Obj *valueObj); +int Tcl_AbstractListObjReplace( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + Tcl_Obj *listObj, /* List object whose elements to replace. */ + ListSizeT first, /* Index of first element to replace. */ + ListSizeT numToDelete, /* Number of elements to replace. */ + ListSizeT numToInsert, /* Number of objects to insert. */ + Tcl_Obj *const insertObjs[]); /* Tcl objects to insert */ #endif diff --git a/generic/tclArithSeries.c b/generic/tclArithSeries.c index 445088b..255b0de 100755 --- a/generic/tclArithSeries.c +++ b/generic/tclArithSeries.c @@ -80,7 +80,8 @@ static Tcl_AbstractListType arithSeriesType = { TclArithSeriesGetElements, FreeArithSeriesRep, UpdateStringOfArithSeries, - NULL + NULL, // SetElement + NULL // Replace }; /* diff --git a/generic/tclInt.h b/generic/tclInt.h index d2ad1af..99ba3cf 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -2655,35 +2655,6 @@ AbstractListObjLength(Tcl_Obj* abstractListObjPtr) return typePtr->lengthProc(abstractListObjPtr); } -static inline int -TclAbstractListHasProc(Tcl_Obj* abstractListObjPtr, Tcl_AbstractListProcType ptype) -{ - Tcl_AbstractListType *typePtr = AbstractListGetType(abstractListObjPtr); - switch (ptype) { - case TCL_ABSL_NEW: - return (typePtr->newObjProc != NULL); - case TCL_ABSL_DUPREP: - return (typePtr->dupRepProc != NULL); - case TCL_ABSL_LENGTH: - return (typePtr->lengthProc != NULL); - case TCL_ABSL_INDEX: - return (typePtr->indexProc != NULL); - case TCL_ABSL_SLICE: - return (typePtr->sliceProc != NULL); - case TCL_ABSL_REVERSE: - return (typePtr->reverseProc != NULL); - case TCL_ABSL_GETELEMENTS: - return (typePtr->getElementsProc != NULL); - case TCL_ABSL_FREEREP: - return (typePtr->freeRepProc != NULL); - case TCL_ABSL_TOSTRING: - return (typePtr->toStringProc != NULL); - case TCL_ABSL_SETELEMENT: - return (typePtr->setElementProc != NULL); - } - return 0; -} - /* * Modes for collecting (or not) in the implementations of TclNRForeachCmd, * TclNRLmapCmd and their compilations. @@ -4789,6 +4760,42 @@ MODULE_SCOPE int TclIsPureByteArray(Tcl_Obj *objPtr); #define TclFetchInternalRep(objPtr, type) \ (TclHasInternalRep((objPtr), (type)) ? &((objPtr)->internalRep) : NULL) +static inline int +TclAbstractListHasProc(Tcl_Obj* abstractListObjPtr, Tcl_AbstractListProcType ptype) +{ + Tcl_AbstractListType *typePtr; + if ( ! TclHasInternalRep(abstractListObjPtr,&tclAbstractListType)) { + return 0; + } + typePtr = AbstractListGetType(abstractListObjPtr); + switch (ptype) { + case TCL_ABSL_NEW: + return (typePtr->newObjProc != NULL); + case TCL_ABSL_DUPREP: + return (typePtr->dupRepProc != NULL); + case TCL_ABSL_LENGTH: + return (typePtr->lengthProc != NULL); + case TCL_ABSL_INDEX: + return (typePtr->indexProc != NULL); + case TCL_ABSL_SLICE: + return (typePtr->sliceProc != NULL); + case TCL_ABSL_REVERSE: + return (typePtr->reverseProc != NULL); + case TCL_ABSL_GETELEMENTS: + return (typePtr->getElementsProc != NULL); + case TCL_ABSL_FREEREP: + return (typePtr->freeRepProc != NULL); + case TCL_ABSL_TOSTRING: + return (typePtr->toStringProc != NULL); + case TCL_ABSL_SETELEMENT: + return (typePtr->setElementProc != NULL); + case TCL_ABSL_REPLACE: + return (typePtr->replaceProc != NULL); + } + return 0; +} + + /* *---------------------------------------------------------------- diff --git a/generic/tclListObj.c b/generic/tclListObj.c index 5fe3819..f29b120 100644 --- a/generic/tclListObj.c +++ b/generic/tclListObj.c @@ -2087,6 +2087,11 @@ Tcl_ListObjReplace( Tcl_Panic("%s called with shared object", "Tcl_ListObjReplace"); } + if (TclAbstractListHasProc(listObj, TCL_ABSL_REPLACE)) { + return Tcl_AbstractListObjReplace(interp, listObj, first, + numToDelete, numToInsert, insertObjs); + } + if (TclListObjGetRep(interp, listObj, &listRep) != TCL_OK) return TCL_ERROR; /* Cannot be converted to a list */ |