add tlist, aka treap list
[rofl0r-libulz.git] / src / tlist / tlist.c
blob1ac4c097bc34855a583b7c9b19f01284cbe9379d
1 #include <stdlib.h>
2 #include <string.h>
3 #include "../../include/tlist.h"
5 #ifndef UINT_MAX
6 #define UINT_MAX 0xffffffffU
7 #endif
9 static int mrand(unsigned *seed)
11 return (*seed = (*seed+1) * 1103515245 + 12345 - 1)+1 & 0x7fffffff;
14 typedef struct item* pitem;
15 struct item {
16 unsigned prior, cnt;
17 pitem l, r;
20 static unsigned cnt (pitem it) {
21 return it ? it->cnt : 0;
24 static void upd_cnt (pitem it) {
25 if (it)
26 it->cnt = cnt(it->l) + cnt(it->r) + 1;
29 static void merge (pitem *t, pitem l, pitem r) {
30 if (!l || !r)
31 *t = l ? l : r;
32 else if (l->prior > r->prior)
33 merge (&l->r, l->r, r), *t = l;
34 else
35 merge (&r->l, l, r->l), *t = r;
36 upd_cnt (*t);
39 static void split (pitem t, pitem *l, pitem *r, unsigned key, unsigned add) {
40 if (!t) {
41 *l = *r = 0;
42 return;
44 unsigned cur_key = add + cnt(t->l);
45 if (key <= cur_key)
46 split (t->l, l, &t->l, key, add), *r = t;
47 else
48 split (t->r, &t->r, r, key, add + 1 + cnt(t->l)), *l = t;
49 upd_cnt (t);
52 static pitem getitem(pitem t, unsigned idx, unsigned add) {
53 if (!t) return t;
54 unsigned ls = cnt (t->l), cur_key = add + ls;
55 if (cur_key == idx) return t;
56 if (cur_key < idx)
57 return getitem (t->r, idx, add + 1 + ls);
58 else
59 return getitem (t->l, idx, add);
62 static void insert(pitem *t, pitem n, unsigned idx) {
63 pitem t1, t2;
64 split (*t, &t1, &t2, idx, 0);
65 merge (t, t1, n);
66 merge (t, *t, t2);
69 static void remove(pitem *t, unsigned idx, unsigned add) {
70 pitem n;
71 if (!(*t)) return;
72 unsigned cur_key = add + cnt ((*t)->l), new_add = cur_key + 1;
73 unsigned rk, lk = rk = UINT_MAX;
74 if ((*t)->l) lk = cnt ((*t)->l->l) + add;
75 if ((*t)->r) rk = cnt ((*t)->r->l) + new_add;
76 if (cur_key == idx) {
77 merge (t, (*t)->l, (*t)->r);
78 } else if (lk == idx) {
79 merge (&n, (*t)->l->l, (*t)->l->r);
80 (*t)->l = n;
81 upd_cnt (*t);
82 } else if (rk == idx) {
83 merge (&n, (*t)->r->l, (*t)->r->r);
84 (*t)->r = n;
85 upd_cnt (*t);
86 } else if (cur_key < idx) {
87 remove (&(*t)->r, idx, new_add);
88 upd_cnt (*t);
89 } else {
90 remove (&(*t)->l, idx, add);
91 upd_cnt (*t);
95 static pitem new_item(void* value, unsigned valsz, unsigned *seed) {
96 pitem n = malloc(sizeof(struct item) + valsz);
97 if(!n) return n;
98 memcpy(n+1, value, valsz);
99 n->prior = mrand(seed);
100 n->cnt = 1;
101 n->l = n->r = 0;
102 return n;
105 struct tlist {
106 unsigned seed;
107 unsigned itemsize;
108 pitem root;
111 struct tlist *tlist_new(unsigned itemsize) {
112 struct tlist* new = malloc(sizeof (struct tlist));
113 if(!new) return 0;
114 new->seed = 385-1;
115 new->itemsize = itemsize;
116 new->root = 0;
117 return new;
120 static void* data(pitem it) {
121 return it+1;
124 size_t tlist_getsize(struct tlist* t) {
125 return cnt(t->root);
128 void* tlist_get(struct tlist* t, size_t idx) {
129 return data(getitem(t->root, idx, 0));
132 int tlist_insert(struct tlist* t, size_t idx, void *value) {
133 if(idx > cnt (t->root)) return 0;
134 pitem new = new_item(value, t->itemsize, &t->seed);
135 if(!new) return 0;
136 insert(&t->root, new, idx);
137 return 1;
140 int tlist_append(struct tlist* t, void *value) {
141 return tlist_insert(t, cnt(t->root), value);
144 static int tlist_delete_impl(struct tlist *t, size_t idx, int deep) {
145 if(idx >= cnt (t->root)) return 0;
146 pitem it = getitem(t->root, idx, 0);
147 if(deep) free(data(it));
148 remove(&t->root, idx, 0);
149 free(it);
150 return 1;
153 int tlist_delete(struct tlist *t, size_t idx) {
154 return tlist_delete_impl(t, idx, 0);
157 int tlist_delete_deep(struct tlist *t, size_t idx) {
158 return tlist_delete_impl(t, idx, 1);
161 static void tlist_free_items_impl(struct tlist *t, int deep) {
162 while(cnt(t->root)) tlist_delete_impl(t, 0, deep);
165 void tlist_free_items(struct tlist *t) {
166 tlist_free_items_impl(t, 0);
169 void tlist_free_items_deep(struct tlist *t) {
170 tlist_free_items_impl(t, 1);
173 static void* tlist_free_impl(struct tlist *t, int deep) {
174 tlist_free_items_impl(t, deep);
175 free(t);
176 return 0;
179 void *tlist_free(struct tlist *t) {
180 return tlist_free_impl(t, 0);
183 void *tlist_free_deep(struct tlist *t) {
184 return tlist_free_impl(t, 1);
187 #ifdef TLIST_TEST
188 extern int printf(const char *__restrict, ...);
189 float tlist_getbalance(struct tlist *t) {
190 size_t n = tlist_getsize(t);
191 int r, l;
192 if (n == 0) return 1.0;
193 l = cnt (t->root->l);
194 r = cnt (t->root->r);
195 printf("l %d, r %d, diff %d\n", l, r, abs(l-r));
196 return 100.f - ((float)abs(l - r)/(n/100.f));
198 #endif