-
Notifications
You must be signed in to change notification settings - Fork 1
/
chtrie.c
109 lines (101 loc) · 1.97 KB
/
chtrie.c
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
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include "chtrie.h"
#define SZ_MAX ((size_t)-1)
#define MIN(x, y) ((x)<(y)?(x):(y))
chtrie *chtrie_alloc(size_t n, size_t m)
{
chtrie *tr;
if (n < 1) n = 1;
if (m < 1) m = 1;
if (n > INT_MAX || m > INT_MAX) {
errno = ERANGE;
goto err;
}
if (MIN(INT_MAX, SZ_MAX) - (n-1) < (n-1) / 3) {
errno = ERANGE;
goto err;
}
if (!(tr = calloc(1, sizeof *tr)))
goto err;
tr->maxn = n;
tr->alphsz = m;
tr->ecap = (n-1) + (n-1)/3;
if (!(tr->etab = calloc(tr->ecap, sizeof tr->etab[0])))
goto free_tr;
if (!(tr->idxpool = calloc(n, sizeof tr->idxpool[0])))
goto free_ecap;
tr->idxmax = 1;
tr->idxptr = tr->idxpool;
return tr;
free_ecap:
free(tr->etab);
free_tr:
free(tr);
err:
return NULL;
}
int chtrie_walk(chtrie *tr, int from, int sym, int creat)
{
struct chtrie_edge *p;
unsigned long h;
h = (unsigned long)from*tr->alphsz + sym;
h %= tr->ecap;
for (p = tr->etab[h]; p; p = p->next)
if (p->from == from && p->sym == sym)
return p->to;
if (creat) {
if (tr->idxptr == tr->idxpool && tr->idxmax >= tr->maxn) {
errno = ENOMEM;
return -1;
}
if (!(p = malloc(sizeof *p)))
return -1;
p->next = tr->etab[h];
tr->etab[h] = p;
p->from = from;
p->sym = sym;
if (tr->idxptr != tr->idxpool)
p->to = *--tr->idxptr;
else
p->to = tr->idxmax++;
return p->to;
}
return -1;
}
void chtrie_del(chtrie *tr, int from, int sym)
{
struct chtrie_edge *p, *q;
unsigned long h;
h = (unsigned long)from*tr->alphsz + sym;
h %= tr->ecap;
for (p = tr->etab[h], q = NULL; p; q = p, p = p->next)
if (p->from == from && p->sym == sym)
break;
if (!p)
return;
if (q)
q->next = p->next;
else
tr->etab[h] = NULL;
*tr->idxptr++ = p->to;
free(p);
}
void chtrie_free(chtrie *tr)
{
struct chtrie_edge *p, *q;
int i;
for (i = 0; i < tr->ecap; i++) {
p = tr->etab[i];
while (p) {
q = p->next;
free(p);
p = q;
}
}
free(tr->etab);
free(tr->idxpool);
free(tr);
}