Updating to reflect the latest work.
[zilutils.git] / zilasm / symtable.c
1 /*
2  * symtable.c -- part of ZilUtils/ZilAsm
3  *
4  * Copyright (C) 2016 Jason Self <j@jxself.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include <assert.h>
23
24 #include "symtable.h"
25
26 #define FIELD_SIZE(Typ,Field)  (sizeof(((Typ*)0)->Field))
27
28 Symtable* symtable_create(unsigned elems_count, unsigned name_size, unsigned elem_size)
29 {
30         size_t n = elems_count * (name_size + elem_size) + sizeof(Symtable) - FIELD_SIZE(Symtable, contents);
31         Symtable *p = malloc(n);
32         assert(p);
33         bzero(p, n);
34         p->elems_count = elems_count;
35         p->name_size   = name_size;
36         p->elem_size   = elem_size;
37         return p;
38 }
39
40 void symtable_destroy(Symtable *p)
41 {
42         assert(p);
43         free(p);
44 }
45
46 static unsigned name2pos(const Symtable *p, const char *name, unsigned namelen)
47 {
48         assert(p);
49         unsigned key = 0;
50         while(namelen--)
51                 key = ((key << 1) | (*name++));
52         return key % p->elems_count;
53 }
54
55 static char *getsym(const Symtable *p, unsigned pos)
56 {
57         //assert(p);   //already checked by caller
58         //assert(pos < p->elems_count);
59         return ((char*)p) + sizeof(Symtable) - FIELD_SIZE(Symtable, contents) + (pos * p->elem_size);
60 }
61
62 void* symtable_lookup2(const Symtable *p, const char *name, unsigned namelen)
63 {
64         assert(p);
65         assert(name);
66         assert(namelen > 0);
67         assert(namelen < p->name_size);
68
69         unsigned start = name2pos(p, name, namelen);
70         unsigned pos = start;
71
72         do {
73                 char *s = getsym(p, pos);
74                 if (!*s)
75                         return NULL;
76                 if (!memcmp(name, s, namelen))
77                         return s + p->name_size;
78                 if (++pos >= p->elems_count)
79                         pos = 0;
80         } while(pos != start);
81
82         return NULL;
83 }
84
85 void* symtable_lookup(const Symtable *p, const char *name)
86 {
87         assert(name);
88         return symtable_lookup2(p, name, strlen(name));
89 }
90
91 void* symtable_add(Symtable *p, const char *name, void *contents)
92 {
93         assert(name);
94         return symtable_add2(p, name, strlen(name), contents);
95 }
96
97 void* symtable_add2(Symtable *p, const char *name, unsigned namelen, void *contents)
98 {
99         assert(p);
100         assert(name);
101         assert(namelen > 0 && namelen < p->name_size);
102         assert(contents);
103
104         unsigned start = name2pos(p, name, namelen);
105         unsigned pos = start;
106
107         do {
108                 char *s = getsym(p, pos);
109                 if (!*s) {
110                         memcpy(s, name, namelen + 1);
111                         s[namelen] = '\0';
112                         memcpy(s + p->name_size, contents, p->elem_size);
113                         return s + p->name_size;
114                 }
115                 if (!memcmp(name, s, namelen) && s[namelen] == '\0') {
116                         /* TODO!! report error */
117                         return NULL;  /* ..already added */
118                 }
119                 if (++pos >= p->elems_count)
120                         pos = 0;
121         } while(pos != start);
122
123         /* TODO!! report overflow */
124         return NULL;
125         /* TODO!!! */
126 }
127
128 static int sortfunc(const void *a, const void *b)
129 {
130         const char *s1 = a;
131         const char *s2 = b;
132         if (!*s1 && !*s2) return  0;
133         if (!*s1)         return  1;
134         if (!*s2)         return -1;
135         return strcmp(s1, s2);
136 }
137
138 void symtable_sort(Symtable *p)
139 {
140         assert(p);
141         qsort(getsym(p, 0), p->elems_count, p->elem_size + p->name_size, sortfunc);
142 }
143
144 /* END */