History

add qp tries

Sigrid Haflínudóttir committed 6 years ago

Commit 4fb339cNo parent (first commit)4 files · +187 −0Browse files

Unified · Split

4 files
  1. LICENSE +1 −0
  2. README.md +6 −0
  3. qp.c +174 −0
  4. qp.h +6 −0
LICENSE+1−0
@@ -0,0 +1 @@
1+Public domain.
README.md+6−0
@@ -0,0 +1,6 @@
1+# Snippets
2+
3+Random snippets of code that are in public domain.
4+Just copy and use for whatever you want.
5+
6+* `qt.[ch]` [QP tries](https://dotat.at/prog/qp/README.html)
qp.c+174−0
@@ -0,0 +1,174 @@
1+#include <u.h>
2+#include <libc.h>
3+#include "qp.h"
4+
5+typedef u16int Tbitmap;
6+typedef struct Tbranch Tbranch;
7+typedef struct Tleaf Tleaf;
8+
9+struct Tleaf {
10+ char *k;
11+ void *v;
12+};
13+
14+struct Tbranch {
15+ Trie *twigs;
16+ u64int x;
17+};
18+
19+union Trie {
20+ Tleaf leaf;
21+ Tbranch branch;
22+};
23+
24+#define x_flags(x) ((x)>>62)
25+#define x_index(x) ((x)>>16 & ((1ULL<<46)-1ULL))
26+#define x_bitmap(x) ((x) & 0xffff)
27+
28+#define isbranch(t) (x_flags((t)->branch.x) != 0)
29+#define hastwig(t, b) (x_bitmap((t)->branch.x) & (b))
30+#define twigoff(t, b) popcount(x_bitmap((t)->branch.x) & ((b)-1))
31+#define twig(t, i) (&(t)->branch.twigs[(i)])
32+#define twigoffmax(off, max, t, b) do{ off = twigoff(t, b); max = popcount(x_bitmap((t)->branch.x)); }while(0)
33+#define nibbit(k, f) (1 << (((k) & (((f)-2) ^ 0x0f) & 0xff) >> ((2-(f))<<2)))
34+#define twigbit(t, k, len) \
35+ (x_index((t)->branch.x) >= (len) ? \
36+ 1 : \
37+ nibbit((u8int)(k)[x_index((t)->branch.x)], x_flags((t)->branch.x)))
38+
39+/*
40+// need some speed? just say no.
41+#define POPCNT BYTE $0xf3; BYTE $0x0f; BYTE $0xb8
42+
43+TEXT popcount(SB),$0
44+ MOVL b+0(FP), AX
45+ POPCNT
46+ RET
47+*/
48+static u16int
49+popcount(u16int b)
50+{
51+ b -= b>>1 & 0x5555;
52+ b = (b & 0x3333) + ((b>>2) & 0x3333);
53+ b = (b + (b>>4)) & 0x0f0f;
54+ b = (b + (b>>8)) & 0x00ff;
55+ return b;
56+}
57+
58+int
59+qpget(Trie *t, char *k, int len, char **pk, char **pv)
60+{
61+ Tbitmap b;
62+
63+ assert(k != nil && pk != nil && pv != nil);
64+
65+ for(; isbranch(t); t = twig(t, twigoff(t, b))){
66+ b = twigbit(t, k, len);
67+ if(!hastwig(t, b))
68+ return -1;
69+ }
70+ if(strncmp(k, t->leaf.k, len) != 0)
71+ return -1;
72+ *pk = t->leaf.k;
73+ *pv = t->leaf.v;
74+
75+ return 0;
76+}
77+
78+int
79+qpnext(Trie *t, char **pk, int *plen, void **pv)
80+{
81+ Tbitmap b;
82+ uint s, m;
83+
84+ assert(pk != nil && plen != nil && pv != nil);
85+
86+ if(isbranch(t)){
87+ b = twigbit(t, *pk, *plen);
88+ twigoffmax(s, m, t, b);
89+ for(; s < m; s++){
90+ if(qpnext(twig(t, s), pk, plen, pv) == 0)
91+ return 0;
92+ }
93+ return -1;
94+ }
95+
96+ if(*pk == nil){
97+ *pk = t->leaf.k;
98+ *plen = strlen(*pk);
99+ *pv = t->leaf.v;
100+ return 0;
101+ }
102+
103+ return -1;
104+}
105+
106+Trie *
107+qpset(Trie *t, char *k, int len, void *v)
108+{
109+ Trie *t0, t1, t2;
110+ uint i, s, m;
111+ u8int f;
112+ Tbitmap b, b1, b2;
113+ u8int k2;
114+
115+ assert(k != nil && v != nil);
116+ if(len < 1)
117+ len = strlen(k);
118+ assert(len > 0);
119+
120+ if(t == nil){
121+ t = malloc(sizeof(*t));
122+ t->leaf.k = k;
123+ t->leaf.v = v;
124+ return t;
125+ }
126+
127+ t0 = t;
128+ for(; isbranch(t); t = twig(t, i)){
129+ b = twigbit(t, k, len);
130+ i = hastwig(t, b) ? twigoff(t, b) : 0;
131+ }
132+ for(i = 0; i <= len && k[i] == t->leaf.k[i]; i++);
133+ if(i == len+1){
134+ t->leaf.v = v;
135+ return t0;
136+ }
137+
138+ k2 = (u8int)t->leaf.k[i];
139+ f = (((u8int)k[i] ^ k2) & 0xf0) ? 1 : 2;
140+ b1 = nibbit(k[i], f);
141+ t1.leaf.k = k;
142+ t1.leaf.v = v;
143+ for(t = t0; isbranch(t); t = twig(t, twigoff(t, b))){
144+ if(i == x_index(t->branch.x)){
145+ if(f == x_flags(t->branch.x))
146+ goto growbranch;
147+ if(f < x_flags(t->branch.x))
148+ break;
149+ }else if(i < x_index(t->branch.x)){
150+ break;
151+ }
152+ b = twigbit(t, k, len);
153+ assert(hastwig(t, b));
154+ }
155+
156+ t2 = *t;
157+ b2 = nibbit(k2, f);
158+ t->branch.twigs = malloc(sizeof(*t)*2);
159+ t->branch.x = (uvlong)f<<62 | (uvlong)i<<16 | b1 | b2;
160+ *twig(t, twigoff(t, b1)) = t1;
161+ *twig(t, twigoff(t, b2)) = t2;
162+
163+ return t0;
164+
165+growbranch:
166+ assert(!hastwig(t, b1));
167+ twigoffmax(s, m, t, b1);
168+ t->branch.twigs = realloc(t->branch.twigs, sizeof(*t)*(m+1));
169+ memmove(t->branch.twigs+s+1, t->branch.twigs+s, sizeof(*t)*(m-s));
170+ memmove(t->branch.twigs+s, &t1, sizeof(t1));
171+ t->branch.x |= b1;
172+
173+ return t0;
174+}
qp.h+6−0
@@ -0,0 +1,6 @@
1+typedef union Trie Trie;
2+#pragma incomplete Trie
3+
4+int qpget(Trie *t, char *k, int len, char **pk, char **pv);
5+int qpnext(Trie *t, char **pk, int *plen, void **pv);
6+Trie *qpset(Trie *t, char *k, int len, void *v);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t