zend_qsort.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Sterling Hughes <sterling@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #include "zend.h"
  20. #include "zend_qsort.h"
  21. #include <limits.h>
  22. #define QSORT_STACK_SIZE (sizeof(size_t) * CHAR_BIT)
  23. static void _zend_qsort_swap(void *a, void *b, size_t siz)
  24. {
  25. register char *tmp_a_char;
  26. register char *tmp_b_char;
  27. register int *tmp_a_int;
  28. register int *tmp_b_int;
  29. register size_t i;
  30. int t_i;
  31. char t_c;
  32. tmp_a_int = (int *) a;
  33. tmp_b_int = (int *) b;
  34. for (i = sizeof(int); i <= siz; i += sizeof(int)) {
  35. t_i = *tmp_a_int;
  36. *tmp_a_int++ = *tmp_b_int;
  37. *tmp_b_int++ = t_i;
  38. }
  39. tmp_a_char = (char *) tmp_a_int;
  40. tmp_b_char = (char *) tmp_b_int;
  41. for (i = i - sizeof(int) + 1; i <= siz; ++i) {
  42. t_c = *tmp_a_char;
  43. *tmp_a_char++ = *tmp_b_char;
  44. *tmp_b_char++ = t_c;
  45. }
  46. }
  47. ZEND_API void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare, void *arg TSRMLS_DC)
  48. {
  49. void *begin_stack[QSORT_STACK_SIZE];
  50. void *end_stack[QSORT_STACK_SIZE];
  51. register char *begin;
  52. register char *end;
  53. register char *seg1;
  54. register char *seg2;
  55. register char *seg2p;
  56. register int loop;
  57. uint offset;
  58. begin_stack[0] = (char *) base;
  59. end_stack[0] = (char *) base + ((nmemb - 1) * siz);
  60. for (loop = 0; loop >= 0; --loop) {
  61. begin = begin_stack[loop];
  62. end = end_stack[loop];
  63. while (begin < end) {
  64. offset = (end - begin) >> 1;
  65. _zend_qsort_swap(begin, begin + (offset - (offset % siz)), siz);
  66. seg1 = begin + siz;
  67. seg2 = end;
  68. while (1) {
  69. for (; seg1 < seg2 && compare(begin, seg1 TSRMLS_CC, arg) > 0;
  70. seg1 += siz);
  71. for (; seg2 >= seg1 && compare(seg2, begin TSRMLS_CC, arg) > 0;
  72. seg2 -= siz);
  73. if (seg1 >= seg2)
  74. break;
  75. _zend_qsort_swap(seg1, seg2, siz);
  76. seg1 += siz;
  77. seg2 -= siz;
  78. }
  79. _zend_qsort_swap(begin, seg2, siz);
  80. seg2p = seg2;
  81. if ((seg2p - begin) <= (end - seg2p)) {
  82. if ((seg2p + siz) < end) {
  83. begin_stack[loop] = seg2p + siz;
  84. end_stack[loop++] = end;
  85. }
  86. end = seg2p - siz;
  87. }
  88. else {
  89. if ((seg2p - siz) > begin) {
  90. begin_stack[loop] = begin;
  91. end_stack[loop++] = seg2p - siz;
  92. }
  93. begin = seg2p + siz;
  94. }
  95. }
  96. }
  97. }
  98. ZEND_API void zend_qsort(void *base, size_t nmemb, size_t siz, compare_func_t compare TSRMLS_DC)
  99. {
  100. zend_qsort_r(base, nmemb, siz, (compare_r_func_t)compare, NULL TSRMLS_CC);
  101. }
  102. /*
  103. * Local Variables:
  104. * c-basic-offset: 4
  105. * tab-width: 4
  106. * End:
  107. * vim600: fdm=marker
  108. * vim: noet sw=4 ts=4
  109. */