Merge branch 'jh/dirstat' into maint
[git] / vcs-svn / trp.h
1 /*
2  * C macro implementation of treaps.
3  *
4  * Usage:
5  *   #include <stdint.h>
6  *   #include "trp.h"
7  *   trp_gen(...)
8  *
9  * Licensed under a two-clause BSD-style license.
10  * See LICENSE for details.
11  */
12
13 #ifndef TRP_H_
14 #define TRP_H_
15
16 #define MAYBE_UNUSED __attribute__((__unused__))
17
18 /* Node structure. */
19 struct trp_node {
20         uint32_t trpn_left;
21         uint32_t trpn_right;
22 };
23
24 /* Root structure. */
25 struct trp_root {
26         uint32_t trp_root;
27 };
28
29 /* Pointer/Offset conversion. */
30 #define trpn_pointer(a_base, a_offset) (a_base##_pointer(a_offset))
31 #define trpn_offset(a_base, a_pointer) (a_base##_offset(a_pointer))
32 #define trpn_modify(a_base, a_offset) \
33         do { \
34                 if ((a_offset) < a_base##_pool.committed) { \
35                         uint32_t old_offset = (a_offset);\
36                         (a_offset) = a_base##_alloc(1); \
37                         *trpn_pointer(a_base, a_offset) = \
38                                 *trpn_pointer(a_base, old_offset); \
39                 } \
40         } while (0)
41
42 /* Left accessors. */
43 #define trp_left_get(a_base, a_field, a_node) \
44         (trpn_pointer(a_base, a_node)->a_field.trpn_left)
45 #define trp_left_set(a_base, a_field, a_node, a_left) \
46         do { \
47                 trpn_modify(a_base, a_node); \
48                 trp_left_get(a_base, a_field, a_node) = (a_left); \
49         } while (0)
50
51 /* Right accessors. */
52 #define trp_right_get(a_base, a_field, a_node) \
53         (trpn_pointer(a_base, a_node)->a_field.trpn_right)
54 #define trp_right_set(a_base, a_field, a_node, a_right) \
55         do { \
56                 trpn_modify(a_base, a_node); \
57                 trp_right_get(a_base, a_field, a_node) = (a_right); \
58         } while (0)
59
60 /*
61  * Fibonacci hash function.
62  * The multiplier is the nearest prime to (2^32 times (√5 - 1)/2).
63  * See Knuth §6.4: volume 3, 3rd ed, p518.
64  */
65 #define trpn_hash(a_node) (uint32_t) (2654435761u * (a_node))
66
67 /* Priority accessors. */
68 #define trp_prio_get(a_node) trpn_hash(a_node)
69
70 /* Node initializer. */
71 #define trp_node_new(a_base, a_field, a_node) \
72         do { \
73                 trp_left_set(a_base, a_field, (a_node), ~0); \
74                 trp_right_set(a_base, a_field, (a_node), ~0); \
75         } while (0)
76
77 /* Internal utility macros. */
78 #define trpn_first(a_base, a_field, a_root, r_node) \
79         do { \
80                 (r_node) = (a_root); \
81                 if ((r_node) == ~0) \
82                         return NULL; \
83                 while (~trp_left_get(a_base, a_field, (r_node))) \
84                         (r_node) = trp_left_get(a_base, a_field, (r_node)); \
85         } while (0)
86
87 #define trpn_rotate_left(a_base, a_field, a_node, r_node) \
88         do { \
89                 (r_node) = trp_right_get(a_base, a_field, (a_node)); \
90                 trp_right_set(a_base, a_field, (a_node), \
91                         trp_left_get(a_base, a_field, (r_node))); \
92                 trp_left_set(a_base, a_field, (r_node), (a_node)); \
93         } while (0)
94
95 #define trpn_rotate_right(a_base, a_field, a_node, r_node) \
96         do { \
97                 (r_node) = trp_left_get(a_base, a_field, (a_node)); \
98                 trp_left_set(a_base, a_field, (a_node), \
99                         trp_right_get(a_base, a_field, (r_node))); \
100                 trp_right_set(a_base, a_field, (r_node), (a_node)); \
101         } while (0)
102
103 #define trp_gen(a_attr, a_pre, a_type, a_field, a_base, a_cmp) \
104 a_attr a_type MAYBE_UNUSED *a_pre##first(struct trp_root *treap) \
105 { \
106         uint32_t ret; \
107         trpn_first(a_base, a_field, treap->trp_root, ret); \
108         return trpn_pointer(a_base, ret); \
109 } \
110 a_attr a_type MAYBE_UNUSED *a_pre##next(struct trp_root *treap, a_type *node) \
111 { \
112         uint32_t ret; \
113         uint32_t offset = trpn_offset(a_base, node); \
114         if (~trp_right_get(a_base, a_field, offset)) { \
115                 trpn_first(a_base, a_field, \
116                         trp_right_get(a_base, a_field, offset), ret); \
117         } else { \
118                 uint32_t tnode = treap->trp_root; \
119                 ret = ~0; \
120                 while (1) { \
121                         int cmp = (a_cmp)(trpn_pointer(a_base, offset), \
122                                 trpn_pointer(a_base, tnode)); \
123                         if (cmp < 0) { \
124                                 ret = tnode; \
125                                 tnode = trp_left_get(a_base, a_field, tnode); \
126                         } else if (cmp > 0) { \
127                                 tnode = trp_right_get(a_base, a_field, tnode); \
128                         } else { \
129                                 break; \
130                         } \
131                 } \
132         } \
133         return trpn_pointer(a_base, ret); \
134 } \
135 a_attr a_type MAYBE_UNUSED *a_pre##search(struct trp_root *treap, a_type *key) \
136 { \
137         int cmp; \
138         uint32_t ret = treap->trp_root; \
139         while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \
140                 if (cmp < 0) { \
141                         ret = trp_left_get(a_base, a_field, ret); \
142                 } else { \
143                         ret = trp_right_get(a_base, a_field, ret); \
144                 } \
145         } \
146         return trpn_pointer(a_base, ret); \
147 } \
148 a_attr a_type MAYBE_UNUSED *a_pre##nsearch(struct trp_root *treap, a_type *key) \
149 { \
150         int cmp; \
151         uint32_t ret = treap->trp_root; \
152         while (~ret && (cmp = (a_cmp)(key, trpn_pointer(a_base, ret)))) { \
153                 if (cmp < 0) { \
154                         if (!~trp_left_get(a_base, a_field, ret)) \
155                                 break; \
156                         ret = trp_left_get(a_base, a_field, ret); \
157                 } else { \
158                         ret = trp_right_get(a_base, a_field, ret); \
159                 } \
160         } \
161         return trpn_pointer(a_base, ret); \
162 } \
163 a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t ins_node) \
164 { \
165         if (cur_node == ~0) { \
166                 return ins_node; \
167         } else { \
168                 uint32_t ret; \
169                 int cmp = (a_cmp)(trpn_pointer(a_base, ins_node), \
170                                         trpn_pointer(a_base, cur_node)); \
171                 if (cmp < 0) { \
172                         uint32_t left = a_pre##insert_recurse( \
173                                 trp_left_get(a_base, a_field, cur_node), ins_node); \
174                         trp_left_set(a_base, a_field, cur_node, left); \
175                         if (trp_prio_get(left) < trp_prio_get(cur_node)) \
176                                 trpn_rotate_right(a_base, a_field, cur_node, ret); \
177                         else \
178                                 ret = cur_node; \
179                 } else { \
180                         uint32_t right = a_pre##insert_recurse( \
181                                 trp_right_get(a_base, a_field, cur_node), ins_node); \
182                         trp_right_set(a_base, a_field, cur_node, right); \
183                         if (trp_prio_get(right) < trp_prio_get(cur_node)) \
184                                 trpn_rotate_left(a_base, a_field, cur_node, ret); \
185                         else \
186                                 ret = cur_node; \
187                 } \
188                 return ret; \
189         } \
190 } \
191 a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
192 { \
193         uint32_t offset = trpn_offset(a_base, node); \
194         trp_node_new(a_base, a_field, offset); \
195         treap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \
196         return trpn_pointer(a_base, offset); \
197 } \
198 a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \
199 { \
200         int cmp = a_cmp(trpn_pointer(a_base, rem_node), \
201                         trpn_pointer(a_base, cur_node)); \
202         if (cmp == 0) { \
203                 uint32_t ret; \
204                 uint32_t left = trp_left_get(a_base, a_field, cur_node); \
205                 uint32_t right = trp_right_get(a_base, a_field, cur_node); \
206                 if (left == ~0) { \
207                         if (right == ~0) \
208                                 return ~0; \
209                 } else if (right == ~0 || trp_prio_get(left) < trp_prio_get(right)) { \
210                         trpn_rotate_right(a_base, a_field, cur_node, ret); \
211                         right = a_pre##remove_recurse(cur_node, rem_node); \
212                         trp_right_set(a_base, a_field, ret, right); \
213                         return ret; \
214                 } \
215                 trpn_rotate_left(a_base, a_field, cur_node, ret); \
216                 left = a_pre##remove_recurse(cur_node, rem_node); \
217                 trp_left_set(a_base, a_field, ret, left); \
218                 return ret; \
219         } else if (cmp < 0) { \
220                 uint32_t left = a_pre##remove_recurse( \
221                         trp_left_get(a_base, a_field, cur_node), rem_node); \
222                 trp_left_set(a_base, a_field, cur_node, left); \
223                 return cur_node; \
224         } else { \
225                 uint32_t right = a_pre##remove_recurse( \
226                         trp_right_get(a_base, a_field, cur_node), rem_node); \
227                 trp_right_set(a_base, a_field, cur_node, right); \
228                 return cur_node; \
229         } \
230 } \
231 a_attr void MAYBE_UNUSED a_pre##remove(struct trp_root *treap, a_type *node) \
232 { \
233         treap->trp_root = a_pre##remove_recurse(treap->trp_root, \
234                 trpn_offset(a_base, node)); \
235 } \
236
237 #endif