PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/sapi/phpdbg/phpdbg_btree.c

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