PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ext/timeouts/bench/bench-llrb.c

https://gitlab.com/teor/tor
C | 425 lines | 322 code | 52 blank | 51 comment | 78 complexity | a133bac06a0f81dd0e66cc0f78ebb722 MD5 | raw file
  1. /* ==========================================================================
  2. * llrb.h - Iterative Left-leaning Red-Black Tree.
  3. * --------------------------------------------------------------------------
  4. * Copyright (c) 2011, 2013 William Ahern <william@25thandClement.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to permit
  11. * persons to whom the Software is furnished to do so, subject to the
  12. * following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  20. * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  21. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  22. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  23. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. * --------------------------------------------------------------------------
  25. * CREDITS:
  26. * o Algorithm courtesy of Robert Sedgewick, "Left-leaning Red-Black
  27. * Trees" (September 2008); and Robert Sedgewick and Kevin Wayne,
  28. * Algorithms (4th ed. 2011).
  29. *
  30. * Sedgewick touts the simplicity of the recursive implementation,
  31. * but at least for the 2-3 tree variant the iterative approach is
  32. * almost line-for-line identical. The magic of C pointers helps;
  33. * it'd be uglier with Java.
  34. *
  35. * A couple of missing NULL checks were added to Sedgewick's deletion
  36. * example, and insert was optimized to short-circuit rotations when
  37. * walking up the tree.
  38. *
  39. * o Code implemented in the fashion of Niels Provos' excellent *BSD
  40. * sys/tree.h pre-processor library.
  41. *
  42. * Regarding relative performance, I've refrained from sharing my own
  43. * benchmarks. Differences in run-time speed were too correlated to
  44. * compiler options and other external factors.
  45. *
  46. * Provos' delete implementation doesn't need to start at the root of
  47. * the tree. However, RB_REMOVE must be passed the actual node to be
  48. * removed. LLRB_REMOVE merely requires a key, much like
  49. * RB_FIND/LLRB_FIND.
  50. * ==========================================================================
  51. */
  52. #ifndef LLRB_H
  53. #define LLRB_H
  54. #define LLRB_VENDOR "william@25thandClement.com"
  55. #define LLRB_VERSION 0x20130925
  56. #ifndef LLRB_STATIC
  57. #ifdef __GNUC__
  58. #define LLRB_STATIC __attribute__((__unused__)) static
  59. #else
  60. #define LLRB_STATIC static
  61. #endif
  62. #endif
  63. #define LLRB_HEAD(name, type) \
  64. struct name { struct type *rbh_root; }
  65. #define LLRB_INITIALIZER(root) { 0 }
  66. #define LLRB_INIT(root) do { (root)->rbh_root = 0; } while (0)
  67. #define LLRB_BLACK 0
  68. #define LLRB_RED 1
  69. #define LLRB_ENTRY(type) \
  70. struct { struct type *rbe_left, *rbe_right, *rbe_parent; _Bool rbe_color; }
  71. #define LLRB_LEFT(elm, field) (elm)->field.rbe_left
  72. #define LLRB_RIGHT(elm, field) (elm)->field.rbe_right
  73. #define LLRB_PARENT(elm, field) (elm)->field.rbe_parent
  74. #define LLRB_EDGE(head, elm, field) (((elm) == LLRB_ROOT(head))? &LLRB_ROOT(head) : ((elm) == LLRB_LEFT(LLRB_PARENT((elm), field), field))? &LLRB_LEFT(LLRB_PARENT((elm), field), field) : &LLRB_RIGHT(LLRB_PARENT((elm), field), field))
  75. #define LLRB_COLOR(elm, field) (elm)->field.rbe_color
  76. #define LLRB_ROOT(head) (head)->rbh_root
  77. #define LLRB_EMPTY(head) ((head)->rbh_root == 0)
  78. #define LLRB_ISRED(elm, field) ((elm) && LLRB_COLOR((elm), field) == LLRB_RED)
  79. #define LLRB_PROTOTYPE(name, type, field, cmp) \
  80. LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
  81. #define LLRB_PROTOTYPE_STATIC(name, type, field, cmp) \
  82. LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp, LLRB_STATIC)
  83. #define LLRB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
  84. attr struct type *name##_LLRB_INSERT(struct name *, struct type *); \
  85. attr struct type *name##_LLRB_DELETE(struct name *, struct type *); \
  86. attr struct type *name##_LLRB_FIND(struct name *, struct type *); \
  87. attr struct type *name##_LLRB_MIN(struct type *); \
  88. attr struct type *name##_LLRB_MAX(struct type *); \
  89. attr struct type *name##_LLRB_NEXT(struct type *);
  90. #define LLRB_GENERATE(name, type, field, cmp) \
  91. LLRB_GENERATE_INTERNAL(name, type, field, cmp,)
  92. #define LLRB_GENERATE_STATIC(name, type, field, cmp) \
  93. LLRB_GENERATE_INTERNAL(name, type, field, cmp, LLRB_STATIC)
  94. #define LLRB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
  95. static inline void name##_LLRB_ROTL(struct type **pivot) { \
  96. struct type *a = *pivot; \
  97. struct type *b = LLRB_RIGHT(a, field); \
  98. if ((LLRB_RIGHT(a, field) = LLRB_LEFT(b, field))) \
  99. LLRB_PARENT(LLRB_RIGHT(a, field), field) = a; \
  100. LLRB_LEFT(b, field) = a; \
  101. LLRB_COLOR(b, field) = LLRB_COLOR(a, field); \
  102. LLRB_COLOR(a, field) = LLRB_RED; \
  103. LLRB_PARENT(b, field) = LLRB_PARENT(a, field); \
  104. LLRB_PARENT(a, field) = b; \
  105. *pivot = b; \
  106. } \
  107. static inline void name##_LLRB_ROTR(struct type **pivot) { \
  108. struct type *b = *pivot; \
  109. struct type *a = LLRB_LEFT(b, field); \
  110. if ((LLRB_LEFT(b, field) = LLRB_RIGHT(a, field))) \
  111. LLRB_PARENT(LLRB_LEFT(b, field), field) = b; \
  112. LLRB_RIGHT(a, field) = b; \
  113. LLRB_COLOR(a, field) = LLRB_COLOR(b, field); \
  114. LLRB_COLOR(b, field) = LLRB_RED; \
  115. LLRB_PARENT(a, field) = LLRB_PARENT(b, field); \
  116. LLRB_PARENT(b, field) = a; \
  117. *pivot = a; \
  118. } \
  119. static inline void name##_LLRB_FLIP(struct type *root) { \
  120. LLRB_COLOR(root, field) = !LLRB_COLOR(root, field); \
  121. LLRB_COLOR(LLRB_LEFT(root, field), field) = !LLRB_COLOR(LLRB_LEFT(root, field), field); \
  122. LLRB_COLOR(LLRB_RIGHT(root, field), field) = !LLRB_COLOR(LLRB_RIGHT(root, field), field); \
  123. } \
  124. static inline void name##_LLRB_FIXUP(struct type **root) { \
  125. if (LLRB_ISRED(LLRB_RIGHT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(*root, field), field)) \
  126. name##_LLRB_ROTL(root); \
  127. if (LLRB_ISRED(LLRB_LEFT(*root, field), field) && LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*root, field), field), field)) \
  128. name##_LLRB_ROTR(root); \
  129. if (LLRB_ISRED(LLRB_LEFT(*root, field), field) && LLRB_ISRED(LLRB_RIGHT(*root, field), field)) \
  130. name##_LLRB_FLIP(*root); \
  131. } \
  132. attr struct type *name##_LLRB_INSERT(struct name *head, struct type *elm) { \
  133. struct type **root = &LLRB_ROOT(head); \
  134. struct type *parent = 0; \
  135. while (*root) { \
  136. int comp = (cmp)((elm), (*root)); \
  137. parent = *root; \
  138. if (comp < 0) \
  139. root = &LLRB_LEFT(*root, field); \
  140. else if (comp > 0) \
  141. root = &LLRB_RIGHT(*root, field); \
  142. else \
  143. return *root; \
  144. } \
  145. LLRB_LEFT((elm), field) = 0; \
  146. LLRB_RIGHT((elm), field) = 0; \
  147. LLRB_COLOR((elm), field) = LLRB_RED; \
  148. LLRB_PARENT((elm), field) = parent; \
  149. *root = (elm); \
  150. while (parent && (LLRB_ISRED(LLRB_LEFT(parent, field), field) || LLRB_ISRED(LLRB_RIGHT(parent, field), field))) { \
  151. root = LLRB_EDGE(head, parent, field); \
  152. parent = LLRB_PARENT(parent, field); \
  153. name##_LLRB_FIXUP(root); \
  154. } \
  155. LLRB_COLOR(LLRB_ROOT(head), field) = LLRB_BLACK; \
  156. return 0; \
  157. } \
  158. static inline void name##_LLRB_MOVL(struct type **pivot) { \
  159. name##_LLRB_FLIP(*pivot); \
  160. if (LLRB_ISRED(LLRB_LEFT(LLRB_RIGHT(*pivot, field), field), field)) { \
  161. name##_LLRB_ROTR(&LLRB_RIGHT(*pivot, field)); \
  162. name##_LLRB_ROTL(pivot); \
  163. name##_LLRB_FLIP(*pivot); \
  164. } \
  165. } \
  166. static inline void name##_LLRB_MOVR(struct type **pivot) { \
  167. name##_LLRB_FLIP(*pivot); \
  168. if (LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*pivot, field), field), field)) { \
  169. name##_LLRB_ROTR(pivot); \
  170. name##_LLRB_FLIP(*pivot); \
  171. } \
  172. } \
  173. static inline struct type *name##_DELETEMIN(struct name *head, struct type **root) { \
  174. struct type **pivot = root, *deleted, *parent; \
  175. while (LLRB_LEFT(*pivot, field)) { \
  176. if (!LLRB_ISRED(LLRB_LEFT(*pivot, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*pivot, field), field), field)) \
  177. name##_LLRB_MOVL(pivot); \
  178. pivot = &LLRB_LEFT(*pivot, field); \
  179. } \
  180. deleted = *pivot; \
  181. parent = LLRB_PARENT(*pivot, field); \
  182. *pivot = 0; \
  183. while (root != pivot) { \
  184. pivot = LLRB_EDGE(head, parent, field); \
  185. parent = LLRB_PARENT(parent, field); \
  186. name##_LLRB_FIXUP(pivot); \
  187. } \
  188. return deleted; \
  189. } \
  190. attr struct type *name##_LLRB_DELETE(struct name *head, struct type *elm) { \
  191. struct type **root = &LLRB_ROOT(head), *parent = 0, *deleted = 0; \
  192. int comp; \
  193. while (*root) { \
  194. parent = LLRB_PARENT(*root, field); \
  195. comp = (cmp)(elm, *root); \
  196. if (comp < 0) { \
  197. if (LLRB_LEFT(*root, field) && !LLRB_ISRED(LLRB_LEFT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_LEFT(*root, field), field), field)) \
  198. name##_LLRB_MOVL(root); \
  199. root = &LLRB_LEFT(*root, field); \
  200. } else { \
  201. if (LLRB_ISRED(LLRB_LEFT(*root, field), field)) { \
  202. name##_LLRB_ROTR(root); \
  203. comp = (cmp)(elm, *root); \
  204. } \
  205. if (!comp && !LLRB_RIGHT(*root, field)) { \
  206. deleted = *root; \
  207. *root = 0; \
  208. break; \
  209. } \
  210. if (LLRB_RIGHT(*root, field) && !LLRB_ISRED(LLRB_RIGHT(*root, field), field) && !LLRB_ISRED(LLRB_LEFT(LLRB_RIGHT(*root, field), field), field)) { \
  211. name##_LLRB_MOVR(root); \
  212. comp = (cmp)(elm, *root); \
  213. } \
  214. if (!comp) { \
  215. struct type *orphan = name##_DELETEMIN(head, &LLRB_RIGHT(*root, field)); \
  216. LLRB_COLOR(orphan, field) = LLRB_COLOR(*root, field); \
  217. LLRB_PARENT(orphan, field) = LLRB_PARENT(*root, field); \
  218. if ((LLRB_RIGHT(orphan, field) = LLRB_RIGHT(*root, field))) \
  219. LLRB_PARENT(LLRB_RIGHT(orphan, field), field) = orphan; \
  220. if ((LLRB_LEFT(orphan, field) = LLRB_LEFT(*root, field))) \
  221. LLRB_PARENT(LLRB_LEFT(orphan, field), field) = orphan; \
  222. deleted = *root; \
  223. *root = orphan; \
  224. parent = *root; \
  225. break; \
  226. } else \
  227. root = &LLRB_RIGHT(*root, field); \
  228. } \
  229. } \
  230. while (parent) { \
  231. root = LLRB_EDGE(head, parent, field); \
  232. parent = LLRB_PARENT(parent, field); \
  233. name##_LLRB_FIXUP(root); \
  234. } \
  235. if (LLRB_ROOT(head)) \
  236. LLRB_COLOR(LLRB_ROOT(head), field) = LLRB_BLACK; \
  237. return deleted; \
  238. } \
  239. attr struct type *name##_LLRB_FIND(struct name *head, struct type *key) { \
  240. struct type *elm = LLRB_ROOT(head); \
  241. while (elm) { \
  242. int comp = (cmp)(key, elm); \
  243. if (comp < 0) \
  244. elm = LLRB_LEFT(elm, field); \
  245. else if (comp > 0) \
  246. elm = LLRB_RIGHT(elm, field); \
  247. else \
  248. return elm; \
  249. } \
  250. return 0; \
  251. } \
  252. attr struct type *name##_LLRB_MIN(struct type *elm) { \
  253. while (elm && LLRB_LEFT(elm, field)) \
  254. elm = LLRB_LEFT(elm, field); \
  255. return elm; \
  256. } \
  257. attr struct type *name##_LLRB_MAX(struct type *elm) { \
  258. while (elm && LLRB_RIGHT(elm, field)) \
  259. elm = LLRB_RIGHT(elm, field); \
  260. return elm; \
  261. } \
  262. attr struct type *name##_LLRB_NEXT(struct type *elm) { \
  263. if (LLRB_RIGHT(elm, field)) { \
  264. return name##_LLRB_MIN(LLRB_RIGHT(elm, field)); \
  265. } else if (LLRB_PARENT(elm, field)) { \
  266. if (elm == LLRB_LEFT(LLRB_PARENT(elm, field), field)) \
  267. return LLRB_PARENT(elm, field); \
  268. while (LLRB_PARENT(elm, field) && elm == LLRB_RIGHT(LLRB_PARENT(elm, field), field)) \
  269. elm = LLRB_PARENT(elm, field); \
  270. return LLRB_PARENT(elm, field); \
  271. } else return 0; \
  272. }
  273. #define LLRB_INSERT(name, head, elm) name##_LLRB_INSERT((head), (elm))
  274. #define LLRB_DELETE(name, head, elm) name##_LLRB_DELETE((head), (elm))
  275. #define LLRB_REMOVE(name, head, elm) name##_LLRB_DELETE((head), (elm))
  276. #define LLRB_FIND(name, head, elm) name##_LLRB_FIND((head), (elm))
  277. #define LLRB_MIN(name, head) name##_LLRB_MIN(LLRB_ROOT((head)))
  278. #define LLRB_MAX(name, head) name##_LLRB_MAX(LLRB_ROOT((head)))
  279. #define LLRB_NEXT(name, head, elm) name##_LLRB_NEXT((elm))
  280. #define LLRB_FOREACH(elm, name, head) \
  281. for ((elm) = LLRB_MIN(name, head); (elm); (elm) = name##_LLRB_NEXT((elm)))
  282. #endif /* LLRB_H */
  283. #include <stdlib.h>
  284. #include "timeout.h"
  285. #include "bench.h"
  286. struct rbtimeout {
  287. timeout_t expires;
  288. int pending;
  289. LLRB_ENTRY(rbtimeout) rbe;
  290. };
  291. struct rbtimeouts {
  292. timeout_t curtime;
  293. LLRB_HEAD(tree, rbtimeout) tree;
  294. };
  295. static int timeoutcmp(struct rbtimeout *a, struct rbtimeout *b) {
  296. if (a->expires < b->expires) {
  297. return -1;
  298. } else if (a->expires > b->expires) {
  299. return 1;
  300. } else if (a < b) {
  301. return -1;
  302. } else if (a > b) {
  303. return 1;
  304. } else {
  305. return 0;
  306. }
  307. } /* timeoutcmp() */
  308. LLRB_GENERATE_STATIC(tree, rbtimeout, rbe, timeoutcmp)
  309. static void *init(struct timeout *timeout, size_t count, int verbose) {
  310. struct rbtimeouts *T;
  311. size_t i;
  312. T = malloc(sizeof *T);
  313. T->curtime = 0;
  314. LLRB_INIT(&T->tree);
  315. for (i = 0; i < count; i++) {
  316. struct rbtimeout *to = (void *)&timeout[i];
  317. to->expires = 0;
  318. to->pending = 0;
  319. }
  320. return T;
  321. } /* init() */
  322. static void add(void *ctx, struct timeout *_to, timeout_t expires) {
  323. struct rbtimeouts *T = ctx;
  324. struct rbtimeout *to = (void *)_to;
  325. if (to->pending)
  326. LLRB_REMOVE(tree, &T->tree, to);
  327. to->expires = T->curtime + expires;
  328. LLRB_INSERT(tree, &T->tree, to);
  329. to->pending = 1;
  330. } /* add() */
  331. static void del(void *ctx, struct timeout *_to) {
  332. struct rbtimeouts *T = ctx;
  333. struct rbtimeout *to = (void *)_to;
  334. LLRB_REMOVE(tree, &T->tree, to);
  335. to->pending = 0;
  336. to->expires = 0;
  337. } /* del() */
  338. static struct timeout *get(void *ctx) {
  339. struct rbtimeouts *T = ctx;
  340. struct rbtimeout *to;
  341. if ((to = LLRB_MIN(tree, &T->tree)) && to->expires <= T->curtime) {
  342. LLRB_REMOVE(tree, &T->tree, to);
  343. to->pending = 0;
  344. to->expires = 0;
  345. return (void *)to;
  346. }
  347. return NULL;
  348. } /* get() */
  349. static void update(void *ctx, timeout_t ts) {
  350. struct rbtimeouts *T = ctx;
  351. T->curtime = ts;
  352. } /* update() */
  353. static void check(void *ctx) {
  354. return;
  355. } /* check() */
  356. static int empty(void *ctx) {
  357. struct rbtimeouts *T = ctx;
  358. return LLRB_EMPTY(&T->tree);
  359. } /* empty() */
  360. static void destroy(void *ctx) {
  361. free(ctx);
  362. return;
  363. } /* destroy() */
  364. const struct benchops benchops = {
  365. .init = &init,
  366. .add = &add,
  367. .del = &del,
  368. .get = &get,
  369. .update = &update,
  370. .check = &check,
  371. .empty = &empty,
  372. .destroy = &destroy,
  373. };