Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
samr7
GitHub Repository: samr7/vanitygen
Path: blob/master/avl.h
239 views
1
/*
2
* Vanitygen, vanity bitcoin address generator
3
* Copyright (C) 2011 <[email protected]>
4
*
5
* Vanitygen is free software: you can redistribute it and/or modify
6
* it under the terms of the GNU Affero General Public License as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
*
10
* Vanitygen is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Affero General Public License for more details.
14
*
15
* You should have received a copy of the GNU Affero General Public License
16
* along with Vanitygen. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#if !defined (__VG_AVL_H__)
20
#define __VG_AVL_H__
21
22
#include <assert.h>
23
24
/*
25
* AVL tree implementation
26
*/
27
28
typedef enum { CENT = 1, LEFT = 0, RIGHT = 2 } avl_balance_t;
29
30
typedef struct _avl_item_s {
31
struct _avl_item_s *ai_left, *ai_right, *ai_up;
32
avl_balance_t ai_balance;
33
#ifndef NDEBUG
34
int ai_indexed;
35
#endif
36
} avl_item_t;
37
38
typedef struct _avl_root_s {
39
avl_item_t *ar_root;
40
} avl_root_t;
41
42
static INLINE void
43
avl_root_init(avl_root_t *rootp)
44
{
45
rootp->ar_root = NULL;
46
}
47
48
static INLINE int
49
avl_root_empty(avl_root_t *rootp)
50
{
51
return (rootp->ar_root == NULL) ? 1 : 0;
52
}
53
54
static INLINE void
55
avl_item_init(avl_item_t *itemp)
56
{
57
itemp->ai_left = NULL;
58
itemp->ai_right = NULL;
59
itemp->ai_up = NULL;
60
itemp->ai_balance = CENT;
61
#ifndef NDEBUG
62
itemp->ai_indexed = 0;
63
#endif
64
}
65
66
#define container_of(ptr, type, member) \
67
(((type*) (((unsigned char *)ptr) - \
68
(size_t)&(((type *)((unsigned char *)0))->member))))
69
70
#define avl_item_entry(ptr, type, member) \
71
container_of(ptr, type, member)
72
73
74
75
static INLINE void
76
_avl_rotate_ll(avl_root_t *rootp, avl_item_t *itemp)
77
{
78
avl_item_t *tmp;
79
tmp = itemp->ai_left;
80
itemp->ai_left = tmp->ai_right;
81
if (itemp->ai_left)
82
itemp->ai_left->ai_up = itemp;
83
tmp->ai_right = itemp;
84
85
if (itemp->ai_up) {
86
if (itemp->ai_up->ai_left == itemp) {
87
itemp->ai_up->ai_left = tmp;
88
} else {
89
assert(itemp->ai_up->ai_right == itemp);
90
itemp->ai_up->ai_right = tmp;
91
}
92
} else {
93
rootp->ar_root = tmp;
94
}
95
tmp->ai_up = itemp->ai_up;
96
itemp->ai_up = tmp;
97
}
98
99
static INLINE void
100
_avl_rotate_lr(avl_root_t *rootp, avl_item_t *itemp)
101
{
102
avl_item_t *rcp, *rlcp;
103
rcp = itemp->ai_left;
104
rlcp = rcp->ai_right;
105
if (itemp->ai_up) {
106
if (itemp == itemp->ai_up->ai_left) {
107
itemp->ai_up->ai_left = rlcp;
108
} else {
109
assert(itemp == itemp->ai_up->ai_right);
110
itemp->ai_up->ai_right = rlcp;
111
}
112
} else {
113
rootp->ar_root = rlcp;
114
}
115
rlcp->ai_up = itemp->ai_up;
116
rcp->ai_right = rlcp->ai_left;
117
if (rcp->ai_right)
118
rcp->ai_right->ai_up = rcp;
119
itemp->ai_left = rlcp->ai_right;
120
if (itemp->ai_left)
121
itemp->ai_left->ai_up = itemp;
122
rlcp->ai_left = rcp;
123
rlcp->ai_right = itemp;
124
rcp->ai_up = rlcp;
125
itemp->ai_up = rlcp;
126
}
127
128
static INLINE void
129
_avl_rotate_rr(avl_root_t *rootp, avl_item_t *itemp)
130
{
131
avl_item_t *tmp;
132
tmp = itemp->ai_right;
133
itemp->ai_right = tmp->ai_left;
134
if (itemp->ai_right)
135
itemp->ai_right->ai_up = itemp;
136
tmp->ai_left = itemp;
137
138
if (itemp->ai_up) {
139
if (itemp->ai_up->ai_right == itemp) {
140
itemp->ai_up->ai_right = tmp;
141
} else {
142
assert(itemp->ai_up->ai_left == itemp);
143
itemp->ai_up->ai_left = tmp;
144
}
145
} else {
146
rootp->ar_root = tmp;
147
}
148
tmp->ai_up = itemp->ai_up;
149
itemp->ai_up = tmp;
150
}
151
152
static INLINE void
153
_avl_rotate_rl(avl_root_t *rootp, avl_item_t *itemp)
154
{
155
avl_item_t *rcp, *rlcp;
156
rcp = itemp->ai_right;
157
rlcp = rcp->ai_left;
158
if (itemp->ai_up) {
159
if (itemp == itemp->ai_up->ai_right) {
160
itemp->ai_up->ai_right = rlcp;
161
} else {
162
assert(itemp == itemp->ai_up->ai_left);
163
itemp->ai_up->ai_left = rlcp;
164
}
165
} else {
166
rootp->ar_root = rlcp;
167
}
168
rlcp->ai_up = itemp->ai_up;
169
rcp->ai_left = rlcp->ai_right;
170
if (rcp->ai_left)
171
rcp->ai_left->ai_up = rcp;
172
itemp->ai_right = rlcp->ai_left;
173
if (itemp->ai_right)
174
itemp->ai_right->ai_up = itemp;
175
rlcp->ai_right = rcp;
176
rlcp->ai_left = itemp;
177
rcp->ai_up = rlcp;
178
itemp->ai_up = rlcp;
179
}
180
181
static void
182
avl_delete_fix(avl_root_t *rootp, avl_item_t *itemp, avl_item_t *parentp)
183
{
184
avl_item_t *childp;
185
186
if ((parentp->ai_left == NULL) &&
187
(parentp->ai_right == NULL)) {
188
assert(itemp == NULL);
189
parentp->ai_balance = CENT;
190
itemp = parentp;
191
parentp = itemp->ai_up;
192
}
193
194
while (parentp) {
195
if (itemp == parentp->ai_right) {
196
itemp = parentp->ai_left;
197
if (parentp->ai_balance == LEFT) {
198
/* Parent was left-heavy, now worse */
199
if (itemp->ai_balance == LEFT) {
200
/* If left child is also
201
* left-heavy, LL fixes it. */
202
_avl_rotate_ll(rootp, parentp);
203
itemp->ai_balance = CENT;
204
parentp->ai_balance = CENT;
205
parentp = itemp;
206
} else if (itemp->ai_balance == CENT) {
207
_avl_rotate_ll(rootp, parentp);
208
itemp->ai_balance = RIGHT;
209
parentp->ai_balance = LEFT;
210
break;
211
} else {
212
childp = itemp->ai_right;
213
_avl_rotate_lr(rootp, parentp);
214
itemp->ai_balance = CENT;
215
parentp->ai_balance = CENT;
216
if (childp->ai_balance == RIGHT)
217
itemp->ai_balance = LEFT;
218
if (childp->ai_balance == LEFT)
219
parentp->ai_balance = RIGHT;
220
childp->ai_balance = CENT;
221
parentp = childp;
222
}
223
} else if (parentp->ai_balance == CENT) {
224
parentp->ai_balance = LEFT;
225
break;
226
} else {
227
parentp->ai_balance = CENT;
228
}
229
230
} else {
231
itemp = parentp->ai_right;
232
if (parentp->ai_balance == RIGHT) {
233
if (itemp->ai_balance == RIGHT) {
234
_avl_rotate_rr(rootp, parentp);
235
itemp->ai_balance = CENT;
236
parentp->ai_balance = CENT;
237
parentp = itemp;
238
} else if (itemp->ai_balance == CENT) {
239
_avl_rotate_rr(rootp, parentp);
240
itemp->ai_balance = LEFT;
241
parentp->ai_balance = RIGHT;
242
break;
243
} else {
244
childp = itemp->ai_left;
245
_avl_rotate_rl(rootp, parentp);
246
247
itemp->ai_balance = CENT;
248
parentp->ai_balance = CENT;
249
if (childp->ai_balance == RIGHT)
250
parentp->ai_balance = LEFT;
251
if (childp->ai_balance == LEFT)
252
itemp->ai_balance = RIGHT;
253
childp->ai_balance = CENT;
254
parentp = childp;
255
}
256
} else if (parentp->ai_balance == CENT) {
257
parentp->ai_balance = RIGHT;
258
break;
259
} else {
260
parentp->ai_balance = CENT;
261
}
262
}
263
264
itemp = parentp;
265
parentp = itemp->ai_up;
266
}
267
}
268
269
static void
270
avl_insert_fix(avl_root_t *rootp, avl_item_t *itemp)
271
{
272
avl_item_t *childp, *parentp = itemp->ai_up;
273
itemp->ai_left = itemp->ai_right = NULL;
274
#ifndef NDEBUG
275
assert(!itemp->ai_indexed);
276
itemp->ai_indexed = 1;
277
#endif
278
while (parentp) {
279
if (itemp == parentp->ai_left) {
280
if (parentp->ai_balance == LEFT) {
281
/* Parent was left-heavy, now worse */
282
if (itemp->ai_balance == LEFT) {
283
/* If left child is also
284
* left-heavy, LL fixes it. */
285
_avl_rotate_ll(rootp, parentp);
286
itemp->ai_balance = CENT;
287
parentp->ai_balance = CENT;
288
break;
289
} else {
290
assert(itemp->ai_balance != CENT);
291
childp = itemp->ai_right;
292
_avl_rotate_lr(rootp, parentp);
293
itemp->ai_balance = CENT;
294
parentp->ai_balance = CENT;
295
if (childp->ai_balance == RIGHT)
296
itemp->ai_balance = LEFT;
297
if (childp->ai_balance == LEFT)
298
parentp->ai_balance = RIGHT;
299
childp->ai_balance = CENT;
300
break;
301
}
302
} else if (parentp->ai_balance == CENT) {
303
parentp->ai_balance = LEFT;
304
} else {
305
parentp->ai_balance = CENT;
306
return;
307
}
308
} else {
309
if (parentp->ai_balance == RIGHT) {
310
if (itemp->ai_balance == RIGHT) {
311
_avl_rotate_rr(rootp, parentp);
312
itemp->ai_balance = CENT;
313
parentp->ai_balance = CENT;
314
break;
315
} else {
316
assert(itemp->ai_balance != CENT);
317
childp = itemp->ai_left;
318
_avl_rotate_rl(rootp, parentp);
319
itemp->ai_balance = CENT;
320
parentp->ai_balance = CENT;
321
if (childp->ai_balance == RIGHT)
322
parentp->ai_balance = LEFT;
323
if (childp->ai_balance == LEFT)
324
itemp->ai_balance = RIGHT;
325
childp->ai_balance = CENT;
326
break;
327
}
328
} else if (parentp->ai_balance == CENT) {
329
parentp->ai_balance = RIGHT;
330
} else {
331
parentp->ai_balance = CENT;
332
break;
333
}
334
}
335
336
itemp = parentp;
337
parentp = itemp->ai_up;
338
}
339
}
340
341
static INLINE avl_item_t *
342
avl_first(avl_root_t *rootp)
343
{
344
avl_item_t *itemp = rootp->ar_root;
345
if (itemp) {
346
while (itemp->ai_left)
347
itemp = itemp->ai_left;
348
}
349
return itemp;
350
}
351
352
static INLINE avl_item_t *
353
avl_next(avl_item_t *itemp)
354
{
355
if (itemp->ai_right) {
356
itemp = itemp->ai_right;
357
while (itemp->ai_left)
358
itemp = itemp->ai_left;
359
return itemp;
360
}
361
362
while (itemp->ai_up && (itemp == itemp->ai_up->ai_right))
363
itemp = itemp->ai_up;
364
365
if (!itemp->ai_up)
366
return NULL;
367
368
return itemp->ai_up;
369
}
370
371
static void
372
avl_remove(avl_root_t *rootp, avl_item_t *itemp)
373
{
374
avl_item_t *relocp, *replacep, *parentp = NULL;
375
#ifndef NDEBUG
376
assert(itemp->ai_indexed);
377
itemp->ai_indexed = 0;
378
#endif
379
/* If the item is directly replaceable, do it. */
380
if ((itemp->ai_left == NULL) || (itemp->ai_right == NULL)) {
381
parentp = itemp->ai_up;
382
replacep = itemp->ai_left;
383
if (replacep == NULL)
384
replacep = itemp->ai_right;
385
if (replacep != NULL)
386
replacep->ai_up = parentp;
387
if (parentp == NULL) {
388
rootp->ar_root = replacep;
389
} else {
390
if (itemp == parentp->ai_left)
391
parentp->ai_left = replacep;
392
else
393
parentp->ai_right = replacep;
394
395
avl_delete_fix(rootp, replacep, parentp);
396
}
397
return;
398
}
399
400
/*
401
* Otherwise we do an indirect replacement with
402
* the item's leftmost right descendant.
403
*/
404
relocp = avl_next(itemp);
405
assert(relocp);
406
assert(relocp->ai_up != NULL);
407
assert(relocp->ai_left == NULL);
408
replacep = relocp->ai_right;
409
relocp->ai_left = itemp->ai_left;
410
if (relocp->ai_left != NULL)
411
relocp->ai_left->ai_up = relocp;
412
if (itemp->ai_up == NULL)
413
rootp->ar_root = relocp;
414
else {
415
if (itemp == itemp->ai_up->ai_left)
416
itemp->ai_up->ai_left = relocp;
417
else
418
itemp->ai_up->ai_right = relocp;
419
}
420
if (relocp == relocp->ai_up->ai_left) {
421
assert(relocp->ai_up != itemp);
422
relocp->ai_up->ai_left = replacep;
423
parentp = relocp->ai_up;
424
if (replacep != NULL)
425
replacep->ai_up = relocp->ai_up;
426
relocp->ai_right = itemp->ai_right;
427
} else {
428
assert(relocp->ai_up == itemp);
429
relocp->ai_right = replacep;
430
parentp = relocp;
431
}
432
if (relocp->ai_right != NULL)
433
relocp->ai_right->ai_up = relocp;
434
relocp->ai_up = itemp->ai_up;
435
relocp->ai_balance = itemp->ai_balance;
436
avl_delete_fix(rootp, replacep, parentp);
437
}
438
439
#endif /* !defined (__VG_AVL_H__) */
440
441