ox-bundlecachetest 2.14.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +751 -0
- data/LICENSE +21 -0
- data/README.md +351 -0
- data/ext/ox/attr.h +78 -0
- data/ext/ox/base64.c +105 -0
- data/ext/ox/base64.h +18 -0
- data/ext/ox/buf.h +162 -0
- data/ext/ox/builder.c +948 -0
- data/ext/ox/cache.c +351 -0
- data/ext/ox/cache.h +21 -0
- data/ext/ox/cache8.c +106 -0
- data/ext/ox/cache8.h +23 -0
- data/ext/ox/dump.c +1260 -0
- data/ext/ox/err.c +46 -0
- data/ext/ox/err.h +36 -0
- data/ext/ox/extconf.rb +47 -0
- data/ext/ox/gen_load.c +342 -0
- data/ext/ox/hash_load.c +309 -0
- data/ext/ox/helper.h +84 -0
- data/ext/ox/intern.c +157 -0
- data/ext/ox/intern.h +25 -0
- data/ext/ox/obj_load.c +809 -0
- data/ext/ox/ox.c +1649 -0
- data/ext/ox/ox.h +245 -0
- data/ext/ox/parse.c +1197 -0
- data/ext/ox/sax.c +1570 -0
- data/ext/ox/sax.h +69 -0
- data/ext/ox/sax_as.c +270 -0
- data/ext/ox/sax_buf.c +209 -0
- data/ext/ox/sax_buf.h +204 -0
- data/ext/ox/sax_hint.c +207 -0
- data/ext/ox/sax_hint.h +40 -0
- data/ext/ox/sax_stack.h +113 -0
- data/ext/ox/slotcache.c +158 -0
- data/ext/ox/slotcache.h +19 -0
- data/ext/ox/special.c +390 -0
- data/ext/ox/special.h +14 -0
- data/ext/ox/type.h +39 -0
- data/lib/ox/bag.rb +103 -0
- data/lib/ox/cdata.rb +10 -0
- data/lib/ox/comment.rb +11 -0
- data/lib/ox/doctype.rb +11 -0
- data/lib/ox/document.rb +28 -0
- data/lib/ox/element.rb +464 -0
- data/lib/ox/error.rb +25 -0
- data/lib/ox/hasattrs.rb +54 -0
- data/lib/ox/instruct.rb +34 -0
- data/lib/ox/node.rb +23 -0
- data/lib/ox/raw.rb +12 -0
- data/lib/ox/sax.rb +97 -0
- data/lib/ox/version.rb +4 -0
- data/lib/ox/xmlrpc_adapter.rb +33 -0
- data/lib/ox.rb +79 -0
- metadata +128 -0
data/ext/ox/cache.c
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
|
3
|
+
|
|
4
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
|
5
|
+
#include <pthread.h>
|
|
6
|
+
#endif
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
|
|
9
|
+
#include "cache.h"
|
|
10
|
+
|
|
11
|
+
// The stdlib calloc, realloc, and free are used instead of the Ruby ALLOC,
|
|
12
|
+
// ALLOC_N, REALLOC, and xfree since the later could trigger a GC which will
|
|
13
|
+
// either corrupt memory or if the mark function locks will deadlock.
|
|
14
|
+
|
|
15
|
+
#define REHASH_LIMIT 4
|
|
16
|
+
#define MIN_SHIFT 8
|
|
17
|
+
#define REUSE_MAX 8192
|
|
18
|
+
|
|
19
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
|
20
|
+
#define CACHE_LOCK(c) pthread_mutex_lock(&((c)->mutex))
|
|
21
|
+
#define CACHE_UNLOCK(c) pthread_mutex_unlock(&((c)->mutex))
|
|
22
|
+
#else
|
|
23
|
+
#define CACHE_LOCK(c) rb_mutex_lock((c)->mutex)
|
|
24
|
+
#define CACHE_UNLOCK(c) rb_mutex_unlock((c)->mutex)
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
// almost the Murmur hash algorithm
|
|
28
|
+
#define M 0x5bd1e995
|
|
29
|
+
|
|
30
|
+
typedef struct _slot {
|
|
31
|
+
struct _slot *next;
|
|
32
|
+
VALUE val;
|
|
33
|
+
uint64_t hash;
|
|
34
|
+
volatile uint32_t use_cnt;
|
|
35
|
+
uint8_t klen;
|
|
36
|
+
char key[CACHE_MAX_KEY];
|
|
37
|
+
} *Slot;
|
|
38
|
+
|
|
39
|
+
typedef struct _cache {
|
|
40
|
+
volatile Slot *slots;
|
|
41
|
+
volatile size_t cnt;
|
|
42
|
+
VALUE (*form)(const char *str, size_t len);
|
|
43
|
+
uint64_t size;
|
|
44
|
+
uint64_t mask;
|
|
45
|
+
VALUE (*intern)(struct _cache *c, const char *key, size_t len, const char **keyp);
|
|
46
|
+
volatile Slot reuse;
|
|
47
|
+
size_t rcnt;
|
|
48
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
|
49
|
+
pthread_mutex_t mutex;
|
|
50
|
+
#else
|
|
51
|
+
VALUE mutex;
|
|
52
|
+
#endif
|
|
53
|
+
uint8_t xrate;
|
|
54
|
+
bool mark;
|
|
55
|
+
} *Cache;
|
|
56
|
+
|
|
57
|
+
const rb_data_type_t ox_cache_type = {
|
|
58
|
+
"Ox/Cache",
|
|
59
|
+
{
|
|
60
|
+
ox_cache_mark,
|
|
61
|
+
ox_cache_free,
|
|
62
|
+
NULL,
|
|
63
|
+
},
|
|
64
|
+
0,
|
|
65
|
+
0,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
|
69
|
+
const uint8_t *end = key + len;
|
|
70
|
+
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
|
71
|
+
uint64_t h = (uint64_t)len;
|
|
72
|
+
uint64_t k;
|
|
73
|
+
|
|
74
|
+
while (key < endless) {
|
|
75
|
+
k = (uint64_t)*key++;
|
|
76
|
+
k |= (uint64_t)*key++ << 8;
|
|
77
|
+
k |= (uint64_t)*key++ << 16;
|
|
78
|
+
k |= (uint64_t)*key++ << 24;
|
|
79
|
+
|
|
80
|
+
k *= M;
|
|
81
|
+
k ^= k >> 24;
|
|
82
|
+
h *= M;
|
|
83
|
+
h ^= k * M;
|
|
84
|
+
}
|
|
85
|
+
if (1 < end - key) {
|
|
86
|
+
uint16_t k16 = (uint16_t)*key++;
|
|
87
|
+
|
|
88
|
+
k16 |= (uint16_t)*key++ << 8;
|
|
89
|
+
h ^= k16 << 8;
|
|
90
|
+
}
|
|
91
|
+
if (key < end) {
|
|
92
|
+
h ^= *key;
|
|
93
|
+
}
|
|
94
|
+
h *= M;
|
|
95
|
+
h ^= h >> 13;
|
|
96
|
+
h *= M;
|
|
97
|
+
h ^= h >> 15;
|
|
98
|
+
|
|
99
|
+
return h;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static void rehash(Cache c) {
|
|
103
|
+
uint64_t osize;
|
|
104
|
+
Slot *end;
|
|
105
|
+
Slot *sp;
|
|
106
|
+
|
|
107
|
+
osize = c->size;
|
|
108
|
+
c->size = osize * 4;
|
|
109
|
+
c->mask = c->size - 1;
|
|
110
|
+
c->slots = realloc((void *)c->slots, sizeof(Slot) * c->size);
|
|
111
|
+
memset((Slot *)c->slots + osize, 0, sizeof(Slot) * osize * 3);
|
|
112
|
+
end = (Slot *)c->slots + osize;
|
|
113
|
+
for (sp = (Slot *)c->slots; sp < end; sp++) {
|
|
114
|
+
Slot s = *sp;
|
|
115
|
+
Slot next = NULL;
|
|
116
|
+
|
|
117
|
+
*sp = NULL;
|
|
118
|
+
for (; NULL != s; s = next) {
|
|
119
|
+
uint64_t h = s->hash & c->mask;
|
|
120
|
+
Slot *bucket = (Slot *)c->slots + h;
|
|
121
|
+
|
|
122
|
+
next = s->next;
|
|
123
|
+
s->next = *bucket;
|
|
124
|
+
*bucket = s;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static VALUE ox_lockless_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
|
130
|
+
uint64_t h = hash_calc((const uint8_t *)key, len);
|
|
131
|
+
Slot *bucket = (Slot *)c->slots + (h & c->mask);
|
|
132
|
+
Slot b;
|
|
133
|
+
volatile VALUE rkey;
|
|
134
|
+
|
|
135
|
+
while (REUSE_MAX < c->rcnt) {
|
|
136
|
+
if (NULL != (b = c->reuse)) {
|
|
137
|
+
c->reuse = b->next;
|
|
138
|
+
free(b);
|
|
139
|
+
c->rcnt--;
|
|
140
|
+
} else {
|
|
141
|
+
// An accounting error occured somewhere so correct it.
|
|
142
|
+
c->rcnt = 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (b = *bucket; NULL != b; b = b->next) {
|
|
146
|
+
if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
|
|
147
|
+
b->use_cnt += 16;
|
|
148
|
+
if (NULL != keyp) {
|
|
149
|
+
*keyp = b->key;
|
|
150
|
+
}
|
|
151
|
+
return b->val;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
rkey = c->form(key, len);
|
|
155
|
+
if (NULL == (b = c->reuse)) {
|
|
156
|
+
b = calloc(1, sizeof(struct _slot));
|
|
157
|
+
} else {
|
|
158
|
+
c->reuse = b->next;
|
|
159
|
+
c->rcnt--;
|
|
160
|
+
}
|
|
161
|
+
b->hash = h;
|
|
162
|
+
memcpy(b->key, key, len);
|
|
163
|
+
b->klen = (uint8_t)len;
|
|
164
|
+
b->key[len] = '\0';
|
|
165
|
+
b->val = rkey;
|
|
166
|
+
b->use_cnt = 4;
|
|
167
|
+
b->next = *bucket;
|
|
168
|
+
*bucket = b;
|
|
169
|
+
c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
|
|
170
|
+
if (NULL != keyp) {
|
|
171
|
+
*keyp = b->key;
|
|
172
|
+
}
|
|
173
|
+
if (REHASH_LIMIT < c->cnt / c->size) {
|
|
174
|
+
rehash(c);
|
|
175
|
+
}
|
|
176
|
+
return rkey;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static VALUE ox_locking_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
|
180
|
+
uint64_t h;
|
|
181
|
+
Slot *bucket;
|
|
182
|
+
Slot b;
|
|
183
|
+
uint64_t old_size;
|
|
184
|
+
volatile VALUE rkey;
|
|
185
|
+
|
|
186
|
+
CACHE_LOCK(c);
|
|
187
|
+
while (REUSE_MAX < c->rcnt) {
|
|
188
|
+
if (NULL != (b = c->reuse)) {
|
|
189
|
+
c->reuse = b->next;
|
|
190
|
+
free(b);
|
|
191
|
+
c->rcnt--;
|
|
192
|
+
} else {
|
|
193
|
+
// An accounting error occured somewhere so correct it.
|
|
194
|
+
c->rcnt = 0;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
h = hash_calc((const uint8_t *)key, len);
|
|
198
|
+
bucket = (Slot *)c->slots + (h & c->mask);
|
|
199
|
+
for (b = *bucket; NULL != b; b = b->next) {
|
|
200
|
+
if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
|
|
201
|
+
b->use_cnt += 4;
|
|
202
|
+
if (NULL != keyp) {
|
|
203
|
+
*keyp = b->key;
|
|
204
|
+
}
|
|
205
|
+
CACHE_UNLOCK(c);
|
|
206
|
+
|
|
207
|
+
return b->val;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
old_size = c->size;
|
|
211
|
+
// The creation of a new value may trigger a GC which be a problem if the
|
|
212
|
+
// cache is locked so make sure it is unlocked for the key value creation.
|
|
213
|
+
if (NULL != (b = c->reuse)) {
|
|
214
|
+
c->reuse = b->next;
|
|
215
|
+
c->rcnt--;
|
|
216
|
+
}
|
|
217
|
+
CACHE_UNLOCK(c);
|
|
218
|
+
if (NULL == b) {
|
|
219
|
+
b = calloc(1, sizeof(struct _slot));
|
|
220
|
+
}
|
|
221
|
+
rkey = c->form(key, len);
|
|
222
|
+
b->hash = h;
|
|
223
|
+
memcpy(b->key, key, len);
|
|
224
|
+
b->klen = (uint8_t)len;
|
|
225
|
+
b->key[len] = '\0';
|
|
226
|
+
b->val = rkey;
|
|
227
|
+
b->use_cnt = 16;
|
|
228
|
+
|
|
229
|
+
// Lock again to add the new entry.
|
|
230
|
+
CACHE_LOCK(c);
|
|
231
|
+
if (old_size != c->size) {
|
|
232
|
+
h = hash_calc((const uint8_t *)key, len);
|
|
233
|
+
bucket = (Slot *)c->slots + (h & c->mask);
|
|
234
|
+
}
|
|
235
|
+
b->next = *bucket;
|
|
236
|
+
*bucket = b;
|
|
237
|
+
c->cnt++; // Don't worry about wrapping. Worse case is the entry is removed and recreated.
|
|
238
|
+
if (NULL != keyp) {
|
|
239
|
+
*keyp = b->key;
|
|
240
|
+
}
|
|
241
|
+
if (REHASH_LIMIT < c->cnt / c->size) {
|
|
242
|
+
rehash(c);
|
|
243
|
+
}
|
|
244
|
+
CACHE_UNLOCK(c);
|
|
245
|
+
|
|
246
|
+
return rkey;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking) {
|
|
250
|
+
Cache c = calloc(1, sizeof(struct _cache));
|
|
251
|
+
int shift = 0;
|
|
252
|
+
|
|
253
|
+
for (; REHASH_LIMIT < size; size /= 2, shift++) {
|
|
254
|
+
}
|
|
255
|
+
if (shift < MIN_SHIFT) {
|
|
256
|
+
shift = MIN_SHIFT;
|
|
257
|
+
}
|
|
258
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
|
259
|
+
pthread_mutex_init(&c->mutex, NULL);
|
|
260
|
+
#else
|
|
261
|
+
c->mutex = rb_mutex_new();
|
|
262
|
+
#endif
|
|
263
|
+
c->size = 1 << shift;
|
|
264
|
+
c->mask = c->size - 1;
|
|
265
|
+
c->slots = calloc(c->size, sizeof(Slot));
|
|
266
|
+
c->form = form;
|
|
267
|
+
c->xrate = 1; // low
|
|
268
|
+
c->mark = mark;
|
|
269
|
+
if (locking) {
|
|
270
|
+
c->intern = ox_locking_intern;
|
|
271
|
+
} else {
|
|
272
|
+
c->intern = ox_lockless_intern;
|
|
273
|
+
}
|
|
274
|
+
return c;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
void ox_cache_free(void *ptr) {
|
|
278
|
+
Cache c = (Cache)ptr;
|
|
279
|
+
uint64_t i;
|
|
280
|
+
|
|
281
|
+
for (i = 0; i < c->size; i++) {
|
|
282
|
+
Slot next;
|
|
283
|
+
Slot s;
|
|
284
|
+
|
|
285
|
+
for (s = c->slots[i]; NULL != s; s = next) {
|
|
286
|
+
next = s->next;
|
|
287
|
+
free(s);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
free((void *)c->slots);
|
|
291
|
+
free(c);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
void ox_cache_mark(void *ptr) {
|
|
295
|
+
Cache c = (Cache)ptr;
|
|
296
|
+
uint64_t i;
|
|
297
|
+
|
|
298
|
+
#if !HAVE_PTHREAD_MUTEX_INIT
|
|
299
|
+
rb_gc_mark(c->mutex);
|
|
300
|
+
#endif
|
|
301
|
+
if (0 == c->cnt) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
for (i = 0; i < c->size; i++) {
|
|
305
|
+
Slot s;
|
|
306
|
+
Slot prev = NULL;
|
|
307
|
+
Slot next;
|
|
308
|
+
|
|
309
|
+
for (s = c->slots[i]; NULL != s; s = next) {
|
|
310
|
+
next = s->next;
|
|
311
|
+
if (0 == s->use_cnt) {
|
|
312
|
+
if (NULL == prev) {
|
|
313
|
+
c->slots[i] = next;
|
|
314
|
+
} else {
|
|
315
|
+
prev->next = next;
|
|
316
|
+
}
|
|
317
|
+
c->cnt--;
|
|
318
|
+
s->next = c->reuse;
|
|
319
|
+
c->reuse = s;
|
|
320
|
+
c->rcnt++;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
switch (c->xrate) {
|
|
324
|
+
case 0: break;
|
|
325
|
+
case 2: s->use_cnt -= 2; break;
|
|
326
|
+
case 3: s->use_cnt /= 2; break;
|
|
327
|
+
default: s->use_cnt--; break;
|
|
328
|
+
}
|
|
329
|
+
if (c->mark) {
|
|
330
|
+
rb_gc_mark(s->val);
|
|
331
|
+
}
|
|
332
|
+
prev = s;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
VALUE
|
|
338
|
+
ox_cache_intern(Cache c, const char *key, size_t len, const char **keyp) {
|
|
339
|
+
if (CACHE_MAX_KEY <= len) {
|
|
340
|
+
if (NULL != keyp) {
|
|
341
|
+
volatile VALUE rkey = c->form(key, len);
|
|
342
|
+
|
|
343
|
+
if (SYMBOL_P(rkey)) {
|
|
344
|
+
*keyp = rb_id2name(rb_sym2id(rkey));
|
|
345
|
+
}
|
|
346
|
+
return rkey;
|
|
347
|
+
}
|
|
348
|
+
return c->form(key, len);
|
|
349
|
+
}
|
|
350
|
+
return c->intern(c, key, len, keyp);
|
|
351
|
+
}
|
data/ext/ox/cache.h
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright (c) 2021 Peter Ohler. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
|
3
|
+
|
|
4
|
+
#ifndef OX_CACHE_H
|
|
5
|
+
#define OX_CACHE_H
|
|
6
|
+
|
|
7
|
+
#include <ruby.h>
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
|
|
10
|
+
#define CACHE_MAX_KEY 35
|
|
11
|
+
|
|
12
|
+
struct _cache;
|
|
13
|
+
|
|
14
|
+
extern const rb_data_type_t ox_cache_type;
|
|
15
|
+
|
|
16
|
+
extern struct _cache *ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
|
|
17
|
+
extern void ox_cache_free(void *ptr);
|
|
18
|
+
extern void ox_cache_mark(void *ptr);
|
|
19
|
+
extern VALUE ox_cache_intern(struct _cache *c, const char *key, size_t len, const char **keyp);
|
|
20
|
+
|
|
21
|
+
#endif /* OX_CACHE_H */
|
data/ext/ox/cache8.c
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* cache8.h
|
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "cache8.h"
|
|
7
|
+
|
|
8
|
+
#include <errno.h>
|
|
9
|
+
#include <stdarg.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
|
|
14
|
+
#include "ruby.h"
|
|
15
|
+
|
|
16
|
+
#define BITS 4
|
|
17
|
+
#define MASK 0x000000000000000FULL
|
|
18
|
+
#define SLOT_CNT 16
|
|
19
|
+
#define DEPTH 16
|
|
20
|
+
|
|
21
|
+
typedef union {
|
|
22
|
+
struct _cache8 *child;
|
|
23
|
+
slot_t value;
|
|
24
|
+
} Bucket;
|
|
25
|
+
|
|
26
|
+
struct _cache8 {
|
|
27
|
+
Bucket buckets[SLOT_CNT];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
static void cache8_delete(Cache8 cache, int depth);
|
|
31
|
+
// static void slot_print(Cache8 cache, sid_t key, unsigned int depth);
|
|
32
|
+
|
|
33
|
+
void ox_cache8_new(Cache8 *cache) {
|
|
34
|
+
Bucket *b;
|
|
35
|
+
int i;
|
|
36
|
+
|
|
37
|
+
*cache = ALLOC(struct _cache8);
|
|
38
|
+
for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) {
|
|
39
|
+
b->value = 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void ox_cache8_delete(Cache8 cache) {
|
|
44
|
+
cache8_delete(cache, 0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static void cache8_delete(Cache8 cache, int depth) {
|
|
48
|
+
Bucket *b;
|
|
49
|
+
unsigned int i;
|
|
50
|
+
|
|
51
|
+
for (i = 0, b = cache->buckets; i < SLOT_CNT; i++, b++) {
|
|
52
|
+
if (0 != b->child) {
|
|
53
|
+
if (DEPTH - 1 != depth) {
|
|
54
|
+
cache8_delete(b->child, depth + 1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
xfree(cache);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
slot_t ox_cache8_get(Cache8 cache, sid_t key, slot_t **slot) {
|
|
62
|
+
Bucket *b;
|
|
63
|
+
int i;
|
|
64
|
+
sid_t k8 = (sid_t)key;
|
|
65
|
+
sid_t k;
|
|
66
|
+
|
|
67
|
+
for (i = 64 - BITS; 0 < i; i -= BITS) {
|
|
68
|
+
k = (k8 >> i) & MASK;
|
|
69
|
+
b = cache->buckets + k;
|
|
70
|
+
if (0 == b->child) {
|
|
71
|
+
ox_cache8_new(&b->child);
|
|
72
|
+
}
|
|
73
|
+
cache = b->child;
|
|
74
|
+
}
|
|
75
|
+
*slot = &(cache->buckets + (k8 & MASK))->value;
|
|
76
|
+
|
|
77
|
+
return **slot;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#if 0
|
|
81
|
+
void
|
|
82
|
+
ox_cache8_print(Cache8 cache) {
|
|
83
|
+
//printf("-------------------------------------------\n");
|
|
84
|
+
slot_print(cache, 0, 0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static void
|
|
88
|
+
slot_print(Cache8 c, sid_t key, unsigned int depth) {
|
|
89
|
+
Bucket *b;
|
|
90
|
+
unsigned int i;
|
|
91
|
+
sid_t k8 = (sid_t)key;
|
|
92
|
+
sid_t k;
|
|
93
|
+
|
|
94
|
+
for (i = 0, b = c->buckets; i < SLOT_CNT; i++, b++) {
|
|
95
|
+
if (0 != b->child) {
|
|
96
|
+
k = (k8 << BITS) | i;
|
|
97
|
+
//printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i);
|
|
98
|
+
if (DEPTH - 1 == depth) {
|
|
99
|
+
printf("0x%016llx: %4llu\n", (unsigned long long)k, (unsigned long long)b->value);
|
|
100
|
+
} else {
|
|
101
|
+
slot_print(b->child, k, depth + 1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
#endif
|
data/ext/ox/cache8.h
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* cache8.h
|
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef OX_CACHE8_H
|
|
7
|
+
#define OX_CACHE8_H
|
|
8
|
+
|
|
9
|
+
#include "ruby.h"
|
|
10
|
+
#include "stdint.h"
|
|
11
|
+
|
|
12
|
+
typedef struct _cache8 *Cache8;
|
|
13
|
+
typedef uint64_t slot_t;
|
|
14
|
+
typedef uint64_t sid_t;
|
|
15
|
+
|
|
16
|
+
extern void ox_cache8_new(Cache8 *cache);
|
|
17
|
+
extern void ox_cache8_delete(Cache8 cache);
|
|
18
|
+
|
|
19
|
+
extern slot_t ox_cache8_get(Cache8 cache, sid_t key, slot_t **slot);
|
|
20
|
+
|
|
21
|
+
// extern void ox_cache8_print(Cache8 cache);
|
|
22
|
+
|
|
23
|
+
#endif /* OX_CACHE8_H */
|