rbtree.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Copyright (c) 2010, 2011 Richard Braun.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. *
  25. *
  26. * Red-black tree.
  27. */
  28. #ifndef _KERN_RBTREE_H
  29. #define _KERN_RBTREE_H
  30. /** @file */
  31. #include <stddef.h>
  32. #include <assert.h>
  33. #include <stdint.h>
  34. #include <sys/types.h>
  35. #include <starpu_util.h>
  36. #define MACRO_BEGIN ({
  37. #define MACRO_END })
  38. /*
  39. * Indexes of the left and right nodes in the children array of a node.
  40. */
  41. #define STARPU_RBTREE_LEFT 0
  42. #define STARPU_RBTREE_RIGHT 1
  43. /**
  44. * Red-black node.
  45. */
  46. struct starpu_rbtree_node;
  47. /**
  48. * Red-black tree.
  49. */
  50. struct starpu_rbtree;
  51. /**
  52. * Static tree initializer.
  53. */
  54. #define STARPU_RBTREE_INITIALIZER { NULL }
  55. #include "rbtree_i.h"
  56. /**
  57. * Initialize a tree.
  58. */
  59. static inline void starpu_rbtree_init(struct starpu_rbtree *tree)
  60. {
  61. tree->root = NULL;
  62. }
  63. /**
  64. * This version assumes that the content of tree was already zeroed
  65. */
  66. static inline void starpu_rbtree_init0(struct starpu_rbtree *tree STARPU_ATTRIBUTE_UNUSED)
  67. {
  68. }
  69. /**
  70. * Initialize a node.
  71. *
  72. * A node is in no tree when its parent points to itself.
  73. */
  74. static inline void starpu_rbtree_node_init(struct starpu_rbtree_node *node)
  75. {
  76. assert(starpu_rbtree_check_alignment(node));
  77. node->parent = (uintptr_t)node | STARPU_RBTREE_COLOR_RED;
  78. node->children[STARPU_RBTREE_LEFT] = NULL;
  79. node->children[STARPU_RBTREE_RIGHT] = NULL;
  80. }
  81. /**
  82. * This version assumes that the content of node was already zeroed
  83. */
  84. static inline void starpu_rbtree_node_init0(struct starpu_rbtree_node *node)
  85. {
  86. assert(starpu_rbtree_check_alignment(node));
  87. node->parent = (uintptr_t)node | STARPU_RBTREE_COLOR_RED;
  88. //node->children[STARPU_RBTREE_LEFT] = NULL;
  89. //node->children[STARPU_RBTREE_RIGHT] = NULL;
  90. }
  91. /**
  92. * Return true if node is in no tree.
  93. */
  94. static inline int starpu_rbtree_node_unlinked(const struct starpu_rbtree_node *node)
  95. {
  96. return starpu_rbtree_parent(node) == node;
  97. }
  98. /**
  99. * Macro that evaluates to the address of the structure containing the
  100. * given node based on the given type and member.
  101. */
  102. #define starpu_rbtree_entry(node, type, member) structof(node, type, member)
  103. /**
  104. * Return true if tree is empty.
  105. */
  106. static inline int starpu_rbtree_empty(const struct starpu_rbtree *tree)
  107. {
  108. return tree->root == NULL;
  109. }
  110. /**
  111. * Look up a node in a tree.
  112. *
  113. * Note that implementing the lookup algorithm as a macro gives two benefits:
  114. * First, it avoids the overhead of a callback function. Next, the type of the
  115. * cmp_fn parameter isn't rigid. The only guarantee offered by this
  116. * implementation is that the key parameter is the first parameter given to
  117. * cmp_fn. This way, users can pass only the value they need for comparison
  118. * instead of e.g. allocating a full structure on the stack.
  119. *
  120. * See starpu_rbtree_insert().
  121. */
  122. #define starpu_rbtree_lookup(tree, key, cmp_fn) \
  123. MACRO_BEGIN \
  124. struct starpu_rbtree_node *___cur; \
  125. int ___diff; \
  126. \
  127. ___cur = (tree)->root; \
  128. \
  129. while (___cur != NULL) { \
  130. ___diff = cmp_fn(key, ___cur); \
  131. \
  132. if (___diff == 0) \
  133. break; \
  134. \
  135. ___cur = ___cur->children[starpu_rbtree_d2i(___diff)]; \
  136. } \
  137. \
  138. ___cur; \
  139. MACRO_END
  140. /**
  141. * Look up a node or one of its nearest nodes in a tree.
  142. *
  143. * This macro essentially acts as starpu_rbtree_lookup() but if no entry matched
  144. * the key, an additional step is performed to obtain the next or previous
  145. * node, depending on the direction (left or right).
  146. *
  147. * The constraints that apply to the key parameter are the same as for
  148. * starpu_rbtree_lookup().
  149. */
  150. #define starpu_rbtree_lookup_nearest(tree, key, cmp_fn, dir) \
  151. MACRO_BEGIN \
  152. struct starpu_rbtree_node *___cur, *___prev; \
  153. int ___diff, ___index; \
  154. \
  155. ___prev = NULL; \
  156. ___index = -1; \
  157. ___cur = (tree)->root; \
  158. \
  159. while (___cur != NULL) { \
  160. ___diff = cmp_fn(key, ___cur); \
  161. \
  162. if (___diff == 0) \
  163. break; \
  164. \
  165. ___prev = ___cur; \
  166. ___index = starpu_rbtree_d2i(___diff); \
  167. ___cur = ___cur->children[___index]; \
  168. } \
  169. \
  170. if (___cur == NULL) \
  171. ___cur = starpu_rbtree_nearest(___prev, ___index, dir); \
  172. \
  173. ___cur; \
  174. MACRO_END
  175. /**
  176. * Insert a node in a tree.
  177. *
  178. * This macro performs a standard lookup to obtain the insertion point of
  179. * the given node in the tree (it is assumed that the inserted node never
  180. * compares equal to any other entry in the tree) and links the node. It
  181. * then checks red-black rules violations, and rebalances the tree if
  182. * necessary.
  183. *
  184. * Unlike starpu_rbtree_lookup(), the cmp_fn parameter must compare two complete
  185. * entries, so it is suggested to use two different comparison inline
  186. * functions, such as myobj_cmp_lookup() and myobj_cmp_insert(). There is no
  187. * guarantee about the order of the nodes given to the comparison function.
  188. *
  189. * See starpu_rbtree_lookup().
  190. */
  191. #define starpu_rbtree_insert(tree, node, cmp_fn) \
  192. MACRO_BEGIN \
  193. struct starpu_rbtree_node *___cur, *___prev; \
  194. int ___diff, ___index; \
  195. \
  196. ___prev = NULL; \
  197. ___index = -1; \
  198. ___cur = (tree)->root; \
  199. \
  200. while (___cur != NULL) { \
  201. ___diff = cmp_fn(node, ___cur); \
  202. assert(___diff != 0); \
  203. ___prev = ___cur; \
  204. ___index = starpu_rbtree_d2i(___diff); \
  205. ___cur = ___cur->children[___index]; \
  206. } \
  207. \
  208. starpu_rbtree_insert_rebalance(tree, ___prev, ___index, node); \
  209. MACRO_END
  210. /**
  211. * Look up a node/slot pair in a tree.
  212. *
  213. * This macro essentially acts as starpu_rbtree_lookup() but in addition to a node,
  214. * it also returns a slot, which identifies an insertion point in the tree.
  215. * If the returned node is null, the slot can be used by starpu_rbtree_insert_slot()
  216. * to insert without the overhead of an additional lookup. The slot is a
  217. * simple uintptr_t integer.
  218. *
  219. * The constraints that apply to the key parameter are the same as for
  220. * starpu_rbtree_lookup().
  221. */
  222. #define starpu_rbtree_lookup_slot(tree, key, cmp_fn, slot) \
  223. MACRO_BEGIN \
  224. struct starpu_rbtree_node *___cur, *___prev; \
  225. int ___diff, ___index; \
  226. \
  227. ___prev = NULL; \
  228. ___index = 0; \
  229. ___cur = (tree)->root; \
  230. \
  231. while (___cur != NULL) { \
  232. ___diff = cmp_fn(key, ___cur); \
  233. \
  234. if (___diff == 0) \
  235. break; \
  236. \
  237. ___prev = ___cur; \
  238. ___index = starpu_rbtree_d2i(___diff); \
  239. ___cur = ___cur->children[___index]; \
  240. } \
  241. \
  242. (slot) = starpu_rbtree_slot(___prev, ___index); \
  243. ___cur; \
  244. MACRO_END
  245. /**
  246. * Insert a node at an insertion point in a tree.
  247. *
  248. * This macro essentially acts as starpu_rbtree_insert() except that it doesn't
  249. * obtain the insertion point with a standard lookup. The insertion point
  250. * is obtained by calling starpu_rbtree_lookup_slot(). In addition, the new node
  251. * must not compare equal to an existing node in the tree (i.e. the slot
  252. * must denote a null node).
  253. */
  254. static inline void starpu_rbtree_insert_slot(struct starpu_rbtree *tree, uintptr_t slot,
  255. struct starpu_rbtree_node *node)
  256. {
  257. struct starpu_rbtree_node *parent;
  258. int index;
  259. parent = starpu_rbtree_slot_parent(slot);
  260. index = starpu_rbtree_slot_index(slot);
  261. starpu_rbtree_insert_rebalance(tree, parent, index, node);
  262. }
  263. /**
  264. * Remove a node from a tree.
  265. *
  266. * After completion, the node is stale.
  267. */
  268. void starpu_rbtree_remove(struct starpu_rbtree *tree, struct starpu_rbtree_node *node);
  269. /**
  270. * Return the first node of a tree.
  271. */
  272. /* TODO: optimize by maintaining the first node of the tree */
  273. #define starpu_rbtree_first(tree) starpu_rbtree_firstlast(tree, STARPU_RBTREE_LEFT)
  274. /**
  275. * Return the last node of a tree.
  276. */
  277. /* TODO: optimize by maintaining the first node of the tree */
  278. /* TODO: could be useful to optimize the case when the key being inserted is
  279. * bigger that the biggest node */
  280. #define starpu_rbtree_last(tree) starpu_rbtree_firstlast(tree, STARPU_RBTREE_RIGHT)
  281. /**
  282. * Return the node previous to the given node.
  283. */
  284. #define starpu_rbtree_prev(node) starpu_rbtree_walk(node, STARPU_RBTREE_LEFT)
  285. /**
  286. * Return the node next to the given node.
  287. */
  288. #define starpu_rbtree_next(node) starpu_rbtree_walk(node, STARPU_RBTREE_RIGHT)
  289. /**
  290. * Forge a loop to process all nodes of a tree, removing them when visited.
  291. *
  292. * This macro can only be used to destroy a tree, so that the resources used
  293. * by the entries can be released by the user. It basically removes all nodes
  294. * without doing any color checking.
  295. *
  296. * After completion, all nodes and the tree root member are stale.
  297. */
  298. #define starpu_rbtree_for_each_remove(tree, node, tmp) \
  299. for (node = starpu_rbtree_postwalk_deepest(tree), \
  300. tmp = starpu_rbtree_postwalk_unlink(node); \
  301. node != NULL; \
  302. node = tmp, tmp = starpu_rbtree_postwalk_unlink(node)) \
  303. #endif /* _KERN_RBTREE_H */