ソースを参照

Provide sort function with CivetWeb

Using qsort_r/s caused a crash on BSD/MacOS, because of a different definition
of this function on different systems. Therefore we provide our own sorting
function. The "ShellSort" algorithm was used, because it has a small code base,
low memory requirements and is still an effective algorithm, in particular for
the typical list size we need to sort. Our application is to sort directory
entries (file and folder names, sizes, dates), so optimizing for ~100 entries
seems most reasonable.

Fixes #1048 (Tests for OSX and FreeBSD on Travis CI broken)

Fixes #200 (Travis CI FreeBSD integration)
bel2125 3 年 前
コミット
6f594a3a93
1 ファイル変更34 行追加8 行削除
  1. 34 8
      src/civetweb.c

+ 34 - 8
src/civetweb.c

@@ -9835,22 +9835,48 @@ dir_scan_callback(struct de *de, void *data)
 }
 }
 
 
 
 
-typedef void (*tsortfunc)(const void *data1, const void *data2, void *userarg);
-
 static void
 static void
 mg_sort(void *data,
 mg_sort(void *data,
         size_t elemcount,
         size_t elemcount,
         size_t elemsize,
         size_t elemsize,
-        tsortfunc sortfunc,
+        int (*compfunc)(const void *data1, const void *data2, void *userarg),
         void *userarg)
         void *userarg)
 {
 {
-	/* Do nothing and check if this is the reason for our MacOS crash. This
-	 * could be because of a different order of arguments for qsort_r between
-	 * Linux and MacOS:
+	/* We cannot use qsort_r here. For a detailed reason, see
+	 * https://github.com/civetweb/civetweb/issues/1048#issuecomment-1047093014
 	 * https://stackoverflow.com/questions/39560773/different-declarations-of-qsort-r-on-mac-and-linux
 	 * https://stackoverflow.com/questions/39560773/different-declarations-of-qsort-r-on-mac-and-linux
-	 * Anyway: Why sort at server side if this could be done on client side in
-	 * Javascript as well?
 	 */
 	 */
+
+	/* We use ShellSort here with this gap sequence: https://oeis.org/A102549 */
+	int A102549[9] = {1, 4, 10, 23, 57, 132, 301, 701, 1750};
+	int Aidx, gap, i, j, k;
+	void *tmp = alloca(elemsize);
+
+	for (Aidx = 8; Aidx >= 0; Aidx--) {
+		gap = A102549[Aidx];
+		if (gap > elemcount / 2) {
+			continue;
+		}
+		for (i = 0; i < gap; i++) {
+			for (j = i; j < elemcount; j += gap) {
+				memcpy(tmp, (void *)((ptrdiff_t)data + elemsize * j), elemsize);
+
+				for (k = j; k >= gap; k -= gap) {
+					void *cmp =
+					    (void *)((ptrdiff_t)data + elemsize * (k - gap));
+					int cmpres = compfunc(cmp, tmp, userarg);
+					if (cmpres > 0) {
+						memcpy((void *)((ptrdiff_t)data + elemsize * k),
+						       cmp,
+						       elemsize);
+					} else {
+						break;
+					}
+				}
+				memcpy((void *)((ptrdiff_t)data + elemsize * k), tmp, elemsize);
+			}
+		}
+	}
 }
 }