dict now reallocates itself
[swftools.git] / lib / q.c
1 /* q.c
2
3    Part of the swftools package.
4    
5    Copyright (c) 2001,2002,2003,2004 Matthias Kramm <kramm@quiss.org>
6  
7    This program is rfx_free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the rfx_free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the rfx_free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <memory.h>
27 #include "mem.h"
28 #include "q.h"
29
30 // ------------------------------- malloc, alloc routines ---------------------
31
32 #ifndef STRNDUP
33 char* strdup_n(const char*str, int size)
34 {
35     char*m = (char*)rfx_alloc(size+1);
36     memcpy(m, str, size);
37     m[size] = 0;
38     return m;
39 }
40 #endif
41 char*qstrdup(const char*string)
42 {
43     return strdup(string);
44 }
45 char*qstrndup(const char*string, int len)
46 {
47     return strdup_n(string, len);
48 }
49
50 // ------------------------------- mem_t --------------------------------------
51
52 void mem_init(mem_t*mem)
53 {
54     memset(mem, 0, sizeof(mem_t));
55 }
56 void mem_clear(mem_t*mem)
57 {
58     rfx_free(mem->buffer);mem->buffer = 0;
59 }
60 void mem_destroy(mem_t*mem)
61 {
62     mem_clear(mem);
63     rfx_free(mem);
64 }
65 static int mem_put_(mem_t*m,const void*data, int length, int null)
66 {
67     int n = m->pos;
68     m->pos += length + (null?1:0);
69     if(m->pos > m->len) { 
70         m->len = (m->pos+63)&~63;
71         m->buffer = m->buffer?(char*)rfx_realloc(m->buffer,m->len):(char*)rfx_alloc(m->len);
72     }
73     assert(n+length <= m->len);
74     memcpy(&m->buffer[n], data, length);
75     if(null)
76         m->buffer[n + length] = 0;
77     return n;
78 }
79 int mem_put(mem_t*m,void*data, int length)
80 {
81     return mem_put_(m, data, length, 0);
82 }
83 int mem_putstring(mem_t*m,string_t str)
84 {
85     return mem_put_(m, str.str, str.len, 1);
86 }
87
88 // ------------------------------- ringbuffer_t -------------------------------
89
90 typedef struct _ringbuffer_internal_t
91 {
92     unsigned char*buffer;
93     int readpos;
94     int writepos;
95     int buffersize;
96 } ringbuffer_internal_t;
97
98 void ringbuffer_init(ringbuffer_t*r)
99 {
100     ringbuffer_internal_t*i = (ringbuffer_internal_t*)rfx_calloc(sizeof(ringbuffer_internal_t)); 
101     memset(r, 0, sizeof(ringbuffer_t));
102     r->internal = i;
103     i->buffer = (unsigned char*)rfx_alloc(1024);
104     i->buffersize = 1024;
105 }
106 int ringbuffer_read(ringbuffer_t*r, void*buf, int len)
107 {
108     unsigned char* data = (unsigned char*)buf;
109     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
110     if(r->available < len)
111         len = r->available;
112     if(!len)
113         return 0;
114     if(i->readpos + len > i->buffersize) {
115         int read1 = i->buffersize-i->readpos;
116         memcpy(data, &i->buffer[i->readpos], read1);
117         memcpy(&data[read1], &i->buffer[0], len - read1);
118         i->readpos = len - read1;
119     } else {
120         memcpy(data, &i->buffer[i->readpos], len);
121         i->readpos += len;
122         i->readpos %= i->buffersize;
123     }
124     r->available -= len;
125     return len;
126 }
127 void ringbuffer_put(ringbuffer_t*r, void*buf, int len)
128 {
129     unsigned char* data = (unsigned char*)buf;
130     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
131     
132     if(i->buffersize - r->available < len)
133     {
134         unsigned char* buf2;
135         int newbuffersize = i->buffersize;
136         int oldavailable = r->available;
137         newbuffersize*=3;newbuffersize/=2; /*grow at least by 50% each time */
138
139         if(newbuffersize < r->available + len)
140             newbuffersize = r->available + len + 1024;
141
142         buf2 = (unsigned char*)rfx_alloc(newbuffersize);
143         ringbuffer_read(r, buf2, r->available);
144         rfx_free(i->buffer);
145         i->buffer = buf2;
146         i->buffersize = newbuffersize;
147         i->readpos = 0;
148         i->writepos = oldavailable;
149         r->available = oldavailable;
150     }
151     if(i->writepos + len > i->buffersize) {
152         int read1 = i->buffersize-i->writepos;
153         memcpy(&i->buffer[i->writepos], data, read1);
154         memcpy(&i->buffer[0], &data[read1], len - read1);
155         i->writepos = len - read1;
156     } else {
157         memcpy(&i->buffer[i->writepos], data, len);
158         i->writepos += len;
159         i->writepos %= i->buffersize;
160     }
161     r->available += len;
162 }
163 void ringbuffer_clear(ringbuffer_t*r)
164 {
165     ringbuffer_internal_t*i = (ringbuffer_internal_t*)r->internal;
166     rfx_free(i->buffer);i->buffer = 0;
167     rfx_free(i);
168 }
169
170 // ------------------------------- heap_t -------------------------------
171
172 void heap_init(heap_t*h,int n,int elem_size, int(*compare)(const void *, const void *))
173 {
174     memset(h, 0, sizeof(heap_t));
175     h->max_size = n;
176     h->size = 0;
177     h->elem_size = elem_size;
178     h->compare = compare;
179     h->elements = (void**)rfx_calloc(n*sizeof(void*));
180     h->data = (char*)rfx_calloc(h->max_size*h->elem_size);
181 }
182 void heap_clear(heap_t*h)
183 {
184     rfx_free(h->elements);
185     rfx_free(h->data);
186 }
187
188 #define HEAP_NODE_SMALLER(h,node1,node2) ((h)->compare((node1),(node2))>0)
189
190 static void up(heap_t*h, int node)
191 {
192     void*node_p = h->elements[node];
193     int parent = node;
194     do {
195         node = parent;
196         if(!node) break;
197         parent = (node-1)/2;
198         h->elements[node] = h->elements[parent];
199     } while(HEAP_NODE_SMALLER(h,h->elements[parent], node_p));
200
201     h->elements[node] = node_p;
202 }
203 static void down(heap_t*h, int node)
204 {
205     void*node_p = h->elements[node];
206     int child = node;
207     do {
208         node = child;
209
210         /* determine new child's position */
211         child = node<<1|1;
212         if(child >= h->size) 
213             break;
214         if(child+1 < h->size && HEAP_NODE_SMALLER(h,h->elements[child],h->elements[child+1])) // search for bigger child
215             child++;
216
217         h->elements[node] = h->elements[child];
218     } while(HEAP_NODE_SMALLER(h,node_p, h->elements[child]));
219     
220     h->elements[node] = node_p;
221 }
222 void heap_put(heap_t*h, void*e) 
223 {
224     int pos = h->size++;
225     memcpy(&h->data[pos*h->elem_size],e,h->elem_size);
226     h->elements[pos] = &h->data[pos];
227     up(h, pos);
228 }
229 int heap_size(heap_t*h)
230 {
231     return h->size;
232 }
233 void* heap_max(heap_t*h)
234 {
235     return h->elements[0];
236 }
237 void* heap_chopmax(heap_t*h)
238 {
239     void*p = h->elements[0];
240     h->elements[0] = h->elements[--h->size];
241     down(h,0);
242     return p;
243 }
244 void heap_dump(heap_t*h, FILE*fi)
245 {
246     int t;
247     for(t=0;t<h->size;t++) {
248         int s;
249         for(s=0;s<=t;s=(s+1)*2-1) {
250             if(s==t) fprintf(fi,"\n");
251         }
252         //fprintf(fi,"%d ", h->elements[t]->x); //?
253     }
254 }
255 void** heap_flatten(heap_t*h)
256 {
257     void**nodes = (void**)rfx_alloc(h->size*sizeof(void*));
258     void**p = nodes;
259    
260     while(h->size) {
261         /*printf("Heap Size: %d\n", h->size);
262         heap_print(stdout, h);
263         printf("\n");*/
264         *p++ = heap_chopmax(h);
265     }
266     return nodes;
267 }
268
269 // ------------------------------- crc32 --------------------------------------
270 static unsigned int*crc32 = 0;
271 static void crc32_init(void)
272 {
273     int t;
274     if(crc32) 
275         return;
276     crc32= (unsigned int*)rfx_alloc(sizeof(unsigned int)*256);
277     for(t=0; t<256; t++) {
278         unsigned int c = t;
279         int s;
280         for (s = 0; s < 8; s++) {
281           c = (0xedb88320L*(c&1)) ^ (c >> 1);
282         }
283         crc32[t] = c;
284     }
285 }
286 // ------------------------------- string_t -----------------------------------
287
288 void string_set2(string_t*str, const char*text, int len)
289 {
290     str->len = len;
291     str->str = text;
292 }
293 void string_set(string_t*str, const char*text)
294 {
295     str->len = strlen(text);
296     str->str = text;
297 }
298 string_t string_new(const char*text, int len)
299 {
300     string_t s;
301     s.len = len;
302     s.str = text;
303     return s;
304 }
305 string_t string_new2(const char*text)
306 {
307     string_t s;
308     s.len = strlen(text);
309     s.str = text;
310     return s;
311 }
312 char* string_cstr(string_t*str)
313 {
314     return strdup_n(str->str, str->len);
315 }
316 unsigned int string_hash(string_t*str)
317 {
318     int t;
319     unsigned int checksum = 0;
320     if(!crc32)
321         crc32_init();
322     for(t=0;t<str->len;t++) {
323         checksum = checksum>>8 ^ crc32[(str->str[t]^checksum)&0xff];
324     }
325     return checksum;
326 }
327 unsigned int string_hash2(const char*str)
328 {
329     unsigned int checksum = 0;
330     const char*p = str;
331     if(!crc32)
332         crc32_init();
333     while(*p) {
334         checksum = checksum>>8 ^ crc32[(*p^checksum)&0xff];
335         p++;
336     }
337     return checksum;
338 }
339 unsigned int string_hash3(const char*str, int len)
340 {
341     string_t s;
342     s.str = str;
343     s.len = len;
344     return string_hash(&s);
345 }
346 void string_dup2(string_t*str, const char*text, int len)
347 {
348     str->len = len;
349     str->str = strdup_n(text, len);
350 }
351 void string_dup(string_t*str, const char*text)
352 {
353     str->len = strlen(text);
354     str->str = strdup(text);
355 }
356 int string_equals(string_t*str, const char*text)
357 {
358     int l = strlen(text);
359     if(str->len == l && !memcmp(str->str, text, l))
360         return 1;
361     return 0;
362 }
363 int string_equals2(string_t*str, string_t*str2)
364 {
365     if(str->len == str2->len && !memcmp(str->str, str2->str, str->len))
366         return 1;
367     return 0;
368 }
369
370 // ------------------------------- stringarray_t ------------------------------
371
372 typedef struct _stringlist {
373     int index;
374     struct _stringlist*next;
375 } stringlist_t;
376
377 typedef struct _stringarray_internal_t
378 {
379     mem_t pos;
380     stringlist_t**hash;
381     int num;
382     int hashsize;
383 } stringarray_internal_t;
384
385 void stringarray_init(stringarray_t*sa, int hashsize)
386 {
387     stringarray_internal_t*s;
388     int t;
389     sa->internal = (stringarray_internal_t*)rfx_calloc(sizeof(stringarray_internal_t)); 
390     s = (stringarray_internal_t*)sa->internal;
391     mem_init(&s->pos);
392     s->hash = rfx_calloc(sizeof(stringlist_t*)*hashsize);
393     s->hashsize = hashsize;
394 }
395 void stringarray_put(stringarray_t*sa, string_t str)
396 {
397     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
398     int pos;
399     int hash = string_hash(&str) % s->hashsize;
400
401     char*ss = string_cstr(&str);
402     mem_put(&s->pos, &ss, sizeof(char*));
403
404     stringlist_t*l = rfx_alloc(sizeof(stringlist_t));
405     l->index = s->num;
406     l->next = s->hash[hash];
407     s->hash[hash] = l;
408
409     s->num++;
410 }
411 char* stringarray_at(stringarray_t*sa, int pos)
412 {
413     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
414     char*p;
415     if(pos<0 || pos>=s->num)
416         return 0;
417     p = *(char**)&s->pos.buffer[pos*sizeof(char*)];
418     if(p<0)
419         return 0;
420     return p;
421 }
422 string_t stringarray_at2(stringarray_t*sa, int pos)
423 {
424     string_t s;
425     s.str = stringarray_at(sa, pos);
426     s.len = s.str?strlen(s.str):0;
427     return s;
428 }
429 static stringlist_t* stringlist_del(stringarray_t*sa, stringlist_t*l, int index)
430 {
431     stringlist_t*ll = l;
432     stringlist_t*old = l;
433     while(l) {
434         if(index==l->index) {
435             old->next = l->next;
436             memset(l, 0, sizeof(stringlist_t));
437             rfx_free(l);
438             if(old==l)
439                 return 0;
440             else
441                 return ll;
442         }
443         old = l;
444         l = l->next;
445     }
446     fprintf(stderr, "Internal error: did not find string %d in hash\n", index);
447     return ll;
448 }
449
450 void stringarray_del(stringarray_t*sa, int pos)
451 {
452     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
453     string_t str = stringarray_at2(sa, pos);
454     int hash = string_hash(&str) % s->hashsize;
455     s->hash[hash] = stringlist_del(sa, s->hash[hash], pos);
456     *(char**)&s->pos.buffer[pos*sizeof(char*)] = 0;
457 }
458 int stringarray_find(stringarray_t*sa, string_t* str)
459 {
460     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
461     int hash = string_hash(str) % s->hashsize;
462     int t;
463     stringlist_t*l = s->hash[hash];
464     //TODO: statistics
465     while(l) {
466         string_t s = stringarray_at2(sa, l->index);
467         if(string_equals2(str, &s)) {
468             return l->index;
469         }
470         l = l->next;
471     }
472     return -1;
473 }
474 void stringarray_clear(stringarray_t*sa)
475 {
476     stringarray_internal_t*s = (stringarray_internal_t*)sa->internal;
477     mem_clear(&s->pos);
478     int t;
479     for(t=0;t<s->hashsize;t++) {
480         stringlist_t*l = s->hash[t];
481         while(l) {
482             stringlist_t*next = l->next;
483             memset(l, 0, sizeof(stringlist_t));
484             rfx_free(l);
485             l = next;
486         }
487     }
488     rfx_free(s->hash);s->hash=0;
489     rfx_free(s);
490 }
491 void stringarray_destroy(stringarray_t*sa)
492 {
493     stringarray_clear(sa);
494     rfx_free(sa);
495 }
496
497
498 // ------------------------------- dictionary_t -------------------------------
499
500 #define INITIAL_SIZE 63
501
502 dict_t*dict_new()
503 {
504     dict_t*d = rfx_alloc(sizeof(dict_t));
505     dict_init(d);
506     return d;
507 }
508 void dict_init(dict_t*h) 
509 {
510     memset(h, 0, sizeof(dict_t));
511     h->hashsize = INITIAL_SIZE;
512     h->slots = h->hashsize?(dictentry_t**)rfx_calloc(sizeof(dictentry_t*)*h->hashsize):0;
513     h->num = 0;
514 }
515 static void dict_expand(dict_t*h, int newlen)
516 {
517     assert(h->hashsize < newlen);
518     dictentry_t**newslots = (dictentry_t**)rfx_calloc(sizeof(dictentry_t*)*newlen);
519     int t; 
520     for(t=0;t<h->hashsize;t++) {
521         dictentry_t*e = h->slots[t];
522         while(e) {
523             dictentry_t*next = e->next;
524             unsigned int newhash = e->hash%newlen;
525             e->next = newslots[newhash];
526             newslots[newhash] = e;
527             e = next;
528         }
529     }
530     if(h->slots)
531         rfx_free(h->slots);
532     h->slots = newslots;
533     h->hashsize = newlen;
534 }
535 void dict_put(dict_t*h, string_t s, void* data)
536 {
537     unsigned int hash = string_hash(&s);
538     dictentry_t*e = (dictentry_t*)rfx_alloc(sizeof(dictentry_t));
539
540     unsigned int hash2 = string_hash(&s) % h->hashsize;
541     char*sdata = rfx_alloc(s.len);
542     memcpy(sdata, s.str, s.len);
543     e->s = sdata;
544     e->len = s.len;
545     e->hash = hash; //for resizing
546     e->next = h->slots[hash2];
547     e->data = data;
548     h->slots[hash2] = e;
549     h->num++;
550 }
551 void dict_put2(dict_t*h, const char*s, void*data) 
552 {
553     string_t s2;
554     string_set(&s2, s);
555     dict_put(h, s2, data);
556 }
557 void dict_put3(dict_t*h, const char* s, int len, void*data)
558 {
559     string_t s3;
560     string_set2(&s3, s, len);
561     dict_put(h, s3, data);
562 }
563 void dict_dump(dict_t*h, FILE*fi, const char*prefix)
564 {
565     int t;
566     for(t=0;t<h->hashsize;t++) {
567         dictentry_t*e = h->slots[t];
568         while(e) {
569             char*s = strdup_n(e->s, e->len);
570             fprintf(fi, "%s%s=%08x\n", prefix, e->s, e->data);
571             rfx_free(s);
572             e = e->next;
573         }
574     }
575 }
576 int dict_count(dict_t*h)
577 {
578     return h->num;
579 }
580 void* dict_lookup2(dict_t*h, const char*s, int len)
581 {
582     if(!h->num)
583         return 0;
584
585     if(h->num*3 >= h->hashsize*2) {
586         /* if dict is 2/3 filled, double the size */
587         dict_expand(h, (h->hashsize+1)*2-1);
588     }
589
590     unsigned int ohash = string_hash2(s);
591     unsigned int hash = ohash % h->hashsize;
592
593     dictentry_t*e = h->slots[hash];
594     while(e) {
595         if(e->len == len && !memcmp(e->s, s, len)) {
596             return e->data;
597         }
598         e = e->next;
599     }
600     return 0;
601 }
602 void* dict_lookup(dict_t*h, const char*s)
603 {
604     int l = strlen(s);
605     return dict_lookup2(h, s, l);
606 }
607 char dict_del(dict_t*h, const char*s)
608 {
609     if(!h->num)
610         return 0;
611     unsigned int hash = string_hash2(s) % h->hashsize;
612     int l = strlen(s);
613     dictentry_t*head = h->slots[hash];
614     dictentry_t*e = head, *prev=0;
615     while(e) {
616         if(e->len ==l && !memcmp(e->s, s, l)) {
617             dictentry_t*next = e->next;
618             rfx_free((void*)e->s);
619             memset(e, 0, sizeof(dictentry_t));
620             rfx_free(e);
621             if(e == head) {
622                 h->slots[hash] = 0;
623             } else {
624                 assert(prev);
625                 prev->next = next;
626             }
627             h->num--;
628             return 1;
629         }
630         prev = e;
631         e = e->next;
632     }
633     return 0;
634 }
635 void dict_foreach_keyvalue(dict_t*h, void (*runFunction)(void*data, const char*key, void*val), void*data)
636 {
637     int t;
638     for(t=0;t<h->hashsize;t++) {
639         dictentry_t*e = h->slots[t];
640         while(e) {
641             dictentry_t*next = e->next;
642             if(runFunction) {
643                 char*s = strdup_n(e->s, e->len); //append \0
644                 runFunction(data, s, e->data);
645                 rfx_free(s);
646             }
647             e = e->next;
648         }
649     }
650 }
651 void dict_foreach_value(dict_t*h, void (*runFunction)(void*))
652 {
653     int t;
654     for(t=0;t<h->hashsize;t++) {
655         dictentry_t*e = h->slots[t];
656         while(e) {
657             dictentry_t*next = e->next;
658             if(runFunction) {
659                 runFunction(e->data);
660             }
661             e = e->next;
662         }
663     }
664 }
665 void dict_free_all(dict_t*h, void (*freeFunction)(void*))
666 {
667     int t;
668     for(t=0;t<h->hashsize;t++) {
669         dictentry_t*e = h->slots[t];
670         while(e) {
671             dictentry_t*next = e->next;
672             rfx_free((void*)e->s);
673             if(freeFunction) {
674                 freeFunction(e->data);
675             }
676             memset(e, 0, sizeof(dictentry_t));
677             rfx_free(e);
678             e = next;
679         }
680     }
681     rfx_free(h->slots);
682     memset(h, 0, sizeof(dict_t));
683 }
684 void dict_clear(dict_t*h) 
685 {
686     dict_free_all(h, 0);
687 }
688 void dict_destroy(dict_t*dict)
689 {
690     dict_clear(dict);
691     rfx_free(dict);
692 }
693
694 // ------------------------------- map_t --------------------------------------
695
696 typedef struct _map_internal_t
697 {
698     dict_t d;
699 } map_internal_t;
700
701 void map_init(map_t*map)
702 {
703     map_internal_t*m;
704     map->internal = (map_internal_t*)rfx_calloc(sizeof(map_internal_t));
705     m = (map_internal_t*)map->internal;
706     dict_init(&m->d);
707 }
708 void map_put(map_t*map, string_t t1, string_t t2)
709 {
710     map_internal_t*m = (map_internal_t*)map->internal;
711     string_t s;
712     char* s1 = string_cstr(&t1);
713     dict_put2(&m->d, s1, (void*)string_cstr(&t2));
714     rfx_free(s1);
715 }
716 const char* map_lookup(map_t*map, const char*name)
717 {
718     map_internal_t*m = (map_internal_t*)map->internal;
719     const char*value = dict_lookup(&m->d, name);
720     return value;
721 }
722 static void freestring(void*data)
723 {
724     rfx_free(data);
725 }
726 static void dumpmapentry(void*data, const char*key, void*value)
727 {
728     FILE*fi = (FILE*)data;
729     fprintf(fi, "%s=%s\n", key, (char*)value);
730 }
731 void map_dump(map_t*map, FILE*fi, const char*prefix)
732 {
733     int t;
734     map_internal_t*m = (map_internal_t*)map->internal;
735     dict_foreach_keyvalue(&m->d, dumpmapentry, fi);
736 }
737 void map_clear(map_t*map)
738 {
739     map_internal_t*m = (map_internal_t*)map->internal;
740     dict_free_all(&m->d, freestring);
741     rfx_free(m);
742 }
743 void map_destroy(map_t*map)
744 {
745     map_clear(map);
746     rfx_free(map);
747 }
748