/* * Copyright © 2020 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include "gtk/timsort/gtktimsortprivate.h" #define assert_sort_equal(a, b, size, n) \ g_assert_cmpmem (a, sizeof (size) * n, b, sizeof (size) * n) static int compare_int (gconstpointer a, gconstpointer b, gpointer unused) { int ia = *(const int *) a; int ib = *(const int *) b; return ia < ib ? -1 : (ia > ib); } static int compare_pointer (gconstpointer a, gconstpointer b, gpointer unused) { gpointer pa = *(const gpointer *) a; gpointer pb = *(const gpointer *) b; return pa < pb ? -1 : (pa > pb); } G_GNUC_UNUSED static void dump (int *a, gsize n) { gsize i; for (i = 0; i < n; i++) { if (i) g_print(", "); g_print ("%d", a[i]); } g_print ("\n"); } static void run_comparison (gpointer a, gsize n, gsize element_size, GCompareDataFunc compare_func, gpointer data) { gint64 start, mid, end; gpointer b; g_assert_cmpint (n, <=, G_MAXSIZE / element_size); b = g_memdup2 (a, element_size * n); start = g_get_monotonic_time (); gtk_tim_sort (a, n, element_size, compare_func, data); mid = g_get_monotonic_time (); g_qsort_with_data (b, n, element_size, compare_func, data); end = g_get_monotonic_time (); g_test_message ("%zu items in %uus vs %uus (%u%%)", n, (guint) (mid - start), (guint) (end - mid), (guint) (100 * (mid - start) / MAX (1, end - mid))); assert_sort_equal (a, b, int, n); g_free (b); } static void test_integers (void) { int *a; gsize i, n, run; a = g_new (int, 1000); for (run = 0; run < 10; run++) { n = g_test_rand_int_range (0, 1000); for (i = 0; i < n; i++) a[i] = g_test_rand_int (); run_comparison (a, n, sizeof (int), compare_int, NULL); } g_free (a); } static void test_integers_runs (void) { int *a; gsize i, j, n, run; a = g_new (int, 1000); for (run = 0; run < 10; run++) { n = g_test_rand_int_range (0, 1000); for (i = 0; i < n; i++) { a[i] = g_test_rand_int (); j = i + g_test_rand_int_range (0, 20); j = MIN (n, j); if (g_test_rand_bit ()) { for (i++; i < j; i++) a[i] = a[i - 1] + 1; } else { for (i++; i < j; i++) a[i] = a[i - 1] - 1; } } run_comparison (a, n, sizeof (int), compare_int, NULL); } g_free (a); } static void test_integers_huge (void) { int *a; gsize i, n; n = g_test_rand_int_range (2 * 1000 * 1000, 5 * 1000 * 1000); a = g_new (int, n); for (i = 0; i < n; i++) a[i] = g_test_rand_int (); run_comparison (a, n, sizeof (int), compare_int, NULL); g_free (a); } static void test_pointers (void) { gpointer *a; gsize i, n, run; a = g_new (gpointer, 1000); for (run = 0; run < 10; run++) { n = g_test_rand_int_range (0, 1000); for (i = 0; i < n; i++) a[i] = GINT_TO_POINTER (g_test_rand_int ()); run_comparison (a, n, sizeof (gpointer), compare_pointer, NULL); } g_free (a); } static void test_pointers_huge (void) { gpointer *a; gsize i, n; n = g_test_rand_int_range (2 * 1000 * 1000, 5 * 1000 * 1000); a = g_new (gpointer, n); for (i = 0; i < n; i++) a[i] = GINT_TO_POINTER (g_test_rand_int ()); run_comparison (a, n, sizeof (gpointer), compare_pointer, NULL); g_free (a); } static void test_steps (void) { GtkTimSortRun change; GtkTimSort sort; int *a, *b; gsize i, n; n = g_test_rand_int_range (20 * 1000, 50 * 1000); a = g_new (int, n); for (i = 0; i < n; i++) a[i] = g_test_rand_int (); b = g_memdup2 (a, sizeof (int) * n); gtk_tim_sort_init (&sort, a, n, sizeof (int), compare_int, NULL); gtk_tim_sort_set_max_merge_size (&sort, g_test_rand_int_range (512, 2048)); while (gtk_tim_sort_step (&sort, &change)) { if (change.len) { int *a_start = change.base; int *b_start = b + ((int *) change.base - a); g_assert_cmpint (a_start[0], !=, b_start[0]); g_assert_cmpint (a_start[change.len - 1], !=, b_start[change.len - 1]); memcpy (b_start, a_start, change.len * sizeof (int)); } assert_sort_equal (a, b, int, n); } g_qsort_with_data (b, n, sizeof (int), compare_int, NULL); assert_sort_equal (a, b, int, n); gtk_tim_sort_finish (&sort); g_free (b); g_free (a); } int main (int argc, char *argv[]) { (g_test_init) (&argc, &argv, NULL); setlocale (LC_ALL, "C"); g_test_add_func ("/timsort/integers", test_integers); g_test_add_func ("/timsort/integers/runs", test_integers_runs); g_test_add_func ("/timsort/integers/huge", test_integers_huge); g_test_add_func ("/timsort/pointers", test_pointers); g_test_add_func ("/timsort/pointers/huge", test_pointers_huge); g_test_add_func ("/timsort/steps", test_steps); return g_test_run (); }