SAA: optimize seeks when used on a byte array
[platform/upstream/nasm.git] / saa.c
1 #include "compiler.h"
2 #include "nasmlib.h"
3 #include "saa.h"
4
5 /* Aggregate SAA components smaller than this */
6 #define SAA_BLKSHIFT    16
7 #define SAA_BLKLEN      ((size_t)1 << SAA_BLKSHIFT)
8
9 struct SAA *saa_init(size_t elem_len)
10 {
11     struct SAA *s;
12     char *data;
13
14     s = nasm_zalloc(sizeof(struct SAA));
15
16     if (elem_len >= SAA_BLKLEN)
17         s->blk_len = elem_len;
18     else
19         s->blk_len = SAA_BLKLEN - (SAA_BLKLEN % elem_len);
20
21     s->elem_len = elem_len;
22     s->length = s->blk_len;
23     data = nasm_malloc(s->blk_len);
24     s->nblkptrs = s->nblks = 1;
25     s->blk_ptrs = nasm_malloc(sizeof(char *));
26     s->blk_ptrs[0] = data;
27     s->wblk = s->rblk = &s->blk_ptrs[0];
28
29     return s;
30 }
31
32 void saa_free(struct SAA *s)
33 {
34     char **p;
35     size_t n;
36
37     for (p = s->blk_ptrs, n = s->nblks; n; p++, n--)
38         nasm_free(*p);
39
40     nasm_free(s->blk_ptrs);
41     nasm_free(s);
42 }
43
44 /* Add one allocation block to an SAA */
45 static void saa_extend(struct SAA *s)
46 {
47     size_t blkn = s->nblks++;
48
49     if (blkn >= s->nblkptrs) {
50         size_t rindex = s->rblk - s->blk_ptrs;
51         size_t windex = s->wblk - s->blk_ptrs;
52
53         s->nblkptrs <<= 1;
54         s->blk_ptrs = nasm_realloc(s->blk_ptrs, s->nblkptrs*sizeof(char *));
55
56         s->rblk = s->blk_ptrs + rindex;
57         s->wblk = s->blk_ptrs + windex;
58     }
59
60     s->blk_ptrs[blkn] = nasm_malloc(s->blk_len);
61     s->length += s->blk_len;
62 }
63
64 void *saa_wstruct(struct SAA *s)
65 {
66     void *p;
67
68     if (s->wpos % s->elem_len)
69             nasm_malloc_error(ERR_PANIC|ERR_NOFILE,
70                               "misaligned wpos in saa_wstruct");
71
72     if (s->wpos + s->elem_len > s->blk_len) {
73         if (s->wpos != s->blk_len)
74             nasm_malloc_error(ERR_PANIC|ERR_NOFILE,
75                               "unfilled block in saa_wstruct");
76
77         if (s->wptr + s->elem_len > s->length)
78             saa_extend(s);
79         s->wblk++;
80         s->wpos = 0;
81     }
82
83     p = *s->wblk + s->wpos;
84     s->wpos += s->elem_len;
85     s->wptr += s->elem_len;
86
87     if (s->wptr > s->datalen)
88         s->datalen = s->wptr;
89
90     return p;
91 }
92
93 void saa_wbytes(struct SAA *s, const void *data, size_t len)
94 {
95     const char *d = data;
96
97     while (len) {
98         size_t l = s->blk_len - s->wpos;
99         if (l > len)
100             l = len;
101         if (l) {
102             if (d) {
103                 memcpy(*s->wblk + s->wpos, d, l);
104                 d += l;
105             } else
106                 memset(*s->wblk + s->wpos, 0, l);
107             s->wpos += l;
108             s->wptr += l;
109             len -= l;
110
111             if (s->datalen < s->wptr)
112                 s->datalen = s->wptr;
113         }
114         if (len) {
115             if (s->wptr >= s->length)
116                 saa_extend(s);
117             s->wblk++;
118             s->wpos = 0;
119         }
120     }
121 }
122
123 void saa_rewind(struct SAA *s)
124 {
125     s->rblk = s->blk_ptrs;
126     s->rpos = s->rptr = 0;
127 }
128
129 void *saa_rstruct(struct SAA *s)
130 {
131     void *p;
132
133     if (s->rptr + s->elem_len > s->datalen)
134         return NULL;
135
136     if (s->rpos % s->elem_len)
137             nasm_malloc_error(ERR_PANIC|ERR_NOFILE,
138                               "misaligned rpos in saa_rstruct");
139
140     if (s->rpos + s->elem_len > s->blk_len) {
141         s->rblk++;
142         s->rpos = 0;
143     }
144
145     p = *s->rblk + s->rpos;
146     s->rpos += s->elem_len;
147     s->rptr += s->elem_len;
148
149     return p;
150 }
151
152 const void *saa_rbytes(struct SAA *s, size_t *lenp)
153 {
154     const void *p;
155     size_t len;
156
157     if (s->rptr >= s->datalen) {
158         *lenp = 0;
159         return NULL;
160     }
161
162     if (s->rpos >= s->blk_len) {
163         s->rblk++;
164         s->rpos = 0;
165     }
166
167     len = *lenp;
168     if (len > s->datalen - s->rptr)
169         len = s->datalen - s->rptr;
170     if (len > s->blk_len - s->rpos)
171         len = s->blk_len - s->rpos;
172
173     *lenp = len;
174     p = *s->rblk + s->rpos;
175
176     s->rpos += len;
177     s->rptr += len;
178
179     return p;
180 }
181
182 void saa_rnbytes(struct SAA *s, void *data, size_t len)
183 {
184     char *d = data;
185
186     if (s->rptr + len > s->datalen) {
187         nasm_malloc_error(ERR_PANIC|ERR_NOFILE, "overrun in saa_rnbytes");
188         return;
189     }
190
191     while (len) {
192         size_t l;
193         const void *p;
194
195         l = len;
196         p = saa_rbytes(s, &l);
197
198         memcpy(d, p, l);
199         d   += l;
200         len -= l;
201     }
202 }
203
204 /* Same as saa_rnbytes, except position the counter first */
205 void saa_fread(struct SAA *s, size_t posn, void *data, size_t len)
206 {
207     size_t ix;
208
209     if (posn+len > s->datalen) {
210         nasm_malloc_error(ERR_PANIC|ERR_NOFILE, "overrun in saa_fread");
211         return;
212     }
213
214     if (s->elem_len == 1) {
215         ix = posn >> SAA_BLKSHIFT;
216         s->rpos = posn & (SAA_BLKLEN-1);
217     } else {
218         ix = posn / s->blk_len;
219         s->rpos = posn % s->blk_len;
220     }
221     s->rptr = posn;
222     s->rblk = &s->blk_ptrs[ix];
223
224     saa_rnbytes(s, data, len);
225 }
226
227 /* Same as saa_wbytes, except position the counter first */
228 void saa_fwrite(struct SAA *s, size_t posn, const void *data, size_t len)
229 {
230     size_t ix;
231
232     if (posn > s->datalen) {
233         /* Seek beyond the end of the existing array not supported */
234         nasm_malloc_error(ERR_PANIC|ERR_NOFILE, "overrun in saa_fwrite");
235         return;
236     }
237
238     
239     if (s->elem_len == 1) {
240         ix = posn >> SAA_BLKSHIFT;
241         s->wpos = posn & (SAA_BLKLEN-1);
242     } else {
243         ix = posn / s->blk_len;
244         s->wpos = posn % s->blk_len;
245     }
246     s->wptr = posn;
247     s->wblk = &s->blk_ptrs[ix];
248
249     if (!s->wpos) {
250         s->wpos = s->blk_len;
251         s->wblk--;
252     }
253
254     saa_wbytes(s, data, len);
255 }
256
257 void saa_fpwrite(struct SAA *s, FILE * fp)
258 {
259     const char *data;
260     size_t len;
261
262     saa_rewind(s);
263     while (len = s->datalen, (data = saa_rbytes(s, &len)) != NULL)
264         fwrite(data, 1, len, fp);
265 }
266
267 void saa_write8(struct SAA *s, uint8_t v)
268 {
269     saa_wbytes(s, &v, 1);
270 }
271
272 #ifdef WORDS_LITTEENDIAN
273
274 void saa_write16(struct SAA *s, uint16_t v)
275 {
276     saa_wbytes(s, &v, 2);
277 }
278
279 void saa_write32(struct SAA *s, uint32_t v)
280 {
281     saa_wbytes(s, &v, 4);
282 }
283
284 void saa_write64(struct SAA *s, uint64_t v)
285 {
286     saa_wbytes(s, &v, 8);
287 }
288
289 #else /* not WORDS_LITTLEENDIAN */
290
291 void saa_write16(struct SAA *s, uint16_t v)
292 {
293     uint8_t b[2];
294
295     b[0] = v;
296     b[1] = v >> 8;
297     saa_wbytes(s, b, 2);
298 }
299
300 void saa_write32(struct SAA *s, uint32_t v)
301 {
302     uint8_t b[4];
303
304     b[0] = v;
305     b[1] = v >> 8;
306     b[2] = v >> 16;
307     b[3] = v >> 24;
308     saa_wbytes(s, b, 4);
309 }
310
311 void saa_write64(struct SAA *s, uint64_t v)
312 {
313     uint8_t b[8];
314
315     b[0] = v;
316     b[1] = v >> 8;
317     b[2] = v >> 16;
318     b[3] = v >> 24;
319     b[4] = v >> 32;
320     b[5] = v >> 40;
321     b[6] = v >> 48;
322     b[7] = v >> 56;
323     saa_wbytes(s, b, 8);
324 }
325
326 #endif  /* WORDS_LITTLEENDIAN */
327
328 /* write unsigned LEB128 value to SAA */
329 void saa_wleb128u(struct SAA *psaa, int value)
330 {
331   char temp[64], *ptemp;
332   uint8_t byte;
333   int len;
334
335   ptemp = temp;
336   len = 0;
337   do
338   {
339      byte = value & 127;
340      value >>= 7;
341      if (value != 0) /* more bytes to come */
342         byte |= 0x80;
343      *ptemp = byte;
344      ptemp++;
345      len++;
346   } while (value != 0);
347   saa_wbytes(psaa, temp, len);
348 }
349
350 /* write signed LEB128 value to SAA */
351 void saa_wleb128s(struct SAA *psaa, int value)
352 {
353   char temp[64], *ptemp;
354   uint8_t byte;
355   bool more, negative;
356   int size, len;
357
358   ptemp = temp;
359   more = 1;
360   negative = (value < 0);
361   size = sizeof(int) * 8;
362   len = 0;
363   while(more)
364   {
365     byte = value & 0x7f;
366     value >>= 7;
367     if (negative)
368      /* sign extend */
369      value |= - (1 <<(size - 7));
370     /* sign bit of byte is second high order bit (0x40) */
371     if ((value == 0 && ! (byte & 0x40)) ||
372        ((value == -1) && (byte & 0x40)))
373        more = 0;
374     else
375       byte |= 0x80;
376     *ptemp = byte;
377     ptemp++;
378     len++;
379   }
380   saa_wbytes(psaa, temp, len);
381 }