From 80032e22c35eb24d2df11843a723caa7c7160d29 Mon Sep 17 00:00:00 2001 From: Evan Hunter Date: Thu, 6 Oct 2016 22:19:26 +0100 Subject: [PATCH] Array fixes and tests Changed 'array exists' to actually check if the variable is an array (matches tclsh) Fix Jim_DictInfo to avoid using printf() and make output match tclsh Added some more tests for array command - checked these work with tclsh --- jim-array.c | 11 ++++++++--- jim.c | 39 +++++++++++++++++++++++++++++---------- jim_tcl.txt | 3 +-- tests/array.test | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 15 deletions(-) diff --git a/jim-array.c b/jim-array.c index 39cd168..cd3e784 100644 --- a/jim-array.c +++ b/jim-array.c @@ -54,7 +54,8 @@ static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { /* Just a regular [info exists] */ - Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0); + Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); + Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1); return JIM_OK; } @@ -115,7 +116,9 @@ static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) { - return JIM_ERR; + /* Variable is not an array - tclsh ignores this and returns nothing - be compatible */ + Jim_SetResultString(interp, "", -1); + return JIM_OK; } /* Create a new object with the values which don't match */ @@ -142,7 +145,9 @@ static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (objPtr) { len = Jim_DictSize(interp, objPtr); if (len < 0) { - return JIM_ERR; + /* Variable is not an array - tclsh ignores this and returns 0 - be compatible */ + Jim_SetResultInt(interp, 0); + return JIM_OK; } } diff --git a/jim.c b/jim.c index 04eedc6..443da61 100644 --- a/jim.c +++ b/jim.c @@ -14365,6 +14365,9 @@ int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_HashTable *ht; unsigned int i; + char buffer[100]; + int sum = 0; + int nonzero_count = 0; if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; @@ -14373,21 +14376,37 @@ int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr) ht = (Jim_HashTable *)objPtr->internalRep.ptr; /* Note that this uses internal knowledge of the hash table */ - printf("%d entries in table, %d buckets\n", ht->used, ht->size); + snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets\n", ht->used, ht->size); + Jim_Obj *output = Jim_NewStringObj(interp, buffer, -1); + int bucket_counts[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; for (i = 0; i < ht->size; i++) { Jim_HashEntry *he = ht->table[i]; - - if (he) { - printf("%d: ", i); - - while (he) { - printf(" %s", Jim_String(he->key)); - he = he->next; - } - printf("\n"); + int entries = 0; + while (he) { + entries++; + he = he->next; } + if (entries > 9) { + bucket_counts[10]++; + } + else { + bucket_counts[entries]++; + } + if (entries) { + sum += entries; + nonzero_count++; + } + } + for (i = 0; i < 10; i++) { + snprintf(buffer, sizeof(buffer), "number of buckets with %d entries: %d\n", i, bucket_counts[i]); + Jim_AppendString(interp, output, buffer, -1); } + snprintf(buffer, sizeof(buffer), "number of buckets with 10 or more entries: %d\n", bucket_counts[10]); + Jim_AppendString(interp, output, buffer, -1); + snprintf(buffer, sizeof(buffer), "average search distance for entry: %.1f", nonzero_count ? (double)sum / nonzero_count : 0.0); + Jim_AppendString(interp, output, buffer, -1); + Jim_SetResult(interp, output); return JIM_OK; } diff --git a/jim_tcl.txt b/jim_tcl.txt index af95d66..28dc317 100644 --- a/jim_tcl.txt +++ b/jim_tcl.txt @@ -1664,8 +1664,7 @@ command. The legal +'options'+ (which may be abbreviated) are: +*array exists* 'arrayName'+:: Returns 1 if arrayName is an array variable, 0 if there is - no variable by that name. This command is essentially - identical to `info exists` + no variable by that name. +*array get* 'arrayName ?pattern?'+:: Returns a list containing pairs of elements. The first diff --git a/tests/array.test b/tests/array.test index ba88147..423276b 100644 --- a/tests/array.test +++ b/tests/array.test @@ -85,4 +85,50 @@ test array-1.14 "access array via unset var" -body { expr {$a($b) + 4} } -returnCodes error -result {can't read "b": no such variable} +test array-1.15 "array unset non-variable" -body { + array unset nonvariable 4 +} -result {} + +test array-1.16 "array names non-variable" -body { + array names nonvariable +} -result {} + +test array-1.17 "array get non-variable" -body { + array get nonvariable +} -result {} + +# This seems like incorrect behaviour, but it matches tclsh +test array-1.18 "array size non-array" -body { + set x 1 + array size x +} -result {0} + +# This seems like incorrect behaviour, but it matches tclsh +test array-1.19 "array unset non-array" -body { + set x 6 + array unset x 4 +} -result {} + +test array-1.20 "array stat" -body { + set output [array stat a] + regexp "1 entries in table.*number of buckets with 1 entries: 1" $output +} -result {1} + +test array-1.21 "array stat non-array" -body { + array stat badvariable +} -returnCodes error -result {"badvariable" isn't an array} + +test array-1.22 "array set non-even args" -body { + array set x { + 1 one + 2 two + 3 +} +} -returnCodes error -result {list must have an even number of elements} + +test array-1.23 "array exists non-array" -body { + set x 4 + array exists x +} -result {0} + testreport -- 2.11.4.GIT