summaryrefslogtreecommitdiffstats
path: root/generic/tclArithSeries.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclArithSeries.c')
-rwxr-xr-xgeneric/tclArithSeries.c93
1 files changed, 90 insertions, 3 deletions
diff --git a/generic/tclArithSeries.c b/generic/tclArithSeries.c
index 166c1c9..40a78a4 100755
--- a/generic/tclArithSeries.c
+++ b/generic/tclArithSeries.c
@@ -80,7 +80,8 @@ static void DupArithSeriesInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void FreeArithSeriesInternalRep(Tcl_Obj *arithSeriesObjPtr);
static void UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObjPtr);
static int SetArithSeriesFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
-
+static int ArithSeriesInOperation(Tcl_Interp *interp, Tcl_Obj *valueObj, Tcl_Obj *arithSeriesObj,
+ int *boolResult);
static const Tcl_ObjType arithSeriesType = {
"arithseries", /* name */
FreeArithSeriesInternalRep, /* freeIntRepProc */
@@ -94,7 +95,8 @@ static const Tcl_ObjType arithSeriesType = {
TclArithSeriesObjReverse,
TclArithSeriesGetElements,
NULL, // SetElement
- NULL) // Replace
+ NULL, // Replace
+ ArithSeriesInOperation) // "in" operator
};
/*
@@ -608,7 +610,7 @@ TclArithSeriesObjIndex(
ArithSeries *arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj);
if (index < 0 || arithSeriesRepPtr->len <= index) {
- *elemObj = Tcl_NewObj();
+ *elemObj = NULL;
} else {
/* List[i] = Start + (Step * index) */
if (arithSeriesRepPtr->isDouble) {
@@ -1108,7 +1110,92 @@ UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObjPtr)
if (bytlen > 0) arithSeriesObjPtr->bytes[bytlen-1] = '\0';
arithSeriesObjPtr->length = bytlen-1;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * ArithSeriesInOperator --
+ *
+ * Evaluate the "in" operation for expr
+ *
+ * This can be done more efficiently in the Arith Series relative to
+ * doing a linear search as implemented in expr.
+ *
+ * Results:
+ * Boolean true or false (1/0)
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+ArithSeriesInOperation(
+ Tcl_Interp *interp,
+ Tcl_Obj *valueObj,
+ Tcl_Obj *arithSeriesObjPtr,
+ int *boolResult)
+{
+ ArithSeries *arithSeriesRepPtr = (ArithSeries*)arithSeriesObjPtr->internalRep.twoPtrValue.ptr1;
+ ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr;
+ int status;
+ Tcl_Size index, incr, elen, vlen;
+
+ if (arithSeriesRepPtr->isDouble) {
+ double y;
+ int test = 0;
+
+ incr = 0; // Check index+incr where incr is 0 and 1
+ status = Tcl_GetDoubleFromObj(interp, valueObj, &y);
+ if (status != TCL_OK) {
+ test = 0;
+ } else {
+ const char *vstr = Tcl_GetStringFromObj(valueObj, &vlen);
+ index = (y - dblRepPtr->start) / dblRepPtr->step;
+ while (incr<2) {
+ Tcl_Obj *elemObj;
+ elen = 0;
+ TclArithSeriesObjIndex(interp, arithSeriesObjPtr, (index+incr), &elemObj);
+ const char *estr = elemObj ? Tcl_GetStringFromObj(elemObj, &elen) : "";
+ /* "in" operation defined as a string compare */
+ test = (elen == vlen) ? (memcmp(estr, vstr, elen) == 0) : 0;
+ Tcl_BounceRefCount(elemObj);
+ /* Stop if we have a match */
+ if (test) {
+ break;
+ }
+ incr++;
+ }
+ }
+ if (boolResult) {
+ *boolResult = test;
+ }
+ } else {
+ ArithSeries *intRepPtr = arithSeriesRepPtr;
+ Tcl_WideInt y;
+
+ status = Tcl_GetWideIntFromObj(NULL, valueObj, &y);
+ if (status != TCL_OK) {
+ if (boolResult) {
+ *boolResult = 0;
+ }
+ } else {
+ Tcl_Obj *elemObj;
+ elen = 0;
+ index = (y - intRepPtr->start) / intRepPtr->step;
+ TclArithSeriesObjIndex(interp, arithSeriesObjPtr, index, &elemObj);
+ char const *vstr = Tcl_GetStringFromObj(valueObj, &vlen);
+ char const *estr = elemObj ? Tcl_GetStringFromObj(elemObj, &elen) : "";
+ if (boolResult) {
+ *boolResult = (elen == vlen) ? (memcmp(estr, vstr, elen) == 0) : 0;
+ }
+ Tcl_BounceRefCount(elemObj);
+ }
+ }
+ return TCL_OK;
+}
+
/*
* Local Variables:
* mode: c