Browse Source

Replace the array sort code by the one from lua 5.1.5 because it can sort with half number of calls to the compare function compared to the original Squirrel code.

mingodad 7 years ago
parent
commit
831f120b7b
1 changed files with 84 additions and 59 deletions
  1. 84 59
      SquiLu/squirrel/sqbaselib.cpp

+ 84 - 59
SquiLu/squirrel/sqbaselib.cpp

@@ -419,6 +419,7 @@ static SQRESULT base_getincludepath(HSQUIRRELVM v)
     else sq_pushnull(v);
 	return 1;
 }
+
 /////////////////////////////////////////////////////////////////
 //TABLE BASE FUNCTIONS
 
@@ -485,6 +486,7 @@ static SQRESULT bf_obj_clone(HSQUIRRELVM v)
 	 if(rc != SQ_OK) return rc;
     return 1;
 }
+
 static SQRESULT bf_table_len(HSQUIRRELVM v)
 {
 	v->Push(SQInteger(sq_getsize(v,2)));
@@ -1070,7 +1072,7 @@ static SQRESULT array_bsearch(HSQUIRRELVM v)
 }
 
 
-bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
+static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
 {
 	if(func < 0) {
 		if(!v->ObjCmp(a,b,ret)) return false;
@@ -1096,70 +1098,88 @@ bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQ
 	return true;
 }
 
-bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)
-{
-	SQInteger maxChild;
-	SQInteger done = 0;
-	SQInteger ret;
-	SQInteger root2;
-	while (((root2 = root * 2) <= bottom) && (!done))
-	{
-		if (root2 == bottom) {
-			maxChild = root2;
-		}
-		else {
-			if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret))
-				return false;
-			if (ret > 0) {
-				maxChild = root2;
-			}
-			else {
-				maxChild = root2 + 1;
-			}
-		}
-
-		if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret))
-			return false;
-		if (ret < 0) {
-			if (root == maxChild) {
-                v->Raise_Error(_SC("inconsistent compare function"));
-                return false; // We'd be swapping ourselve. The compare function is incorrect
-            }
-
-			_Swap(arr->_values[root],arr->_values[maxChild]);
-			root = maxChild;
-		}
-		else {
-			done = 1;
-		}
-	}
-	return true;
-}
-
-bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger /*l*/, SQInteger /*r*/,SQInteger func)
-{
-	SQArray *a = _array(arr);
-	SQInteger i;
-	SQInteger array_size = a->Size();
-	for (i = (array_size / 2); i >= 0; i--) {
-		if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false;
-	}
+/*
+** The lua_auxsort code is adapted from from lua 5.1.5
+** {======================================================
+** Quicksort
+** (based on 'Algorithms in MODULA-3', Robert Sedgewick;
+**  Addison-Wesley, 1993.)
+** =======================================================
+*/
 
-	for (i = array_size-1; i >= 1; i--)
-	{
-		_Swap(a->_values[0],a->_values[i]);
-		if(!_hsort_sift_down(v,a, 0, i-1,func)) return false;
-	}
-	return true;
+static bool lua_auxsort (HSQUIRRELVM v, SQArray *arr, SQInteger l, SQInteger u,
+                                   SQInteger func) {
+  while (l < u) {  /* for tail recursion */
+    SQInteger i, j, ret;
+    bool rc;
+    /* sort elements a[l], a[(l+u)/2] and a[u] */
+    if(!_sort_compare(v,arr->_values[u],arr->_values[l],func,ret))
+        return false;
+    if (ret < 0)  /* a[u] < a[l]? */
+      _Swap(arr->_values[l],arr->_values[u]);  /* swap a[l] - a[u] */
+    if (u-l == 1) break;  /* only 2 elements */
+    i = (l+u)/2;
+    if(!_sort_compare(v,arr->_values[i],arr->_values[l],func,ret))
+        return false;
+    if (ret < 0)  /* a[i]<a[l]? */
+      _Swap(arr->_values[i],arr->_values[l]);
+    else {
+      if(!_sort_compare(v,arr->_values[u],arr->_values[i],func,ret))
+        return false;
+      if (ret < 0)  /* a[u]<a[i]? */
+        _Swap(arr->_values[i],arr->_values[u]);
+    }
+    if (u-l == 2) break;  /* only 3 elements */
+    SQObjectPtr P = arr->_values[i];  /* Pivot */
+    _Swap(arr->_values[i],arr->_values[u-1]);
+    /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
+    i = l; j = u-1;
+    for (;;) {  /* invariant: a[l..i] <= P <= a[j..u] */
+      /* repeat ++i until a[i] >= P */
+      while ((rc = _sort_compare(v,arr->_values[++i],P,func,ret)) && (ret < 0)) {
+        if (i>u)
+        {
+            sq_throwerror(v, _SC("invalid order function for sorting"));
+            return false;
+        }
+      }
+      if(!rc) return false;
+      /* repeat --j until a[j] <= P */
+      while ((rc = _sort_compare(v,P, arr->_values[--j],func,ret)) && (ret < 0)) {
+        if (j<l)
+        {
+            sq_throwerror(v, _SC("invalid order function for sorting"));
+            return false;
+        }
+      }
+      if(!rc) return false;
+      if (j<i) {
+        break;
+      }
+      _Swap(arr->_values[i],arr->_values[j]);
+    }
+    _Swap(arr->_values[u-1],arr->_values[i]);  /* swap pivot (a[u-1]) with a[i] */
+    /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
+    /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
+    if (i-l < u-i) {
+      j=l; i=i-1; l=i+2;
+    }
+    else {
+      j=i+1; i=u; u=j-2;
+    }
+    if(!lua_auxsort(v, arr, j, i, func))  /* call recursively for upper interval */
+        return false;
+  }  /* repeat the routine for the larger one */
+  return true;
 }
 
-static SQRESULT array_sort(HSQUIRRELVM v)
-{
+static SQRESULT array_sort(HSQUIRRELVM v) {
 	SQInteger func = -1;
 	SQObjectPtr &o = stack_get(v,1);
-	if(_array(o)->Size() > 1) {
+	SQArray *arr = _array(o);
+	if(arr->Size() > 1) {
 		if(sq_gettop(v) == 2) func = 2;
-		if(!_hsort(v, o, 0, _array(o)->Size()-1, func))
+		if(!lua_auxsort(v, arr, 0, arr->Size()-1, func))
 			return SQ_ERROR;
 
 	}
@@ -1167,6 +1187,8 @@ static SQRESULT array_sort(HSQUIRRELVM v)
 	return 1;
 }
 
+/* }====================================================== */
+
 static SQRESULT array_slice(HSQUIRRELVM v)
 {
 	SQInteger sidx,eidx;
@@ -1423,6 +1445,7 @@ static inline void push_match_capture(HSQUIRRELVM v, int i, LuaMatchState *ms)
     else sq_pushstring(v, ms->capture[i].init, ms->capture[i].len);
 }
 
+
 //on 64 bits there is an error SQRESULT/int
 static int process_string_gsub(LuaMatchState *ms, void *udata, lua_char_buffer_st **b) {
     const SQChar *str;
@@ -1885,6 +1908,7 @@ static SQRESULT string_strncmp(HSQUIRRELVM v) {
     sq_pushinteger(v, scstrncmp(str1+offset, str2, str2_size));
     return 1;
 }
+
 static SQRESULT string_countchr(HSQUIRRELVM v) {
     SQ_FUNC_VARS_NO_TOP(v);
     SQ_GET_STRING(v, 1, src);
@@ -2191,6 +2215,7 @@ static SQRESULT string_ushort(HSQUIRRELVM v)
 	return 1;
 }
 
+
 #define MMIN(a,b) (((a)<(b))?(a):(b))
 static SQRESULT string_edit_distance (HSQUIRRELVM v) {
     SQ_FUNC_VARS(v);