phpdbg_btree.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Felipe Pena <felipe@php.net> |
  16. | Authors: Joe Watkins <joe.watkins@live.co.uk> |
  17. | Authors: Bob Weinand <bwoebi@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #include "phpdbg_btree.h"
  21. #include "phpdbg.h"
  22. #define CHOOSE_BRANCH(n) \
  23. branch = branch->branches[!!(n)];
  24. #ifdef _Win32
  25. # undef pemalloc
  26. # undef pefree
  27. # define pemalloc(size, persistent) malloc(size)
  28. # define pefree(ptr, persistent) free(ptr)
  29. #endif
  30. /* depth in bits */
  31. void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) {
  32. tree->depth = depth;
  33. tree->branch = NULL;
  34. tree->persistent = 0;
  35. tree->count = 0;
  36. }
  37. phpdbg_btree_result *phpdbg_btree_find(phpdbg_btree *tree, zend_ulong idx) {
  38. phpdbg_btree_branch *branch = tree->branch;
  39. int i = tree->depth - 1;
  40. if (branch == NULL) {
  41. return NULL;
  42. }
  43. do {
  44. if ((idx >> i) % 2 == 1) {
  45. if (branch->branches[1]) {
  46. CHOOSE_BRANCH(1);
  47. } else {
  48. return NULL;
  49. }
  50. } else {
  51. if (branch->branches[0]) {
  52. CHOOSE_BRANCH(0);
  53. } else {
  54. return NULL;
  55. }
  56. }
  57. } while (i--);
  58. return &branch->result;
  59. }
  60. phpdbg_btree_result *phpdbg_btree_find_closest(phpdbg_btree *tree, zend_ulong idx) {
  61. phpdbg_btree_branch *branch = tree->branch;
  62. int i = tree->depth - 1, last_superior_i = -1;
  63. if (branch == NULL) {
  64. return NULL;
  65. }
  66. /* find nearest watchpoint */
  67. do {
  68. if ((idx >> i) % 2 == 0) {
  69. if (branch->branches[0]) {
  70. CHOOSE_BRANCH(0);
  71. /* an impossible branch was found if: */
  72. } else {
  73. /* there's no lower branch than idx */
  74. if (last_superior_i == -1) {
  75. /* failure */
  76. return NULL;
  77. }
  78. /* reset state */
  79. branch = tree->branch;
  80. i = tree->depth - 1;
  81. /* follow branch according to bits in idx until the last lower branch before the impossible branch */
  82. do {
  83. CHOOSE_BRANCH((idx >> i) % 2 == 1 && branch->branches[1]);
  84. } while (--i > last_superior_i);
  85. /* use now the lower branch of which we can be sure that it contains only branches lower than idx */
  86. CHOOSE_BRANCH(0);
  87. /* and choose the highest possible branch in the branch containing only branches lower than idx */
  88. while (i--) {
  89. CHOOSE_BRANCH(branch->branches[1]);
  90. }
  91. break;
  92. }
  93. /* follow branch according to bits in idx until having found an impossible branch */
  94. } else {
  95. if (branch->branches[1]) {
  96. if (branch->branches[0]) {
  97. last_superior_i = i;
  98. }
  99. CHOOSE_BRANCH(1);
  100. } else {
  101. CHOOSE_BRANCH(0);
  102. while (i--) {
  103. CHOOSE_BRANCH(branch->branches[1]);
  104. }
  105. break;
  106. }
  107. }
  108. } while (i--);
  109. return &branch->result;
  110. }
  111. phpdbg_btree_position phpdbg_btree_find_between(phpdbg_btree *tree, zend_ulong lower_idx, zend_ulong higher_idx) {
  112. phpdbg_btree_position pos;
  113. pos.tree = tree;
  114. pos.end = lower_idx;
  115. pos.cur = higher_idx;
  116. return pos;
  117. }
  118. phpdbg_btree_result *phpdbg_btree_next(phpdbg_btree_position *pos) {
  119. phpdbg_btree_result *result = phpdbg_btree_find_closest(pos->tree, pos->cur);
  120. if (result == NULL || result->idx < pos->end) {
  121. return NULL;
  122. }
  123. pos->cur = result->idx - 1;
  124. return result;
  125. }
  126. int phpdbg_btree_insert_or_update(phpdbg_btree *tree, zend_ulong idx, void *ptr, int flags) {
  127. int i = tree->depth - 1;
  128. phpdbg_btree_branch **branch = &tree->branch;
  129. do {
  130. if (*branch == NULL) {
  131. break;
  132. }
  133. branch = &(*branch)->branches[(idx >> i) % 2];
  134. } while (i--);
  135. if (*branch == NULL) {
  136. if (!(flags & PHPDBG_BTREE_INSERT)) {
  137. return FAILURE;
  138. }
  139. {
  140. phpdbg_btree_branch *memory = *branch = pemalloc((i + 2) * sizeof(phpdbg_btree_branch), tree->persistent);
  141. do {
  142. (*branch)->branches[!((idx >> i) % 2)] = NULL;
  143. branch = &(*branch)->branches[(idx >> i) % 2];
  144. *branch = ++memory;
  145. } while (i--);
  146. tree->count++;
  147. }
  148. } else if (!(flags & PHPDBG_BTREE_UPDATE)) {
  149. return FAILURE;
  150. }
  151. (*branch)->result.idx = idx;
  152. (*branch)->result.ptr = ptr;
  153. return SUCCESS;
  154. }
  155. int phpdbg_btree_delete(phpdbg_btree *tree, zend_ulong idx) {
  156. int i = tree->depth;
  157. phpdbg_btree_branch *branch = tree->branch;
  158. int i_last_dual_branch = -1, last_dual_branch_branch;
  159. phpdbg_btree_branch *last_dual_branch = NULL;
  160. goto check_branch_existence;
  161. do {
  162. if (branch->branches[0] && branch->branches[1]) {
  163. last_dual_branch = branch;
  164. i_last_dual_branch = i;
  165. last_dual_branch_branch = (idx >> i) % 2;
  166. }
  167. branch = branch->branches[(idx >> i) % 2];
  168. check_branch_existence:
  169. if (branch == NULL) {
  170. return FAILURE;
  171. }
  172. } while (i--);
  173. tree->count--;
  174. if (i_last_dual_branch == -1) {
  175. pefree(tree->branch, tree->persistent);
  176. tree->branch = NULL;
  177. } else {
  178. if (last_dual_branch->branches[last_dual_branch_branch] == last_dual_branch + 1) {
  179. phpdbg_btree_branch *original_branch = last_dual_branch->branches[!last_dual_branch_branch];
  180. memcpy(last_dual_branch + 1, last_dual_branch->branches[!last_dual_branch_branch], (i_last_dual_branch + 1) * sizeof(phpdbg_btree_branch));
  181. pefree(last_dual_branch->branches[!last_dual_branch_branch], tree->persistent);
  182. last_dual_branch->branches[!last_dual_branch_branch] = last_dual_branch + 1;
  183. branch = last_dual_branch->branches[!last_dual_branch_branch];
  184. for (i = i_last_dual_branch; i--;) {
  185. branch = (branch->branches[branch->branches[1] == ++original_branch] = last_dual_branch + i_last_dual_branch - i + 1);
  186. }
  187. } else {
  188. pefree(last_dual_branch->branches[last_dual_branch_branch], tree->persistent);
  189. }
  190. last_dual_branch->branches[last_dual_branch_branch] = NULL;
  191. }
  192. return SUCCESS;
  193. }
  194. void phpdbg_btree_clean_recursive(phpdbg_btree_branch *branch, zend_ulong depth, zend_bool persistent) {
  195. phpdbg_btree_branch *start = branch;
  196. while (depth--) {
  197. zend_bool use_branch = branch + 1 == branch->branches[0];
  198. if (branch->branches[use_branch]) {
  199. phpdbg_btree_clean_recursive(branch->branches[use_branch], depth, persistent);
  200. }
  201. }
  202. pefree(start, persistent);
  203. }
  204. void phpdbg_btree_clean(phpdbg_btree *tree) {
  205. if (tree->branch) {
  206. phpdbg_btree_clean_recursive(tree->branch, tree->depth, tree->persistent);
  207. tree->branch = NULL;
  208. tree->count = 0;
  209. }
  210. }
  211. void phpdbg_btree_branch_dump(phpdbg_btree_branch *branch, zend_ulong depth) {
  212. if (branch) {
  213. if (depth--) {
  214. phpdbg_btree_branch_dump(branch->branches[0], depth);
  215. phpdbg_btree_branch_dump(branch->branches[1], depth);
  216. } else {
  217. fprintf(stderr, "%p: %p\n", (void *) branch->result.idx, branch->result.ptr);
  218. }
  219. }
  220. }
  221. void phpdbg_btree_dump(phpdbg_btree *tree) {
  222. phpdbg_btree_branch_dump(tree->branch, tree->depth);
  223. }