sort.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
  4. *
  5. * Jan 23 2005 Matt Mackall <mpm@selenic.com>
  6. */
  7. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  8. #include <linux/types.h>
  9. #include <linux/export.h>
  10. #include <linux/sort.h>
  11. static int alignment_ok(const void *base, int align)
  12. {
  13. return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
  14. ((unsigned long)base & (align - 1)) == 0;
  15. }
  16. static void u32_swap(void *a, void *b, int size)
  17. {
  18. u32 t = *(u32 *)a;
  19. *(u32 *)a = *(u32 *)b;
  20. *(u32 *)b = t;
  21. }
  22. static void u64_swap(void *a, void *b, int size)
  23. {
  24. u64 t = *(u64 *)a;
  25. *(u64 *)a = *(u64 *)b;
  26. *(u64 *)b = t;
  27. }
  28. static void generic_swap(void *a, void *b, int size)
  29. {
  30. char t;
  31. do {
  32. t = *(char *)a;
  33. *(char *)a++ = *(char *)b;
  34. *(char *)b++ = t;
  35. } while (--size > 0);
  36. }
  37. /**
  38. * sort - sort an array of elements
  39. * @base: pointer to data to sort
  40. * @num: number of elements
  41. * @size: size of each element
  42. * @cmp_func: pointer to comparison function
  43. * @swap_func: pointer to swap function or NULL
  44. *
  45. * This function does a heapsort on the given array. You may provide a
  46. * swap_func function optimized to your element type.
  47. *
  48. * Sorting time is O(n log n) both on average and worst-case. While
  49. * qsort is about 20% faster on average, it suffers from exploitable
  50. * O(n*n) worst-case behavior and extra memory requirements that make
  51. * it less suitable for kernel use.
  52. */
  53. void sort(void *base, size_t num, size_t size,
  54. int (*cmp_func)(const void *, const void *),
  55. void (*swap_func)(void *, void *, int size))
  56. {
  57. /* pre-scale counters for performance */
  58. int i = (num/2 - 1) * size, n = num * size, c, r;
  59. if (!swap_func) {
  60. if (size == 4 && alignment_ok(base, 4))
  61. swap_func = u32_swap;
  62. else if (size == 8 && alignment_ok(base, 8))
  63. swap_func = u64_swap;
  64. else
  65. swap_func = generic_swap;
  66. }
  67. /* heapify */
  68. for ( ; i >= 0; i -= size) {
  69. for (r = i; r * 2 + size < n; r = c) {
  70. c = r * 2 + size;
  71. if (c < n - size &&
  72. cmp_func(base + c, base + c + size) < 0)
  73. c += size;
  74. if (cmp_func(base + r, base + c) >= 0)
  75. break;
  76. swap_func(base + r, base + c, size);
  77. }
  78. }
  79. /* sort */
  80. for (i = n - size; i > 0; i -= size) {
  81. swap_func(base, base + i, size);
  82. for (r = 0; r * 2 + size < i; r = c) {
  83. c = r * 2 + size;
  84. if (c < i - size &&
  85. cmp_func(base + c, base + c + size) < 0)
  86. c += size;
  87. if (cmp_func(base + r, base + c) >= 0)
  88. break;
  89. swap_func(base + r, base + c, size);
  90. }
  91. }
  92. }
  93. EXPORT_SYMBOL(sort);