comparison src/ploki/list.c @ 4223:ac0403686959

<oerjan> rm -rf src/ploki; mv ploki src
author HackBot
date Fri, 20 Dec 2013 22:18:50 +0000
parents
children
comparison
equal deleted inserted replaced
4222:b0f3e267bb1e 4223:ac0403686959
1 #include "list.h"
2 #include "val.h"
3 #include "xmalloc.h"
4
5 #include <string.h>
6 #include <assert.h>
7
8 typedef struct li_whale whale;
9
10 static whale *incr(whale *wp) {
11 assert(wp->refs > 0);
12 ++wp->refs;
13 return wp;
14 }
15
16 static void decr(whale *wp) {
17 assert(wp->refs > 0);
18 if (!--wp->refs) {
19 while (wp->length) {
20 --wp->length;
21 v_delete(wp->field[wp->length]);
22 }
23 xfree(wp->field);
24 xfree(wp);
25 }
26 }
27
28 enum {MAGIC = 7};
29
30 struct list *li_new(void) {
31 struct list *l = xmalloc(1, sizeof *l);
32 l->lwp = xmalloc(1, sizeof *l->lwp);
33 l->lwp->field = xmalloc(l->lwp->size = MAGIC, sizeof *l->lwp->field);
34 l->lwp->length = 0;
35 l->lwp->refs = 1;
36 l->offset = 0;
37 l->length = 0;
38 return l;
39 }
40
41 struct list *li_dup(const struct list *k) {
42 struct list *l = xmalloc(1, sizeof *l);
43 l->lwp = incr(k->lwp);
44 l->offset = k->offset;
45 l->length = k->length;
46 return l;
47 }
48
49 static void decouple(struct list *l, size_t slack) {
50 size_t i, n;
51 whale *const wp = l->lwp;
52 struct val **const field = wp->field + l->offset, **nfield;
53 assert(wp->refs > 0);
54 if (wp->refs == 1) {
55 return;
56 }
57 l->lwp = xmalloc(1, sizeof *l->lwp);
58 n = l->length;
59 l->lwp->field = nfield = xmalloc(l->lwp->size = n + slack > MAGIC ? n + slack : MAGIC, sizeof *l->lwp->field);
60 for (i = 0; i < n; ++i) {
61 v_set(nfield[i] = v_undef(), field[i]);
62 }
63 l->lwp->length = n;
64 l->lwp->refs = 1;
65 l->offset = 0;
66 decr(wp);
67 }
68
69 void li_decouple(struct list *l) {
70 decouple(l, 1);
71 }
72
73 void li_delete(struct list *l) {
74 decr(l->lwp);
75 xfree(l);
76 }
77
78 size_t (li_length)(const struct list *l) {
79 return li_length(l);
80 }
81
82 struct val *li_at(const struct list *l, size_t i) {
83 return i < l->length ? l->lwp->field[l->offset + i] : NULL;
84 }
85
86 int li_cmp(const struct list *k, const struct list *l) {
87 const size_t len_k = li_length(k), len_l = li_length(l);
88 struct val **const field_k = k->lwp->field + k->offset, **const field_l = l->lwp->field + l->offset;
89 size_t i;
90
91 for (i = 0; i < len_k && i < len_l; ++i) {
92 const int tmp = v_cmp_ls(field_k[i], field_l[i]);
93 if (tmp) {
94 return tmp;
95 }
96 }
97 if (i < len_k) {
98 return 1;
99 }
100 if (i < len_l) {
101 return -1;
102 }
103 return 0;
104 }
105
106 void (li_zero)(struct list *l) {
107 li_zero(l);
108 }
109
110 static void vpswap(struct val **p, struct val **q) {
111 struct val *tmp = *p;
112 *p = *q;
113 *q = tmp;
114 }
115
116 void li_push(struct list *l, struct val *v) {
117 struct li_whale *wp = l->lwp;
118 const size_t off = l->offset, len = l->length, wlen = wp->length, wsiz = wp->size;
119 struct val **field = wp->field;
120 assert(wp->refs > 0);
121 if (wp->refs > 1) {
122 decouple(l, 1);
123 wp = l->lwp;
124 field = wp->field;
125 } else if (off + len < wlen) {
126 v_delete(field[off + len]);
127 } else if (wlen < wsiz) {
128 /* */
129 } else if (off) {
130 size_t i;
131 for (i = 0; i < len; ++i) {
132 vpswap(&field[i], &field[off + i]);
133 }
134 l->offset = 0;
135 v_delete(field[len]);
136 } else {
137 wp->field = field = xrealloc(field, wp->size *= 2);
138 }
139 field[l->offset + l->length++] = v;
140 if (l->offset + l->length > wlen) {
141 wp->length = l->offset + l->length;
142 }
143 }
144
145 void li_push_cpy(struct list *l, const struct val *v) {
146 struct li_whale *wp = l->lwp;
147 const size_t off = l->offset, len = l->length, wlen = wp->length, wsiz = wp->size;
148 struct val **field = wp->field;
149 assert(wp->refs > 0);
150 if (wp->refs > 1) {
151 decouple(l, 1);
152 wp = l->lwp;
153 field = wp->field;
154 field[l->offset + len] = v_undef();
155 } else if (off + len < wlen) {
156 /* */
157 } else if (wlen < wsiz) {
158 field[off + len] = v_undef();
159 } else if (off) {
160 size_t i;
161 for (i = 0; i < len; ++i) {
162 vpswap(&field[i], &field[off + i]);
163 }
164 l->offset = 0;
165 } else {
166 wp->field = field = xrealloc(field, wp->size *= 2);
167 field[len] = v_undef();
168 }
169 v_set(field[l->offset + l->length++], v);
170 if (l->offset + l->length > wlen) {
171 wp->length = l->offset + l->length;
172 }
173 }
174
175 void li_append(struct list *k, const struct list *l) {
176 struct val **const field = l->lwp->field + l->offset;
177 const size_t len = li_length(l);
178 size_t i;
179
180 for (i = 0; i < len; ++i) {
181 li_push_cpy(k, field[i]);
182 }
183 }
184
185 void li_reverse(struct list *l) {
186 struct val **field;
187 size_t i, len;
188
189 len = li_length(l);
190 if (len < 2) {
191 return;
192 }
193
194 li_decouple(l);
195
196 field = l->lwp->field + l->offset;
197
198 for (i = 0; i < len / 2; ++i) {
199 vpswap(&field[i], &field[len - i - 1]);
200 }
201 }
202
203 void li_trunc(struct list *l, size_t n) {
204 if (l->length > n) {
205 if (!(l->length = n)) {
206 l->offset = 0;
207 }
208 }
209 }
210
211 void li_shift(struct list *l, size_t n) {
212 if (n >= li_length(l)) {
213 li_zero(l);
214 return;
215 }
216
217 l->offset += n;
218 l->length -= n;
219 }