summaryrefslogtreecommitdiffstats
path: root/generic/tclArithSeries.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclArithSeries.c')
-rwxr-xr-xgeneric/tclArithSeries.c178
1 files changed, 144 insertions, 34 deletions
diff --git a/generic/tclArithSeries.c b/generic/tclArithSeries.c
index 4902158..3be6cad 100755
--- a/generic/tclArithSeries.c
+++ b/generic/tclArithSeries.c
@@ -13,15 +13,14 @@
#include <assert.h>
#include "tcl.h"
#include "tclInt.h"
-#include "tclArithSeries.h"
/*
- * The structure below defines the arithmetic series Tcl Obj Type by means of
- * procedures that can be invoked by generic object code.
+ * 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 oTcl_AbstractList representing an interval
- * of an arithmetic series in constant space.
+ * The arithmetic series object is an AbstractList 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
@@ -34,15 +33,37 @@
* else if RANGE < 0
* LEN is (((END-START)-1)/STEP) - 1
*
- * And where the list's I-th element is calculated
+ * And where an equivalent list's I-th element is calculated
* as:
*
- * LIST[i] = START+(STEP*i)
+ * 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.
*/
+/*
+ * The structure used for the ArithSeries 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 {
+ Tcl_Size len;
+ Tcl_Obj **elements;
+ int isDouble;
+ Tcl_WideInt start;
+ Tcl_WideInt end;
+ Tcl_WideInt step;
+} ArithSeries;
+typedef struct {
+ Tcl_Size len;
+ Tcl_Obj **elements;
+ int isDouble;
+ double start;
+ double end;
+ double step;
+} ArithSeriesDbl;
+
static inline double ArithSeriesIndexDbl(ArithSeriesDbl *repPtr, Tcl_Size index)
{
return (repPtr->start + ((double)index * repPtr->step));
@@ -69,13 +90,14 @@ static Tcl_Obj *TclNewArithSeriesDbl(double start, double end,
static void DupArithSeriesRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void FreeArithSeriesRep(Tcl_Obj *arithSeriesObjPtr);
static void UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObjPtr);
+static int SetArithSeriesFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static Tcl_ObjType arithSeriesType = {
"arithseries", /* name */
FreeArithSeriesRep, /* freeIntRepProc */
DupArithSeriesRep, /* dupIntRepProc */
UpdateStringOfArithSeries, /* updateStringProc */
- NULL, /* setFromAnyProc */
+ SetArithSeriesFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V1(
TclArithSeriesObjLength,
NULL,
@@ -103,7 +125,7 @@ static Tcl_ObjType arithSeriesType = {
*
* 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.
+ * The function returns -1 if the list is of length infinite.
*
* Side effects:
*
@@ -149,8 +171,11 @@ DupArithSeriesRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)
/* Note: we do not have to be worry about existing internal rep because
copyPtr is supposed to be freshly initialized */
- Tcl_ObjSetConcreteRep(copyPtr, copyArithSeries);
- copyPtr->typePtr = srcPtr->typePtr;
+
+ Tcl_ObjInternalRep itr;
+ itr.twoPtrValue.ptr1 = copyArithSeries;
+ itr.twoPtrValue.ptr2 = NULL;
+ Tcl_StoreInternalRep(copyPtr, srcPtr->typePtr, &itr);
if (copyArithSeries->len > 0) {
Tcl_InvalidateStringRep(copyPtr);
} else {
@@ -217,8 +242,9 @@ TclNewArithSeriesInt(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step, Tcl_W
Tcl_ObjInternalRep itr;
ArithSeries *arithSeriesRepPtr;
+ TclNewObj(arithSeriesObj);
+
if (length <= 0) {
- TclNewObj(arithSeriesObj);
return arithSeriesObj;
}
@@ -230,9 +256,9 @@ TclNewArithSeriesInt(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step, Tcl_W
arithSeriesRepPtr->len = length;
arithSeriesRepPtr->elements = NULL;
- TclNewObj(arithSeriesObj);
+ itr.twoPtrValue.ptr1 = arithSeriesRepPtr;
+ itr.twoPtrValue.ptr2 = NULL;
Tcl_StoreInternalRep(arithSeriesObj, &arithSeriesType, &itr);
- Tcl_ObjSetConcreteRep(arithSeriesObj, arithSeriesRepPtr);
if (length > 0)
Tcl_InvalidateStringRep(arithSeriesObj);
@@ -266,8 +292,9 @@ TclNewArithSeriesDbl(double start, double end, double step, Tcl_WideInt len)
Tcl_ObjInternalRep itr;
ArithSeriesDbl *arithSeriesRepPtr;
+ TclNewObj(arithSeriesObj);
+
if (length <= 0) {
- TclNewObj(arithSeriesObj);
return arithSeriesObj;
}
@@ -279,9 +306,9 @@ TclNewArithSeriesDbl(double start, double end, double step, Tcl_WideInt len)
arithSeriesRepPtr->len = length;
arithSeriesRepPtr->elements = NULL;
- TclNewObj(arithSeriesObj);
+ itr.twoPtrValue.ptr1 = arithSeriesRepPtr;
+ itr.twoPtrValue.ptr2 = NULL;
Tcl_StoreInternalRep(arithSeriesObj, &arithSeriesType, &itr);
- Tcl_ObjSetConcreteRep(arithSeriesObj, arithSeriesRepPtr);
if (length > 0)
Tcl_InvalidateStringRep(arithSeriesObj);
@@ -294,7 +321,7 @@ TclNewArithSeriesDbl(double start, double end, double step, Tcl_WideInt len)
*
* assignNumber --
*
- * Create the approprite Tcl_Obj value for the given numeric values.
+ * Create the appropriate Tcl_Obj value for the given numeric values.
* Used locally only for decoding [lseq] numeric arguments.
* refcount = 0.
*
@@ -362,14 +389,14 @@ assignNumber(
int
TclNewArithSeriesObj(
- Tcl_Interp *interp, /* For error reporting */
- Tcl_Obj **arithSeriesObj, /* return value */
- int useDoubles, /* Promote values to double when true,
- * int otherwise */
- Tcl_Obj *startObj, /* First value in list */
- Tcl_Obj *endObj, /* Upper bound value of list */
- Tcl_Obj *stepObj, /* Increment amount */
- Tcl_Obj *lenObj) /* Number of elements */
+ Tcl_Interp *interp, /* For error reporting */
+ Tcl_Obj **arithSeriesObj, /* return value */
+ int useDoubles, /* Promote values to double when true,
+ ** int otherwise */
+ Tcl_Obj *startObj, /* First value in list */
+ Tcl_Obj *endObj, /* Upper bound value of list */
+ Tcl_Obj *stepObj, /* Increment amount */
+ Tcl_Obj *lenObj) /* Number of elements */
{
double dstart, dend, dstep;
Tcl_WideInt start, end, step;
@@ -390,7 +417,7 @@ TclNewArithSeriesObj(
}
if (dstep == 0) {
*arithSeriesObj = Tcl_NewObj();
- return TCL_OK;
+ return TCL_OK;
}
}
if (endObj) {
@@ -477,14 +504,14 @@ Tcl_Size TclArithSeriesObjLength(Tcl_Obj *arithSeriesObj)
* TclArithSeriesObjIndex --
*
* Returns the element with the specified index in the list
- * represented by the specified Arithmentic Sequence object.
+ * represented by the specified Arithmetic 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.
+ * TCL_OK on success, TCL_ERROR on index out of range.
*
* Side Effects:
*
@@ -495,10 +522,10 @@ Tcl_Size TclArithSeriesObjLength(Tcl_Obj *arithSeriesObj)
int
TclArithSeriesObjIndex(
- Tcl_Interp *interp, /* Used for error reporting if not NULL. */
+ Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *arithSeriesPtr, /* List obj */
- Tcl_Size index, /* index to element of interest */
- Tcl_Obj **elemObj) /* Return value */
+ Tcl_Size index, /* index to element of interest */
+ Tcl_Obj **elemObj) /* Return value */
{
ArithSeries *arithSeriesRepPtr = (ArithSeries *)Tcl_ObjGetConcreteRep(arithSeriesPtr);
(void)interp; // quiet compiler
@@ -760,8 +787,33 @@ TclArithSeriesObjReverse(
}
/*
-** Handle ArithSeries GetElements call
-*/
+ *----------------------------------------------------------------------
+ *
+ * TclArithSeriesGetElements --
+ *
+ * This function returns an (objc,objv) array of the elements in a list
+ * object.
+ *
+ * Results:
+ * The return value is normally TCL_OK; in this case *objcPtr is set to
+ * the count of list elements and *objvPtr is set to a pointer to an
+ * array of (*objcPtr) pointers to each list element. If listPtr does not
+ * refer to an Abstract List object and the object can not be converted
+ * to one, TCL_ERROR is returned and an error message will be left in the
+ * interpreter's result if interp is not NULL.
+ *
+ * The objects referenced by the returned array should be treated as
+ * readonly and their ref counts are _not_ incremented; the caller must
+ * do that if it holds on to a reference. Furthermore, the pointer and
+ * length returned by this function may change as soon as any function is
+ * called on the list object; be careful about retaining the pointer in a
+ * local data structure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
int
TclArithSeriesGetElements(
@@ -818,6 +870,34 @@ TclArithSeriesGetElements(
return TCL_OK;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 *arithSeriesObjPtr)
{
@@ -862,6 +942,36 @@ UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObjPtr)
if (length > 0) arithSeriesObjPtr->bytes[length-1] = '\0';
arithSeriesObjPtr->length = length-1;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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(
+ TCL_UNUSED(Tcl_Interp *), /* Used for error reporting if not NULL. */
+ TCL_UNUSED(Tcl_Obj *)) /* The object to convert. */
+{
+ Tcl_Panic("SetArithSeriesFromAny: should never be called");
+ return TCL_ERROR;
+}
/*
* Local Variables: