A Python parser for MediaWiki wikicode https://mwparserfromhell.readthedocs.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

359 lines
10 KiB

  1. /*
  2. * avl_tree.h - intrusive, nonrecursive AVL tree data structure (self-balancing
  3. * binary search tree), header file
  4. *
  5. * Written in 2014-2016 by Eric Biggers <ebiggers3@gmail.com>
  6. *
  7. * To the extent possible under law, the author(s) have dedicated all copyright
  8. * and related and neighboring rights to this software to the public domain
  9. * worldwide via the Creative Commons Zero 1.0 Universal Public Domain
  10. * Dedication (the "CC0").
  11. *
  12. * This software is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  14. * FOR A PARTICULAR PURPOSE. See the CC0 for more details.
  15. *
  16. * You should have received a copy of the CC0 along with this software; if not
  17. * see <http://creativecommons.org/publicdomain/zero/1.0/>.
  18. */
  19. #ifndef _AVL_TREE_H_
  20. #define _AVL_TREE_H_
  21. #include <stdbool.h>
  22. #include <stddef.h>
  23. #include <inttypes.h> /* for uintptr_t */
  24. #ifdef __GNUC__
  25. # define AVL_INLINE inline __attribute__((always_inline))
  26. #else
  27. # define AVL_INLINE inline
  28. #endif
  29. /* Node in an AVL tree. Embed this in some other data structure. */
  30. struct avl_tree_node {
  31. /* Pointer to left child or NULL */
  32. struct avl_tree_node *left;
  33. /* Pointer to right child or NULL */
  34. struct avl_tree_node *right;
  35. /* Pointer to parent combined with the balance factor. This saves 4 or
  36. * 8 bytes of memory depending on the CPU architecture.
  37. *
  38. * Low 2 bits: One greater than the balance factor of this subtree,
  39. * which is equal to height(right) - height(left). The mapping is:
  40. *
  41. * 00 => -1
  42. * 01 => 0
  43. * 10 => +1
  44. * 11 => undefined
  45. *
  46. * The rest of the bits are the pointer to the parent node. It must be
  47. * 4-byte aligned, and it will be NULL if this is the root node and
  48. * therefore has no parent. */
  49. uintptr_t parent_balance;
  50. };
  51. /* Cast an AVL tree node to the containing data structure. */
  52. #define avl_tree_entry(entry, type, member) \
  53. ((type*) ((char *)(entry) - offsetof(type, member)))
  54. /* Returns a pointer to the parent of the specified AVL tree node, or NULL if it
  55. * is already the root of the tree. */
  56. static AVL_INLINE struct avl_tree_node *
  57. avl_get_parent(const struct avl_tree_node *node)
  58. {
  59. return (struct avl_tree_node *)(node->parent_balance & ~3);
  60. }
  61. /* Marks the specified AVL tree node as unlinked from any tree. */
  62. static AVL_INLINE void
  63. avl_tree_node_set_unlinked(struct avl_tree_node *node)
  64. {
  65. node->parent_balance = (uintptr_t)node;
  66. }
  67. /* Returns true iff the specified AVL tree node has been marked with
  68. * avl_tree_node_set_unlinked() and has not subsequently been inserted into a
  69. * tree. */
  70. static AVL_INLINE bool
  71. avl_tree_node_is_unlinked(const struct avl_tree_node *node)
  72. {
  73. return node->parent_balance == (uintptr_t)node;
  74. }
  75. /* (Internal use only) */
  76. extern void
  77. avl_tree_rebalance_after_insert(struct avl_tree_node **root_ptr,
  78. struct avl_tree_node *inserted);
  79. /*
  80. * Looks up an item in the specified AVL tree.
  81. *
  82. * @root
  83. * Pointer to the root of the AVL tree. (This can be NULL --- that just
  84. * means the tree is empty.)
  85. *
  86. * @cmp_ctx
  87. * First argument to pass to the comparison callback. This generally
  88. * should be a pointer to an object equal to the one being searched for.
  89. *
  90. * @cmp
  91. * Comparison callback. Must return < 0, 0, or > 0 if the first argument
  92. * is less than, equal to, or greater than the second argument,
  93. * respectively. The first argument will be @cmp_ctx and the second
  94. * argument will be a pointer to the AVL tree node of an item in the tree.
  95. *
  96. * Returns a pointer to the AVL tree node of the resulting item, or NULL if the
  97. * item was not found.
  98. *
  99. * Example:
  100. *
  101. * struct int_wrapper {
  102. * int data;
  103. * struct avl_tree_node index_node;
  104. * };
  105. *
  106. * static int _avl_cmp_int_to_node(const void *intptr,
  107. * const struct avl_tree_node *nodeptr)
  108. * {
  109. * int n1 = *(const int *)intptr;
  110. * int n2 = avl_tree_entry(nodeptr, struct int_wrapper, index_node)->data;
  111. * if (n1 < n2)
  112. * return -1;
  113. * else if (n1 > n2)
  114. * return 1;
  115. * else
  116. * return 0;
  117. * }
  118. *
  119. * bool contains_int(struct avl_tree_node *root, int n)
  120. * {
  121. * struct avl_tree_node *result;
  122. *
  123. * result = avl_tree_lookup(root, &n, _avl_cmp_int_to_node);
  124. * return result ? true : false;
  125. * }
  126. */
  127. static AVL_INLINE struct avl_tree_node *
  128. avl_tree_lookup(const struct avl_tree_node *root,
  129. const void *cmp_ctx,
  130. int (*cmp)(const void *, const struct avl_tree_node *))
  131. {
  132. const struct avl_tree_node *cur = root;
  133. while (cur) {
  134. int res = (*cmp)(cmp_ctx, cur);
  135. if (res < 0)
  136. cur = cur->left;
  137. else if (res > 0)
  138. cur = cur->right;
  139. else
  140. break;
  141. }
  142. return (struct avl_tree_node*)cur;
  143. }
  144. /* Same as avl_tree_lookup(), but uses a more specific type for the comparison
  145. * function. Specifically, with this function the item being searched for is
  146. * expected to be in the same format as those already in the tree, with an
  147. * embedded 'struct avl_tree_node'. */
  148. static AVL_INLINE struct avl_tree_node *
  149. avl_tree_lookup_node(const struct avl_tree_node *root,
  150. const struct avl_tree_node *node,
  151. int (*cmp)(const struct avl_tree_node *,
  152. const struct avl_tree_node *))
  153. {
  154. const struct avl_tree_node *cur = root;
  155. while (cur) {
  156. int res = (*cmp)(node, cur);
  157. if (res < 0)
  158. cur = cur->left;
  159. else if (res > 0)
  160. cur = cur->right;
  161. else
  162. break;
  163. }
  164. return (struct avl_tree_node*)cur;
  165. }
  166. /*
  167. * Inserts an item into the specified AVL tree.
  168. *
  169. * @root_ptr
  170. * Location of the AVL tree's root pointer. Indirection is needed because
  171. * the root node may change as a result of rotations caused by the
  172. * insertion. Initialize *root_ptr to NULL for an empty tree.
  173. *
  174. * @item
  175. * Pointer to the `struct avl_tree_node' embedded in the item to insert.
  176. * No members in it need be pre-initialized, although members in the
  177. * containing structure should be pre-initialized so that @cmp can use them
  178. * in comparisons.
  179. *
  180. * @cmp
  181. * Comparison callback. Must return < 0, 0, or > 0 if the first argument
  182. * is less than, equal to, or greater than the second argument,
  183. * respectively. The first argument will be @item and the second
  184. * argument will be a pointer to an AVL tree node embedded in some
  185. * previously-inserted item to which @item is being compared.
  186. *
  187. * If no item in the tree is comparatively equal (via @cmp) to @item, inserts
  188. * @item and returns NULL. Otherwise does nothing and returns a pointer to the
  189. * AVL tree node embedded in the previously-inserted item which compared equal
  190. * to @item.
  191. *
  192. * Example:
  193. *
  194. * struct int_wrapper {
  195. * int data;
  196. * struct avl_tree_node index_node;
  197. * };
  198. *
  199. * #define GET_DATA(i) avl_tree_entry((i), struct int_wrapper, index_node)->data
  200. *
  201. * static int _avl_cmp_ints(const struct avl_tree_node *node1,
  202. * const struct avl_tree_node *node2)
  203. * {
  204. * int n1 = GET_DATA(node1);
  205. * int n2 = GET_DATA(node2);
  206. * if (n1 < n2)
  207. * return -1;
  208. * else if (n1 > n2)
  209. * return 1;
  210. * else
  211. * return 0;
  212. * }
  213. *
  214. * bool insert_int(struct avl_tree_node **root_ptr, int data)
  215. * {
  216. * struct int_wrapper *i = malloc(sizeof(struct int_wrapper));
  217. * i->data = data;
  218. * if (avl_tree_insert(root_ptr, &i->index_node, _avl_cmp_ints)) {
  219. * // Duplicate.
  220. * free(i);
  221. * return false;
  222. * }
  223. * return true;
  224. * }
  225. */
  226. static AVL_INLINE struct avl_tree_node *
  227. avl_tree_insert(struct avl_tree_node **root_ptr,
  228. struct avl_tree_node *item,
  229. int (*cmp)(const struct avl_tree_node *,
  230. const struct avl_tree_node *))
  231. {
  232. struct avl_tree_node **cur_ptr = root_ptr, *cur = NULL;
  233. int res;
  234. while (*cur_ptr) {
  235. cur = *cur_ptr;
  236. res = (*cmp)(item, cur);
  237. if (res < 0)
  238. cur_ptr = &cur->left;
  239. else if (res > 0)
  240. cur_ptr = &cur->right;
  241. else
  242. return cur;
  243. }
  244. *cur_ptr = item;
  245. item->parent_balance = (uintptr_t)cur | 1;
  246. avl_tree_rebalance_after_insert(root_ptr, item);
  247. return NULL;
  248. }
  249. /* Removes an item from the specified AVL tree.
  250. * See implementation for details. */
  251. extern void
  252. avl_tree_remove(struct avl_tree_node **root_ptr, struct avl_tree_node *node);
  253. /* Nonrecursive AVL tree traversal functions */
  254. extern struct avl_tree_node *
  255. avl_tree_first_in_order(const struct avl_tree_node *root);
  256. extern struct avl_tree_node *
  257. avl_tree_last_in_order(const struct avl_tree_node *root);
  258. extern struct avl_tree_node *
  259. avl_tree_next_in_order(const struct avl_tree_node *node);
  260. extern struct avl_tree_node *
  261. avl_tree_prev_in_order(const struct avl_tree_node *node);
  262. extern struct avl_tree_node *
  263. avl_tree_first_in_postorder(const struct avl_tree_node *root);
  264. extern struct avl_tree_node *
  265. avl_tree_next_in_postorder(const struct avl_tree_node *prev,
  266. const struct avl_tree_node *prev_parent);
  267. /*
  268. * Iterate through the nodes in an AVL tree in sorted order.
  269. * You may not modify the tree during the iteration.
  270. *
  271. * @child_struct
  272. * Variable that will receive a pointer to each struct inserted into the
  273. * tree.
  274. * @root
  275. * Root of the AVL tree.
  276. * @struct_name
  277. * Type of *child_struct.
  278. * @struct_member
  279. * Member of @struct_name type that is the AVL tree node.
  280. *
  281. * Example:
  282. *
  283. * struct int_wrapper {
  284. * int data;
  285. * struct avl_tree_node index_node;
  286. * };
  287. *
  288. * void print_ints(struct avl_tree_node *root)
  289. * {
  290. * struct int_wrapper *i;
  291. *
  292. * avl_tree_for_each_in_order(i, root, struct int_wrapper, index_node)
  293. * printf("%d\n", i->data);
  294. * }
  295. */
  296. #define avl_tree_for_each_in_order(child_struct, root, \
  297. struct_name, struct_member) \
  298. for (struct avl_tree_node *_cur = \
  299. avl_tree_first_in_order(root); \
  300. _cur && ((child_struct) = \
  301. avl_tree_entry(_cur, struct_name, \
  302. struct_member), 1); \
  303. _cur = avl_tree_next_in_order(_cur))
  304. /*
  305. * Like avl_tree_for_each_in_order(), but uses the reverse order.
  306. */
  307. #define avl_tree_for_each_in_reverse_order(child_struct, root, \
  308. struct_name, struct_member) \
  309. for (struct avl_tree_node *_cur = \
  310. avl_tree_last_in_order(root); \
  311. _cur && ((child_struct) = \
  312. avl_tree_entry(_cur, struct_name, \
  313. struct_member), 1); \
  314. _cur = avl_tree_prev_in_order(_cur))
  315. /*
  316. * Like avl_tree_for_each_in_order(), but iterates through the nodes in
  317. * postorder, so the current node may be deleted or freed.
  318. */
  319. #define avl_tree_for_each_in_postorder(child_struct, root, \
  320. struct_name, struct_member) \
  321. for (struct avl_tree_node *_cur = \
  322. avl_tree_first_in_postorder(root), *_parent; \
  323. _cur && ((child_struct) = \
  324. avl_tree_entry(_cur, struct_name, \
  325. struct_member), 1) \
  326. && (_parent = avl_get_parent(_cur), 1); \
  327. _cur = avl_tree_next_in_postorder(_cur, _parent))
  328. #endif /* _AVL_TREE_H_ */