Tcl Source Code

Artifact [5e4157c232]
Login

Artifact 5e4157c232b0f885b40eba79d57fb4daa4ac0b4b:

Attachment "range3.patch" to ticket [1052584fff] added by antirez 2004-10-24 16:34:19.
? foo.ps
? unix/dltest.marker
Index: generic/tcl.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tcl.decls,v
retrieving revision 1.104
diff -u -r1.104 tcl.decls
--- generic/tcl.decls	13 May 2004 12:59:20 -0000	1.104
+++ generic/tcl.decls	24 Oct 2004 09:31:18 -0000
@@ -1909,6 +1909,17 @@
 declare 534 generic {
     int Tcl_LimitGetGranularity(Tcl_Interp *interp, int type)
 }
+declare 535 generic {
+    Tcl_Obj * Tcl_NewArithSeriesObj(Tcl_WideInt start,
+	    Tcl_WideInt end, Tcl_WideInt step)
+}
+declare 536 generic {
+    int Tcl_ArithSeriesObjIndex(Tcl_Obj *arithSeriesPtr, Tcl_WideInt index,
+            Tcl_WideInt *element)
+}
+declare 537 generic {
+    Tcl_WideInt Tcl_ArithSeriesObjLength(Tcl_Obj *arithSeriesPtr)
+}
 
 ##############################################################################
 
Index: generic/tclBasic.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBasic.c,v
retrieving revision 1.132
diff -u -r1.132 tclBasic.c
--- generic/tclBasic.c	21 Oct 2004 17:07:31 -0000	1.132
+++ generic/tclBasic.c	24 Oct 2004 09:31:25 -0000
@@ -94,6 +94,7 @@
     {"namespace",	Tcl_NamespaceObjCmd,	(CompileProc *) NULL,	1},
     {"package",		Tcl_PackageObjCmd,	(CompileProc *) NULL,	1},
     {"proc",		Tcl_ProcObjCmd,		(CompileProc *) NULL,	1},
+    {"range",		Tcl_RangeObjCmd,	(CompileProc *) NULL,	1},
     {"regexp",		Tcl_RegexpObjCmd,	TclCompileRegexpCmd,	1},
     {"regsub",		Tcl_RegsubObjCmd,	(CompileProc *) NULL,	1},
     {"rename",		Tcl_RenameObjCmd,	(CompileProc *) NULL,	1},
Index: generic/tclCmdAH.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdAH.c,v
retrieving revision 1.56
diff -u -r1.56 tclCmdAH.c
--- generic/tclCmdAH.c	21 Oct 2004 15:19:46 -0000	1.56
+++ generic/tclCmdAH.c	24 Oct 2004 09:31:29 -0000
@@ -1767,10 +1767,14 @@
 	    goto done;
 	}
 
-	result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
-	        &argcList[i], &argvList[i]);
-	if (result != TCL_OK) {
-	    goto done;
+	if (argObjv[2+i*2]->typePtr != &tclArithSeriesType) {
+	    result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
+			&argcList[i], &argvList[i]);
+	    if (result != TCL_OK) {
+	        goto done;
+	    }
+	} else {
+	    argcList[i] = (int) Tcl_ArithSeriesObjLength(argObjv[2+i*2]);
 	}
 
 	j = argcList[i] / varcList[i];
@@ -1804,10 +1808,14 @@
 	    if (result != TCL_OK) {
 		Tcl_Panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i);
 	    }
-	    result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
-		    &argcList[i], &argvList[i]);
-	    if (result != TCL_OK) {
-		Tcl_Panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i);
+	    if (argObjv[2+i*2]->typePtr != &tclArithSeriesType) {
+	        result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
+		        &argcList[i], &argvList[i]);
+	        if (result != TCL_OK) {
+		    Tcl_Panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i);
+	        }
+	    } else {
+		argcList[i] = (int) Tcl_ArithSeriesObjLength(argObjv[2+i*2]);
 	    }
 
 	    for (v = 0;  v < varcList[i];  v++) {
@@ -1816,7 +1824,14 @@
 		int isEmptyObj = 0;
 
 		if (k < argcList[i]) {
-		    valuePtr = argvList[i][k];
+		    if (argObjv[2+i*2]->typePtr != &tclArithSeriesType) {
+		    	valuePtr = argvList[i][k];
+		    } else {
+			ArithSeries *arithSeriesRepPtr =
+				argObjv[2+i*2]->internalRep.twoPtrValue.ptr1;
+			valuePtr = Tcl_NewWideIntObj(arithSeriesRepPtr->start+
+					(k*arithSeriesRepPtr->step));
+		    }
 		} else {
 		    valuePtr = Tcl_NewObj(); /* empty string */
 		    isEmptyObj = 1;
Index: generic/tclCmdIL.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdIL.c,v
retrieving revision 1.66
diff -u -r1.66 tclCmdIL.c
--- generic/tclCmdIL.c	14 Oct 2004 17:20:11 -0000	1.66
+++ generic/tclCmdIL.c	24 Oct 2004 09:31:35 -0000
@@ -2344,6 +2344,31 @@
 
     if (argPtr->typePtr != &tclListType 
 	    && TclGetIntForIndex(NULL , argPtr, 0, &index) == TCL_OK) {
+
+	/* If the list is an arithmetic series return the
+	 * computed element. */
+        if (listPtr->typePtr == &tclArithSeriesType) {
+	    Tcl_Obj *widePtr;
+	    Tcl_WideInt wideVal, asLen;
+
+	    /* Parse the index */
+	    asLen = Tcl_ArithSeriesObjLength(listPtr);
+	    result = TclGetIntForIndex(interp, argPtr,
+			    /*endValue*/ asLen-1, &index);
+	    if (result != TCL_OK) return NULL;
+
+	    /* Return the computed wideInt object */
+	    if (Tcl_ArithSeriesObjIndex(listPtr, index, &wideVal) == TCL_OK)
+	    {
+	        widePtr = Tcl_NewWideIntObj(wideVal);
+            } else {
+		/* Index out of range case */
+		widePtr = Tcl_NewObj();
+	    }
+	    Tcl_IncrRefCount(widePtr);
+	    return widePtr;
+	}
+
 	/*
 	 * argPtr designates a single index.
 	 */
@@ -2728,6 +2753,11 @@
 	return TCL_ERROR;
     }
 
+    if (objv[1]->typePtr == &tclArithSeriesType) {
+	    Tcl_SetObjResult(interp,
+		Tcl_NewWideIntObj(Tcl_ArithSeriesObjLength(objv[1])));
+	    return TCL_OK;
+    }
     result = Tcl_ListObjLength(interp, objv[1], &listLen);
     if (result != TCL_OK) {
 	return result;
@@ -3647,6 +3677,83 @@
     return TCL_OK;
 }
 
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_RangeObjCmd --
+ *
+ * 	This procedure returns a list where every element is
+ * 	part of an arithmetic sequence starting with the number START,
+ * 	incrementing the next elements of STEP, and including
+ * 	all the elements < END (or > END for negative steps).
+ * 	The command returns a specialized object able to represent
+ * 	this lists in constant space (the Arithmetic Sequence object type).
+ * 	See Tcl_ListObj.c for more information on this object.
+ *
+ * Results:
+ *	A standard Tcl result.
+ *
+ * Side effects:
+ *	See the user documentation.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_RangeObjCmd( clientData, interp, objc, objv )
+    ClientData clientData;	/* Not used. */
+    Tcl_Interp *interp;		/* Current interpreter. */
+    int objc;			/* Number of arguments. */
+    Tcl_Obj *CONST objv[];	/* Argument values. */
+{
+    Tcl_WideInt start = 0, end, step = 1;
+    Tcl_Obj *arithSeriesPtr;
+
+    /* Check parameter count */
+
+    if (objc < 2 || objc > 4) {
+	Tcl_WrongNumArgs(interp, 1, objv, "?start? end ?step?");
+	return TCL_ERROR;
+    }
+
+    /* Get the start, end, step parameters from arguments */
+    if (objc == 2) {
+	    if (Tcl_GetWideIntFromObj(interp, objv[1], &end) != TCL_OK)
+		    return TCL_ERROR;
+    } else if (objc >= 3) {
+	    if (Tcl_GetWideIntFromObj(interp, objv[1], &start) != TCL_OK ||
+		Tcl_GetWideIntFromObj(interp, objv[2], &end) != TCL_OK)
+		    return TCL_ERROR;
+	    if (objc == 4 &&
+		Tcl_GetWideIntFromObj(interp, objv[3], &step) != TCL_OK)
+		    return TCL_ERROR;
+    }
+
+    /* Create the arithmetic series object, checking if the
+     * parameters are invalid. */
+
+    arithSeriesPtr = Tcl_NewArithSeriesObj(start, end, step);
+    if (arithSeriesPtr == NULL) {
+	Tcl_AppendResult(interp,
+		"Invalid (infinite?) arithmetic sequence specified", NULL);
+	return TCL_ERROR;
+    }
+
+    Tcl_IncrRefCount(arithSeriesPtr); /* we may use DecrRefCount to free it */
+    if (Tcl_ArithSeriesObjLength(arithSeriesPtr) > INT_MAX/sizeof(Tcl_Obj *)) {
+	Tcl_DecrRefCount(arithSeriesPtr);
+	Tcl_AppendResult(interp, "overflow of maximum list length", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Return the new object. */
+
+    Tcl_SetObjResult(interp, arithSeriesPtr);
+    Tcl_DecrRefCount(arithSeriesPtr);
+    return TCL_OK;
+}
+
 /*
  *----------------------------------------------------------------------
  *
Index: generic/tclDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclDecls.h,v
retrieving revision 1.105
diff -u -r1.105 tclDecls.h
--- generic/tclDecls.h	7 Jun 2004 16:48:44 -0000	1.105
+++ generic/tclDecls.h	24 Oct 2004 09:31:49 -0000
@@ -3314,6 +3314,25 @@
 EXTERN int		Tcl_LimitGetGranularity _ANSI_ARGS_((
 				Tcl_Interp * interp, int type));
 #endif
+#ifndef Tcl_NewArithSeriesObj_TCL_DECLARED
+#define Tcl_NewArithSeriesObj_TCL_DECLARED
+/* 535 */
+EXTERN Tcl_Obj *	Tcl_NewArithSeriesObj _ANSI_ARGS_((Tcl_WideInt start, 
+				Tcl_WideInt end, Tcl_WideInt step));
+#endif
+#ifndef Tcl_ArithSeriesObjIndex_TCL_DECLARED
+#define Tcl_ArithSeriesObjIndex_TCL_DECLARED
+/* 536 */
+EXTERN int		Tcl_ArithSeriesObjIndex _ANSI_ARGS_((
+				Tcl_Obj * arithSeriesPtr, Tcl_WideInt index, 
+				Tcl_WideInt * element));
+#endif
+#ifndef Tcl_ArithSeriesObjLength_TCL_DECLARED
+#define Tcl_ArithSeriesObjLength_TCL_DECLARED
+/* 537 */
+EXTERN Tcl_WideInt	Tcl_ArithSeriesObjLength _ANSI_ARGS_((
+				Tcl_Obj * arithSeriesPtr));
+#endif
 
 typedef struct TclStubHooks {
     struct TclPlatStubs *tclPlatStubs;
@@ -3890,6 +3909,9 @@
     int (*tcl_LimitGetCommands) _ANSI_ARGS_((Tcl_Interp * interp)); /* 532 */
     void (*tcl_LimitGetTime) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Time * timeLimitPtr)); /* 533 */
     int (*tcl_LimitGetGranularity) _ANSI_ARGS_((Tcl_Interp * interp, int type)); /* 534 */
+    Tcl_Obj * (*tcl_NewArithSeriesObj) _ANSI_ARGS_((Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step)); /* 535 */
+    int (*tcl_ArithSeriesObjIndex) _ANSI_ARGS_((Tcl_Obj * arithSeriesPtr, Tcl_WideInt index, Tcl_WideInt * element)); /* 536 */
+    Tcl_WideInt (*tcl_ArithSeriesObjLength) _ANSI_ARGS_((Tcl_Obj * arithSeriesPtr)); /* 537 */
 } TclStubs;
 
 #ifdef __cplusplus
@@ -6070,6 +6092,18 @@
 #define Tcl_LimitGetGranularity \
 	(tclStubsPtr->tcl_LimitGetGranularity) /* 534 */
 #endif
+#ifndef Tcl_NewArithSeriesObj
+#define Tcl_NewArithSeriesObj \
+	(tclStubsPtr->tcl_NewArithSeriesObj) /* 535 */
+#endif
+#ifndef Tcl_ArithSeriesObjIndex
+#define Tcl_ArithSeriesObjIndex \
+	(tclStubsPtr->tcl_ArithSeriesObjIndex) /* 536 */
+#endif
+#ifndef Tcl_ArithSeriesObjLength
+#define Tcl_ArithSeriesObjLength \
+	(tclStubsPtr->tcl_ArithSeriesObjLength) /* 537 */
+#endif
 
 #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
 
Index: generic/tclExecute.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclExecute.c,v
retrieving revision 1.160
diff -u -r1.160 tclExecute.c
--- generic/tclExecute.c	22 Oct 2004 14:01:00 -0000	1.160
+++ generic/tclExecute.c	24 Oct 2004 09:31:59 -0000
@@ -2610,13 +2610,18 @@
 	    
 	    valuePtr = *tosPtr;
 
-	    result = Tcl_ListObjLength(interp, valuePtr, &length);
-	    if (result != TCL_OK) {
-		TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
-			Tcl_GetObjResult(interp));
-		goto checkForCatch;
+	    if (valuePtr->typePtr == &tclArithSeriesType) {
+	        objResultPtr = Tcl_NewWideIntObj(
+				Tcl_ArithSeriesObjLength(valuePtr));
+	    } else {
+	        result = Tcl_ListObjLength(interp, valuePtr, &length);
+	        if (result != TCL_OK) {
+		    TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
+			    Tcl_GetObjResult(interp));
+		    goto checkForCatch;
+	        }
+	        objResultPtr = Tcl_NewIntObj(length);
 	    }
-	    objResultPtr = Tcl_NewIntObj(length);
 	    TRACE(("%.20s => %d\n", O2S(valuePtr), length));
 	    NEXT_INST_F(1, 1, 1);
 	}
@@ -4562,6 +4567,7 @@
 	    int numLists;
 	    Tcl_Obj *listPtr,*valuePtr, *value2Ptr;
 	    List *listRepPtr;
+	    ArithSeries *arithSeriesRepPtr;
 	    Var *iterVarPtr, *listVarPtr;
 	    int iterNum, listTmpIndex, listLen, numVars;
 	    int varIndex, valIndex, continueLoop, j;
@@ -4596,7 +4602,12 @@
 		    
 		listVarPtr = &(compiledLocals[listTmpIndex]);
 		listPtr = listVarPtr->value.objPtr;
-		result = Tcl_ListObjLength(interp, listPtr, &listLen);
+		if (listPtr->typePtr == &tclArithSeriesType) {
+			listLen = (int) Tcl_ArithSeriesObjLength(listPtr);
+			result = TCL_OK; /* Tcl_ArithSeriesLength can't fail */
+		} else {
+			result = Tcl_ListObjLength(interp, listPtr, &listLen);
+		}
 		if (result != TCL_OK) {
 		    TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ",
 		            opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
@@ -4624,27 +4635,70 @@
 		    listVarPtr = &(compiledLocals[listTmpIndex]);
 		    listPtr = listVarPtr->value.objPtr;
 		    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
-		    listLen = listRepPtr->elemCount;
+		    arithSeriesRepPtr = (ArithSeries *) listRepPtr;
+		    if (listPtr->typePtr == &tclListType) {
+		    	listLen = listRepPtr->elemCount;
+		    } else {
+			listLen = arithSeriesRepPtr->len;
+		    }
 			
 		    valIndex = (iterNum * numVars);
 		    for (j = 0;  j < numVars;  j++) {
-			int setEmptyStr = 0;
-			if (valIndex >= listLen) {
-			    setEmptyStr = 1;
-			    TclNewObj(valuePtr);
-			} else {
-			    valuePtr = listRepPtr->elements[valIndex];
-			}
-			    
+			int setEmptyStr = 0, inlineVarAccess = 0;
+
 			varIndex = varListPtr->varIndexes[j];
 			varPtr = &(compiledLocals[varIndex]);
 			part1 = varPtr->name;
 			while (TclIsVarLink(varPtr)) {
 			    varPtr = varPtr->value.linkPtr;
 			}
-			if (!((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL))
-			        && (varPtr->tracePtr == NULL)
-			        && (TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr))) {
+			if (!((varPtr->flags & VAR_IN_HASHTABLE) &&
+				(varPtr->hPtr == NULL))
+				&& (varPtr->tracePtr == NULL)
+				&& (TclIsVarScalar(varPtr) ||
+					TclIsVarUndefined(varPtr)))
+			{
+			    inlineVarAccess = 1;
+			}
+
+			if (valIndex >= listLen) {
+			    setEmptyStr = 1;
+			    TclNewObj(valuePtr);
+			} else {
+			    if(listPtr->typePtr == &tclListType) {
+			        valuePtr = listRepPtr->elements[valIndex];
+			    } else {
+				/* If possible we kill the reference
+				 * in the var ASAP, in order to be sure
+				 * that the arithSeries Wide object is not
+				 * shared just becaues of it. */
+				if (inlineVarAccess) {
+				    if (varPtr->value.objPtr ==
+				        arithSeriesRepPtr->wideObjPtr)
+				    {
+					Tcl_DecrRefCount(varPtr->value.objPtr);
+					varPtr->value.objPtr = NULL;
+				    }
+				}
+				/* Try to reuse the same object for every
+				 * interation. */
+				if (arithSeriesRepPtr->wideObjPtr->typePtr !=
+						&tclWideIntType ||
+				    Tcl_IsShared(arithSeriesRepPtr->wideObjPtr))
+				{
+				    Tcl_DecrRefCount(arithSeriesRepPtr->wideObjPtr);
+				    arithSeriesRepPtr->wideObjPtr = Tcl_NewWideIntObj(0);
+				    Tcl_IncrRefCount(arithSeriesRepPtr->wideObjPtr);
+				}
+				valuePtr = arithSeriesRepPtr->wideObjPtr;
+				valuePtr->internalRep.wideValue =
+					arithSeriesRepPtr->start+
+					(valIndex*arithSeriesRepPtr->step);
+	    			Tcl_InvalidateStringRep(valuePtr);
+			    }
+			}
+			    
+			if (inlineVarAccess) {
 			    value2Ptr = varPtr->value.objPtr;
 			    if (valuePtr != value2Ptr) {
 				if (value2Ptr != NULL) {
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.186
diff -u -r1.186 tclInt.h
--- generic/tclInt.h	21 Oct 2004 17:07:31 -0000	1.186
+++ generic/tclInt.h	24 Oct 2004 09:32:05 -0000
@@ -1537,6 +1537,19 @@
 } List;
 
 /*
+ * The structure used for the AirthSeries internal representation.
+ * Note that the len can in theory be always computed by start,end,step
+ * but it's faster to cache it inside the internal representation.
+ */
+typedef struct ArithSeries {
+    Tcl_WideInt start;
+    Tcl_WideInt end;
+    Tcl_WideInt step;
+    Tcl_WideInt len;
+    Tcl_Obj *wideObjPtr; /* Used to speedup [foreach] reusing the same obj. */
+} ArithSeries;
+
+/*
  *----------------------------------------------------------------
  * Data structures related to the filesystem internals
  *----------------------------------------------------------------
@@ -1642,6 +1655,7 @@
 extern Tcl_ObjType	tclEndOffsetType;
 extern Tcl_ObjType	tclIntType;
 extern Tcl_ObjType	tclListType;
+extern Tcl_ObjType	tclArithSeriesType;
 extern Tcl_ObjType	tclDictType;
 extern Tcl_ObjType	tclProcBodyType;
 extern Tcl_ObjType	tclStringType;
@@ -2062,6 +2076,8 @@
 		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
 EXTERN int	Tcl_PwdObjCmd _ANSI_ARGS_((ClientData clientData,
 		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
+EXTERN int	Tcl_RangeObjCmd _ANSI_ARGS_((ClientData clientData,
+		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
 EXTERN int	Tcl_ReadObjCmd _ANSI_ARGS_((ClientData clientData,
 		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
 EXTERN int	Tcl_RegexpObjCmd _ANSI_ARGS_((ClientData clientData,
Index: generic/tclListObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclListObj.c,v
retrieving revision 1.19
diff -u -r1.19 tclListObj.c
--- generic/tclListObj.c	29 Sep 2004 22:17:30 -0000	1.19
+++ generic/tclListObj.c	24 Oct 2004 09:32:09 -0000
@@ -1566,6 +1566,33 @@
     List *listRepPtr;
 
     /*
+     * Convertion from Arithmetic Series is a special case
+     * because it can be done an order of magnitude faster
+     * and may occur frequently.
+     */
+    if (objPtr->typePtr == &tclArithSeriesType) {
+        Tcl_WideInt wideLen = Tcl_ArithSeriesObjLength(objPtr), j;
+        ArithSeries *arithSeriesRepPtr = (ArithSeries*)
+		objPtr->internalRep.twoPtrValue.ptr1;
+
+	elemPtrs = (Tcl_Obj**) ckalloc(sizeof(Tcl_Obj*)*wideLen);
+	for (j = 0; j < wideLen; j++) {
+		elemPtrs[j] = Tcl_NewWideIntObj(
+			arithSeriesRepPtr->start+(j*arithSeriesRepPtr->step));
+	}
+        listRepPtr = (List *) ckalloc(sizeof(List));
+        listRepPtr->maxElemCount = wideLen;
+        listRepPtr->elemCount    = wideLen;
+        listRepPtr->elements     = elemPtrs;
+
+        TclFreeIntRep(objPtr);
+        objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
+        objPtr->internalRep.twoPtrValue.ptr2 = NULL;
+        objPtr->typePtr = &tclListType;
+	return TCL_OK;
+    }
+
+    /*
      * Get the string representation. Make it up-to-date if necessary.
      */
 
@@ -1733,3 +1760,372 @@
     }
     listPtr->length = dst - listPtr->bytes;
 }
+
+/* -------------------------- ArithSeries object ---------------------------- */
+
+/*
+ * Prototypes for procedures defined later in this file:
+ */
+
+static void		DupArithSeriesInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
+			    Tcl_Obj *copyPtr));
+static void		FreeArithSeriesInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr));
+static int		SetArithSeriesFromAny _ANSI_ARGS_((Tcl_Interp *interp,
+			    Tcl_Obj *objPtr));
+static void		UpdateStringOfArithSeries _ANSI_ARGS_((Tcl_Obj *listPtr));
+
+/*
+ * The structure below defines the arithmetic series Tcl object type by
+ * means of procedures that can be invoked by generic object code.
+ *
+ * The arithmetic series object is a special case of Tcl list representing
+ * an interval of an arithmetic series in constant space.
+ * 
+ * The arithmetic series is internally represented with three integers,
+ * *start*, *end*, and *step*, Where the length is calculated with
+ * the following algorithm:
+ *
+ * if RANGE == 0 THEN
+ *   ERROR
+ * if RANGE > 0
+ *   LEN is (((END-START)-1)/STEP) + 1
+ * else if RANGE < 0
+ *   LEN is (((END-START)-1)/STEP) - 1
+ *
+ * And where the equivalent's list I-th element is calculated
+ * as:
+ *
+ * LIST[i] = START+(STEP*i)
+ *
+ * Zero elements ranges, like in the case of START=10 END=10 STEP=1
+ * are valid and will be equivalent to the empty list.
+ */
+
+Tcl_ObjType tclArithSeriesType = {
+    "arithseries",			/* name */
+    FreeArithSeriesInternalRep,		/* freeIntRepProc */
+    DupArithSeriesInternalRep,		/* dupIntRepProc */
+    UpdateStringOfArithSeries,		/* updateStringProc */
+    SetArithSeriesFromAny		/* setFromAnyProc */
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArithSeriesLen --
+ *
+ * 	Compute the length of the equivalent list where
+ * 	every element is generated starting from *start*,
+ * 	and adding *step* to generate every successive element
+ * 	that's < *end* for positive steps, or > *end* for negative
+ * 	steps.
+ *
+ * Results:
+ *
+ * 	The length of the list generated by the given range,
+ * 	that may be zero.
+ * 	The function returns -1 if the list is of length infiite.
+ *
+ * Side effects:
+ *
+ * 	None.
+ *
+ *----------------------------------------------------------------------
+ */
+static Tcl_WideInt
+ArithSeriesLen(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step)
+{
+	Tcl_WideInt len;
+
+	if (step == 0) return -1;
+	else if (step > 0 && start > end) return -1;
+	else if (step < 0 && end > start) return -1;
+	len = ((step > 0) ? 1 : -1) + (((end-start)-1)/step);
+	return (len < 0) ? -1 : len;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_NewArithSeriesObj --
+ *
+ *	Creates a new ArithSeries object. The returned object has
+ *	refcount = 0.
+ *
+ * Results:
+ *
+ * 	A Tcl_Obj pointer to the created ArithSeries object.
+ * 	A NULL pointer of the range is invalid.
+ *
+ * Side Effects:
+ *
+ * 	None.
+ *----------------------------------------------------------------------
+ */
+Tcl_Obj *
+Tcl_NewArithSeriesObj(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step)
+{
+    Tcl_WideInt len = ArithSeriesLen(start, end, step);
+    Tcl_Obj *arithSeriesPtr;
+    ArithSeries *arithSeriesRepPtr;
+
+    if (len == -1) return NULL; /* Invalid range error */
+    TclNewObj(arithSeriesPtr);
+
+    arithSeriesRepPtr = (ArithSeries*) ckalloc(sizeof (ArithSeries));
+    arithSeriesRepPtr->start = start;
+    arithSeriesRepPtr->end = end;
+    arithSeriesRepPtr->step = step;
+    arithSeriesRepPtr->len = len;
+    arithSeriesRepPtr->wideObjPtr = Tcl_NewWideIntObj(0);
+    Tcl_IncrRefCount(arithSeriesRepPtr->wideObjPtr);
+    arithSeriesPtr->internalRep.twoPtrValue.ptr1 = (VOID *) arithSeriesRepPtr;
+    arithSeriesPtr->internalRep.twoPtrValue.ptr2 = NULL;
+    arithSeriesPtr->typePtr = &tclArithSeriesType;
+    if (len > 0)
+    	Tcl_InvalidateStringRep(arithSeriesPtr);
+
+    return arithSeriesPtr;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ArithSeriesObjIndex --
+ *
+ *	Returns the element with the specified index in the list
+ *	represented by the specified Arithmentic Sequence object.
+ *	If the index is out of range, TCL_ERROR is returned,
+ *	otherwise TCL_OK is returned and the integer value of the
+ *	element is stored in *element.
+ *
+ * Results:
+ *
+ * 	TCL_OK on succes, TCL_ERROR on index out of range.
+ *
+ * Side Effects:
+ *
+ * 	On success, the integer pointed by *element is modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_ArithSeriesObjIndex(Tcl_Obj *arithSeriesPtr, Tcl_WideInt index, Tcl_WideInt *element)
+{
+    ArithSeries *arithSeriesRepPtr;
+
+    if (arithSeriesPtr->typePtr != &tclArithSeriesType) {
+        Tcl_Panic("Tcl_ArithSeriesObjIndex called with a not ArithSeries Obj.");
+    }
+    arithSeriesRepPtr = (ArithSeries*)
+	    arithSeriesPtr->internalRep.twoPtrValue.ptr1;
+    if (index < 0 || index >= arithSeriesRepPtr->len)
+	    return TCL_ERROR;
+    /* List[i] = Start + (Step * i) */
+    *element = arithSeriesRepPtr->start+(index*arithSeriesRepPtr->step);
+    return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ArithSeriesObjLength
+ *
+ *	Returns the length of the arithmentic series.
+ *
+ * Results:
+ *
+ * 	The length of the series as Tcl_WideInt.
+ *
+ * Side Effects:
+ *
+ * 	None.
+ *
+ *----------------------------------------------------------------------
+ */
+Tcl_WideInt Tcl_ArithSeriesObjLength(Tcl_Obj *arithSeriesPtr)
+{
+    ArithSeries *arithSeriesRepPtr = (ArithSeries*)
+	    arithSeriesPtr->internalRep.twoPtrValue.ptr1;
+    return arithSeriesRepPtr->len;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FreeArithSeriesInternalRep --
+ *
+ *	Deallocate the storage associated with an arithseries object's
+ *	internal representation.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	Frees arithSeriesPtr's ArithSeries* internal representation and
+ *	sets listPtr's	internalRep.twoPtrValue.ptr1 to NULL.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+FreeArithSeriesInternalRep(Tcl_Obj *arithSeriesPtr)
+{
+    ArithSeries *arithSeriesRepPtr =
+	    (ArithSeries *) arithSeriesPtr->internalRep.twoPtrValue.ptr1;
+    Tcl_DecrRefCount(arithSeriesRepPtr->wideObjPtr);
+    ckfree((char *) arithSeriesRepPtr);
+    arithSeriesPtr->internalRep.twoPtrValue.ptr1 = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DupArithSeriesInternalRep --
+ *
+ *	Initialize the internal representation of a arithseries Tcl_Obj to a
+ *	copy of the internal representation of an existing arithseries object. 
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	We set "copyPtr"s internal rep to a pointer to a
+ *	newly allocated ArithSeries structure.
+ *----------------------------------------------------------------------
+ */
+
+static void
+DupArithSeriesInternalRep(srcPtr, copyPtr)
+    Tcl_Obj *srcPtr;		/* Object with internal rep to copy. */
+    Tcl_Obj *copyPtr;		/* Object with internal rep to set. */
+{
+    ArithSeries *srcArithSeriesRepPtr =
+	    (ArithSeries *) srcPtr->internalRep.twoPtrValue.ptr1;
+    ArithSeries *copyArithSeriesRepPtr;
+    Tcl_WideInt wideVal;
+
+    /*
+     * Allocate a new ArithSeries structure. */
+
+    copyArithSeriesRepPtr = (ArithSeries*) ckalloc(sizeof(ArithSeries));
+    copyArithSeriesRepPtr->start = srcArithSeriesRepPtr->start;
+    copyArithSeriesRepPtr->end = srcArithSeriesRepPtr->end;
+    copyArithSeriesRepPtr->step = srcArithSeriesRepPtr->step;
+    copyArithSeriesRepPtr->len = srcArithSeriesRepPtr->len;
+    if (Tcl_GetWideIntFromObj(NULL, srcArithSeriesRepPtr->wideObjPtr,
+			    &wideVal) != TCL_OK)
+    {
+    	Tcl_Panic("Tcl_GetWideIntFromObj() failed against WideInt object.");
+    }
+    copyArithSeriesRepPtr->wideObjPtr = Tcl_NewWideIntObj(wideVal);
+    Tcl_IncrRefCount(copyArithSeriesRepPtr->wideObjPtr);
+
+    copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) copyArithSeriesRepPtr;
+    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
+    copyPtr->typePtr = &tclArithSeriesType;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * UpdateStringOfArithSeries --
+ *
+ *	Update the string representation for an arithseries object.
+ *	Note: This procedure does not invalidate an existing old string rep
+ *	so storage will be lost if this has not already been done. 
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	The object's string is set to a valid string that results from
+ *	the list-to-string conversion. This string will be empty if the
+ *	list has no elements. The list internal representation
+ *	should not be NULL and we assume it is not NULL.
+ *
+ * Notes:
+ * 	At the cost of overallocation it's possible to estimate
+ * 	the length of the string representation and make this procedure
+ * 	much faster. Because the programmer shouldn't expect the
+ * 	string conversion of a big arithmetic sequence to be fast
+ * 	this version takes more care of space than time.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+UpdateStringOfArithSeries(Tcl_Obj *arithSeriesPtr)
+{
+    ArithSeries *arithSeriesRepPtr =
+	    (ArithSeries*) arithSeriesPtr->internalRep.twoPtrValue.ptr1;
+    char buffer[TCL_INTEGER_SPACE+2], *p;
+    Tcl_WideInt i;
+    Tcl_WideInt length = 0, ele;
+    int slen;
+
+    /*
+     * Pass 1: estimate space.
+     */
+    for (i = 0; i < arithSeriesRepPtr->len; i++) {
+	ele = arithSeriesRepPtr->start + (i*arithSeriesRepPtr->step);
+    /*
+     * Note that sprintf will generate a compiler warning under
+     * Mingw claiming %I64 is an unknown format specifier.
+     * Just ignore this warning. We can't use %L as the format
+     * specifier since that gets printed as a 32 bit value.
+     */
+	sprintf(buffer, "%" TCL_LL_MODIFIER "d", ele);
+	slen = strlen(buffer) + 1; /* + 1 is for the space or the nul-term */
+	length += slen;
+    }
+
+    /*
+     * Pass 2: generate the string repr.
+     */
+
+    p = arithSeriesPtr->bytes = ckalloc(length);
+    for (i = 0; i < arithSeriesRepPtr->len; i++) {
+	ele = arithSeriesRepPtr->start + (i*arithSeriesRepPtr->step);
+	sprintf(buffer, "%" TCL_LL_MODIFIER "d", ele);
+	slen = strlen(buffer);
+	strcpy(p, buffer);
+	p[slen] = ' ';
+	p += slen+1;
+    }
+    if (length > 0) arithSeriesPtr->bytes[length-1] = '\0';
+    arithSeriesPtr->length = length;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * SetArithSeriesFromAny --
+ *
+ * 	The Arithmetic Series object is just an way to optimize
+ * 	Lists space complexity, so no one should try to convert
+ * 	a string to an Arithmetic Series object.
+ *
+ * 	This function is here just to populate the Type structure.
+ *
+ * Results:
+ *
+ * 	The result is always TCL_ERROR. But see Side Effects.
+ *
+ * Side effects:
+ *
+ * 	Tcl Panic if called.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+SetArithSeriesFromAny(interp, objPtr)
+    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
+    Tcl_Obj *objPtr;		/* The object to convert. */
+{
+    Tcl_Panic("SetArithSeriesFromAny: should never be called");
+    return TCL_ERROR;
+}
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.105
diff -u -r1.105 tclStubInit.c
--- generic/tclStubInit.c	14 Oct 2004 15:06:03 -0000	1.105
+++ generic/tclStubInit.c	24 Oct 2004 09:32:11 -0000
@@ -932,6 +932,9 @@
     Tcl_LimitGetCommands, /* 532 */
     Tcl_LimitGetTime, /* 533 */
     Tcl_LimitGetGranularity, /* 534 */
+    Tcl_NewArithSeriesObj, /* 535 */
+    Tcl_ArithSeriesObjIndex, /* 536 */
+    Tcl_ArithSeriesObjLength, /* 537 */
 };
 
 /* !END!: Do not edit above this line. */