-
Notifications
You must be signed in to change notification settings - Fork 0
/
istr.h
148 lines (110 loc) · 2.4 KB
/
istr.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#ifndef INTERN_H
#define INTERN_H
#include <stddef.h>
typedef const char *istr;
void init_interns();
istr intern(const char*, size_t);
istr intern_substr(const char*, const char*);
istr intern_str(const char*); // Null-terminated
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#define INTERN_DEF_CAP 1024
typedef struct {
istr data;
size_t len;
} intern_entry;
// const char* -> istr
typedef struct {
intern_entry *data;
size_t cap;
size_t len;
} intern_table;
static intern_table interns;
static size_t hash(const char *str, size_t len)
{
size_t h = 5381;
size_t i = 0;
while (i < len)
h += (h << 5) + str[i++];
return h;
}
intern_entry table_get_ins(intern_table*, const char*, size_t);
void table_resize(intern_table *table)
{
size_t sz = table->cap * 2;
intern_table swap = {
calloc(sz, sizeof(intern_entry)),
sz,
0,
};
if (table->data) {
for (size_t i = 0; i < table->cap; ++i) {
intern_entry entry = table->data[i];
if (!entry.data) continue;
table_get_ins(&swap, entry.data, entry.len);
}
free(table->data);
}
*table = swap;
}
intern_table new_intern_table(size_t desired_len)
{
assert(desired_len);
intern_table table;
table.data = NULL;
table.cap = desired_len;
table_resize(&table);
return table;
}
intern_entry table_get_ins(intern_table *table, const char *str, size_t len)
{
if ((table->len + 1) * 2 >= table->cap)
table_resize(table);
assert((table->len + 1) * 2 < table->cap);
size_t i = hash(str, len);
i %= table->cap;
intern_entry entry;
while (1) {
entry = table->data[i];
if (!entry.data) break;
else if (len == entry.len && !strncmp(str, entry.data, len))
return entry;
i = (i + 1) % table->cap;
}
/* Make new intern */
// Allocate string
char *data = (char*)malloc(len + 1);
if (!data) {
perror("Memory error");
exit(1);
}
memcpy(data, str, len);
data[len] = 0; // Null terminator
entry.data = data;
entry.len = len;
table->data[i] = entry;
table->len++;
return entry;
}
void init_interns()
{
interns = new_intern_table(INTERN_DEF_CAP);
}
istr intern(const char *str, size_t len)
{
assert(interns.data);
return table_get_ins(&interns, str, len).data;
}
istr intern_substr(const char *beg, const char *end)
{
size_t len = end - beg;
return intern(beg, len);
}
istr intern_str(const char *str)
{
size_t len = strlen(str);
return intern(str, len);
}
#endif