Jelajahi Sumber

Fixed a List resize issue and some minor warnings. (Unit test added)

Marco Bambini 8 tahun lalu
induk
melakukan
fa26077135
3 mengubah file dengan 161 tambahan dan 13 penghapusan
  1. 21 11
      src/runtime/gravity_core.c
  2. 3 2
      src/shared/gravity_value.h
  3. 137 0
      test/unittest/list_resize.gravity

+ 21 - 11
src/runtime/gravity_core.c

@@ -825,12 +825,13 @@ static bool list_storeat (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
 
 	if (index < 0) index = count + index;
 	if (index < 0) RETURN_ERROR("Out of bounds error: index %d beyond bounds 0...%d", index, count-1);
+    
 	if ((uint32_t)index >= count) {
 		// handle list resizing here
-		marray_resize(gravity_value_t, list->array, index-count);
+		marray_resize(gravity_value_t, list->array, index-count+MIN_LIST_RESIZE);
         if (!list->array.p) RETURN_ERROR("Not enough memory to resize List.");
 		marray_nset(list->array, index+1);
-		for (int32_t i=count; i<index; ++i) {
+		for (int32_t i=count; i<=(index+MIN_LIST_RESIZE); ++i) {
 			marray_set(list->array, i, VALUE_FROM_NULL);
 		}
 		marray_set(list->array, index, value);
@@ -934,12 +935,14 @@ static bool list_reverse (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
   gravity_list_t *list = VALUE_AS_LIST(value);
   uint32_t count = (uint32_t)marray_size(list->array);
   gravity_int_t i = 0;
+    
   while (i < count/2) {
     gravity_value_t tmp = marray_get(list->array, count-i-1);
     marray_set(list->array, count-i-1,  marray_get(list->array, i));
     marray_set(list->array, i,  tmp);
     i++;
   }
+    
   RETURN_VALUE(VALUE_FROM_OBJECT(list), rindex);
 }
 
@@ -947,21 +950,23 @@ static bool list_reversed (gravity_vm *vm, gravity_value_t *args, uint16_t nargs
   if (nargs > 1) RETURN_ERROR("Incorrect number of arguments.");
   gravity_value_t value = GET_VALUE(0);							// self parameter
   gravity_list_t *list = VALUE_AS_LIST(value);
-  gravity_list_t *newlist = gravity_list_new(vm, list->array.n);
+    gravity_list_t *newlist = gravity_list_new(vm, (uint32_t)list->array.n);
   uint32_t count = (uint32_t)marray_size(list->array);
   gravity_int_t i = 0;
+    
   while (i < count) {
     marray_push(gravity_value_t, newlist->array, marray_get(list->array, count-i-1));
     i++;
   }
+    
   RETURN_VALUE(VALUE_FROM_OBJECT(newlist), rindex);
 }
 
-static
-bool compare_values(gravity_vm *vm, gravity_value_t selfvalue, gravity_value_t val1, gravity_value_t val2, gravity_closure_t *predicate) {
+static bool compare_values(gravity_vm *vm, gravity_value_t selfvalue, gravity_value_t val1, gravity_value_t val2, gravity_closure_t *predicate) {
   gravity_value_t params[2] = {val1, val2};
   if (!gravity_vm_runclosure(vm, predicate, selfvalue, params, 2)) return false;
   gravity_value_t result = gravity_vm_result(vm);
+    
   //the conversion will make sure that the comparison function only returns a
   //truthy value that can be interpreted as the result of a comparison
   //(i.e. only integer, bool, float, null, undefined, or string)
@@ -969,10 +974,10 @@ bool compare_values(gravity_vm *vm, gravity_value_t selfvalue, gravity_value_t v
   return truthy_value.n;
 }
 
-uint32_t partition(gravity_vm *vm, gravity_value_t *array, int32_t low, int32_t high, gravity_value_t selfvalue, gravity_closure_t *predicate)
-{
+static uint32_t partition(gravity_vm *vm, gravity_value_t *array, int32_t low, int32_t high, gravity_value_t selfvalue, gravity_closure_t *predicate) {
   gravity_value_t pivot = array[high];
   int32_t i = low - 1;
+    
   for (int32_t j = low; j <= high - 1; j++) {
     if (!compare_values(vm, selfvalue, array[j], pivot, predicate)) {
       i++;
@@ -981,13 +986,15 @@ uint32_t partition(gravity_vm *vm, gravity_value_t *array, int32_t low, int32_t
       array[j] = temp;
     }
   }
+    
   gravity_value_t temp = array[i + 1];
   array[i + 1] = array[high];
   array[high] = temp;
+    
   return i + 1;
 }
 
-void quicksort(gravity_vm *vm, gravity_value_t *array, int32_t low, int32_t high, gravity_value_t selfvalue, gravity_closure_t *predicate) {
+static void quicksort(gravity_vm *vm, gravity_value_t *array, int32_t low, int32_t high, gravity_value_t selfvalue, gravity_closure_t *predicate) {
   if (low < high) {
     int32_t pi = partition(vm, array, low, high, selfvalue, predicate);
     quicksort(vm, array, low, pi - 1, selfvalue, predicate);
@@ -1011,16 +1018,19 @@ static bool list_sorted (gravity_vm *vm, gravity_value_t *args, uint16_t nargs,
   if (nargs != 2) RETURN_ERROR("One argument is needed by the sort function.");
   if (!VALUE_ISA_CLOSURE(GET_VALUE(1))) RETURN_ERROR("Argument must be a Closure.");
   gravity_value_t selfvalue = GET_VALUE(0);							// self parameter
+    
   //the predicate is the comparison function, passed to list.sort()
   gravity_closure_t *predicate = VALUE_AS_CLOSURE(GET_VALUE(1));
   gravity_list_t *list = VALUE_AS_LIST(selfvalue);
-  int64_t count = (int64_t)marray_size(list->array);
-  gravity_list_t *newlist = gravity_list_new(vm, count);
+    size_t count = marray_size(list->array);
+    gravity_list_t *newlist = gravity_list_new(vm, (uint32_t)count);
+    
   //memcpy should be faster than pushing element by element
   memcpy(newlist->array.p, list->array.p, sizeof(gravity_value_t)*count);
   newlist->array.m = list->array.m;
   newlist->array.n = list->array.n;
-  quicksort(vm, newlist->array.p, 0, count-1, selfvalue, predicate);
+    quicksort(vm, newlist->array.p, 0, (int32_t)count-1, selfvalue, predicate);
+    
   RETURN_VALUE(VALUE_FROM_OBJECT(newlist), rindex);
 }
 

+ 3 - 2
src/shared/gravity_value.h

@@ -66,8 +66,8 @@
 extern "C" {
 #endif
 
-#define GRAVITY_VERSION						"0.3.6"     // git tag 0.3.6
-#define GRAVITY_VERSION_NUMBER				0x000306    // git push --tags
+#define GRAVITY_VERSION						"0.3.7"     // git tag 0.3.7
+#define GRAVITY_VERSION_NUMBER				0x000307    // git push --tags
 #define GRAVITY_BUILD_DATE					__DATE__
 
 #ifndef GRAVITY_ENABLE_DOUBLE
@@ -140,6 +140,7 @@ extern "C" {
 #define MAXNUM(a,b)							((a) > (b) ? a : b)
 #define MINNUM(a,b)							((a) < (b) ? a : b)
 #define EPSILON								0.000001
+#define MIN_LIST_RESIZE                     12          // value used when a List is resized
 
 #define GRAVITY_DATA_REGISTER				UINT32_MAX
 #define GRAVITY_FIBER_REGISTER				UINT32_MAX-1

+ 137 - 0
test/unittest/list_resize.gravity

@@ -0,0 +1,137 @@
+#unittest {
+    name: "List resize.";
+    result: "[2,4,6,8,10,12,14,16,18]";
+};
+
+// BEGIN PARRO CODE
+
+func raiseError(msg) {
+    Fiber.abort(msg);
+}
+
+func reverseArgs(fn) {
+    return func(/* args */) {
+        var revertedArgs = [];
+        for (var i in (_args.count - 1) ... 0) {
+            revertedArgs.push(_args[i]);
+        }
+        return fn.apply(null, revertedArgs);
+    }
+}
+
+func compose(/* fns */) {
+    if (_args.count < 1) {
+        return raiseError('Arguments must contain at least one function.');
+    }
+    var lastFn = _args.pop();
+    var otherFns = _args;
+    
+    return func(/* first fn args */) {
+        var result = lastFn.apply(null, _args);
+        for (var i in (otherFns.count - 1) ... 0) {
+            var fn = otherFns[i];
+            result = fn(result);
+        }
+        return result;
+    }
+}
+
+var pipe = reverseArgs(compose);
+
+func curry (arity, fn) {
+    var accumulatedArgs = [];
+    return func() {
+        accumulatedArgs = concat(accumulatedArgs, _args);
+        
+        if (accumulatedArgs.count == arity) {
+            return fn.apply(null, accumulatedArgs);
+        }
+        return _func;
+    };
+}
+
+func concat(arr1, arr2) {
+    var result = [];
+    for (var item in arr1) {
+        result.push(item);
+    }
+    for (var item in arr2) {
+        result.push(item);
+    }
+    return result
+}
+
+func partial(fn /*...args*/) {
+    var argsToApply = [];
+    
+    for (var i in 1 ..< _args.count) {
+        argsToApply.push(_args[i]);
+    }
+    
+    return func() {
+        var args = concat(argsToApply, _args);
+        return fn.apply(null, args);
+    }
+}
+
+var map = curry(2, func(fn, data) {
+    if (!(fn is Closure)) {
+        return raiseError('First argument must be a function.');
+    }
+    
+    var results = [];
+    var idx = 0;
+    
+    for (var item in data) {
+        results[idx] = fn(item, idx);
+        idx += 1;
+    }
+    
+    return results;
+});
+
+var filter = curry(2, func(fn, data) {
+    if (!(fn is Closure)) {
+        return raiseError('First argument must be a function.');
+    }
+    
+    var results = [];
+    var idx = 0;
+    
+    for (var item in data) {
+        if ( fn(item, idx) ) {
+            results[idx] = item;
+            idx += 1;
+        }
+    }
+    
+    return results;
+});
+
+
+var reduce = curry(3, func(fn, accumulator, data) {
+    if (!(fn is Closure)) {
+        return raiseError('First argument must be a function.');
+    }
+    
+    var result = accumulator;
+    var idx = 0;
+    
+    for (var item in data) {
+        result = fn(result, item, idx);
+        idx += 1;
+    }
+    
+    return result;
+});
+
+// END PARRO CODE
+
+func double(x) {
+    return x * 2
+}
+
+func main() {
+    var list = [1,2,3,4,5,6,7,8,9]
+    return map(double, list).String();
+}