1 /* Copyright(C) 2004 Brazil
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 2.1 of the License, or (at your option) any later version.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17 #include "senna_in.h"
18 #include <string.h>
19 #include <limits.h>
20 #include "ctx.h"
21 #include "set.h"
22
23 #define INITIAL_N_ENTRIES 256U
24 #define INITIAL_INDEX_SIZE 256U
25
26 #define GARBAGE ((entry *) 1)
27
28 #define STEP(x) (((x) >> 2) | 0x1010101)
29
30 typedef struct _sen_set_element entry;
31 typedef struct _sen_set_element_str entry_str;
32
33 #define SEN_SET_STRHASH(e) (((entry_str *)(e))->key)
34
35 inline static entry *
entry_new(sen_set * set)36 entry_new(sen_set *set)
37 {
38 entry *e;
39 if (set->garbages) {
40 e = set->garbages;
41 set->garbages = *((entry **)e);
42 memset(e, 0, set->entry_size);
43 } else {
44 SEN_ARRAY_NEXT(&set->a, e);
45 }
46 return e;
47 }
48
49 sen_rc
sen_set_init(sen_ctx * ctx,sen_set * set,uint32_t key_size,uint32_t value_size,uint32_t init_size)50 sen_set_init(sen_ctx *ctx, sen_set *set,
51 uint32_t key_size, uint32_t value_size, uint32_t init_size)
52 {
53 uint32_t entry_size, n, mod;
54 for (n = INITIAL_INDEX_SIZE; n < init_size; n *= 2);
55 switch (key_size) {
56 case 0 :
57 entry_size = (intptr_t)(&((entry_str *)0)->dummy) + value_size;
58 break;
59 case sizeof(uint32_t) :
60 entry_size = (intptr_t)(&((entry *)0)->dummy) + value_size;
61 break;
62 default :
63 entry_size = (intptr_t)(&((entry *)0)->dummy) + key_size + value_size;
64 break;
65 }
66 if ((mod = entry_size % sizeof(intptr_t))) {
67 entry_size += sizeof(intptr_t) - mod;
68 }
69 memset(set, 0, sizeof(sen_set));
70 set->ctx = ctx;
71 set->key_size = key_size;
72 set->value_size = value_size;
73 set->entry_size = entry_size;
74 set->max_offset = n - 1;
75
76 sen_array_init(&set->a, ctx, entry_size, SEN_ARRAY_CLEAR);
77
78 return (set->index = SEN_CALLOC(n * sizeof(entry *))) ? sen_success : sen_memory_exhausted;
79 }
80
81 sen_rc
sen_set_fin(sen_set * set)82 sen_set_fin(sen_set * set)
83 {
84 uint32_t i;
85 sen_ctx *ctx;
86 if (!set || !set->index) { return sen_invalid_argument; }
87 ctx = set->ctx;
88 if (!set->key_size) {
89 entry *e, **sp;
90 for (i = set->max_offset + 1, sp = set->index; i; i--, sp++) {
91 e = *sp;
92 if (!e || (e == GARBAGE)) { continue; }
93 if (SEN_SET_STRKEY(e)) { SEN_FREE(SEN_SET_STRKEY(e)); }
94 }
95 }
96 /*
97 for (i = 0; i <= SEN_SET_MAX_CHUNK; i++) {
98 if (set->chunks[i]) { SEN_FREE(set->chunks[i]); }
99 }
100 */
101 sen_array_fin(&set->a);
102 SEN_FREE(set->index);
103 return sen_success;
104 }
105
106 /* for compatibility */
107 sen_set *
sen_set_open(uint32_t key_size,uint32_t value_size,uint32_t init_size)108 sen_set_open(uint32_t key_size, uint32_t value_size, uint32_t init_size)
109 {
110 sen_set *set;
111 sen_ctx *ctx = &sen_gctx; /* todo : replace it with the local ctx */
112 if (!(set = SEN_MALLOC(sizeof(sen_set)))) { return NULL; }
113 if (sen_set_init(ctx, set, key_size, value_size, init_size)) {
114 SEN_FREE(set);
115 return NULL;
116 }
117 return set;
118 }
119
120 sen_rc
sen_set_close(sen_set * set)121 sen_set_close(sen_set *set)
122 {
123 sen_rc rc;
124 if (set) {
125 sen_ctx *ctx = set->ctx;
126 rc = sen_set_fin(set);
127 SEN_FREE(set);
128 } else {
129 rc = sen_invalid_argument;
130 }
131 return rc;
132 }
133
134 sen_rc
sen_set_reset(sen_set * set,uint32_t ne)135 sen_set_reset(sen_set * set, uint32_t ne)
136 {
137 uint32_t i, j, m, n, s;
138 entry **index, *e, **sp, **dp;
139 sen_ctx *ctx = set->ctx;
140 if (!ne) { ne = set->n_entries * 2; }
141 if (ne > INT_MAX) { return sen_memory_exhausted; }
142 for (n = INITIAL_INDEX_SIZE; n <= ne; n *= 2);
143 if (!(index = SEN_CALLOC(n * sizeof(entry *)))) { return sen_memory_exhausted; }
144 m = n - 1;
145 if (set->index) {
146 if (set->key_size) {
147 for (j = set->max_offset + 1, sp = set->index; j; j--, sp++) {
148 e = *sp;
149 if (!e || (e == GARBAGE)) { continue; }
150 for (i = e->key, s = STEP(i); ; i += s) {
151 dp = index + (i & m);
152 if (!*dp) { break; }
153 }
154 *dp = e;
155 }
156 } else {
157 for (j = set->max_offset + 1, sp = set->index; j; j--, sp++) {
158 e = *sp;
159 if (!e || (e == GARBAGE)) { continue; }
160 for (i = SEN_SET_STRHASH(e), s = STEP(i); ; i += s) {
161 dp = index + (i & m);
162 if (!*dp) { break; }
163 }
164 *dp = e;
165 }
166 }
167 }
168 {
169 entry **i0 = set->index;
170 set->index = index;
171 set->max_offset = m;
172 set->n_garbages = 0;
173 if (i0) { SEN_FREE(i0); }
174 }
175 return sen_success;
176 }
177
178 sen_rc
sen_set_info(sen_set * set,unsigned * key_size,unsigned * value_size,unsigned * n_entries)179 sen_set_info(sen_set *set, unsigned *key_size, unsigned *value_size,
180 unsigned *n_entries)
181 {
182 if (!set) { return sen_invalid_argument; }
183 if (key_size) { *key_size = set->key_size; }
184 if (value_size) { *value_size = set->value_size; }
185 if (n_entries) { *n_entries = set->n_entries; }
186 return sen_success;
187 }
188
189 inline static uint32_t
str_hash(const unsigned char * p)190 str_hash(const unsigned char *p)
191 {
192 uint32_t r;
193 for (r = 0; *p; p++) { r = (r * 1021) + *p; }
194 return r;
195 }
196
197 inline static uint32_t
bin_hash(const uint8_t * p,uint32_t length)198 bin_hash(const uint8_t *p, uint32_t length)
199 {
200 uint32_t r;
201 for (r = 0; length--; p++) { r = (r * 1021) + *p; }
202 return r;
203 }
204
205 sen_set_eh *
sen_set_int_at(sen_set * set,const uint32_t * key,void ** value)206 sen_set_int_at(sen_set *set, const uint32_t *key, void **value)
207 {
208 entry *e, **ep, **index = set->index;
209 uint32_t h = *key, i, m = set->max_offset, s = STEP(h);
210 if (index) {
211 for (i = h; ep = index + (i & m), (e = *ep); i += s) {
212 if (e == GARBAGE) { continue; }
213 if (e->key == h) {
214 if (value) { *value = e->dummy; }
215 return ep;
216 }
217 }
218 }
219 return NULL;
220 }
221
222 sen_set_eh *
sen_set_str_at(sen_set * set,const char * key,void ** value)223 sen_set_str_at(sen_set *set, const char *key, void **value)
224 {
225 entry *e, **ep, **index = set->index;
226 uint32_t h = str_hash((unsigned char *)key), i, m = set->max_offset, s = STEP(h);
227 if (index) {
228 for (i = h; ep = index + (i & m), (e = *ep); i += s) {
229 if (e == GARBAGE) { continue; }
230 if (SEN_SET_STRHASH(e) == h && !strcmp(key, SEN_SET_STRKEY(e))) {
231 if (value) { *value = SEN_SET_STRVAL(e); }
232 return (sen_set_eh *) ep;
233 }
234 }
235 }
236 return NULL;
237 }
238
239 sen_set_eh *
sen_set_bin_at(sen_set * set,const void * key,void ** value)240 sen_set_bin_at(sen_set *set, const void *key, void **value)
241 {
242 entry *e, **ep, **index = set->index;
243 uint32_t h = bin_hash(key, set->key_size), i, m = set->max_offset, s = STEP(h);
244 if (index) {
245 for (i = h; ep = index + (i & m), (e = *ep); i += s) {
246 if (e == GARBAGE) { continue; }
247 if (e->key == h && !memcmp(key, e->dummy, set->key_size)) {
248 if (value) { *value = SEN_SET_BINVAL(e, set); }
249 return ep;
250 }
251 }
252 }
253 return NULL;
254 }
255
256 sen_set_eh *
sen_set_at(sen_set * set,const void * key,void ** value)257 sen_set_at(sen_set *set, const void *key, void **value)
258 {
259 if (set->arrayp) {
260 if (sen_set_reset(set, 0)) { return NULL; }
261 // set->curr_entry = 0;
262 set->arrayp = 0;
263 }
264 switch (set->key_size) {
265 case 0 :
266 return sen_set_str_at(set, key, value);
267 case sizeof(uint32_t) :
268 return sen_set_int_at(set, key, value);
269 default :
270 return sen_set_bin_at(set, key, value);
271 }
272 }
273
274 inline static sen_set_eh *
sen_set_int_get(sen_set * set,const uint32_t * key,void ** value)275 sen_set_int_get(sen_set *set, const uint32_t *key, void **value)
276 {
277 static int _ncalls = 0, _ncolls = 0;
278 entry *e, **ep, **np = NULL, **index = set->index;
279 uint32_t h = *key, i, m = set->max_offset, s = STEP(h);
280 _ncalls++;
281 if (!index) { return NULL; }
282 for (i = h; ep = index + (i & m), e = *ep; i += s) {
283 if (e == GARBAGE) {
284 if (!np) { np = ep; }
285 } else {
286 if (e->key == h) { goto exit; }
287 }
288 if (!(++_ncolls % 1000000) && (_ncolls > _ncalls)) {
289 if (_ncolls < 0 || _ncalls < 0) {
290 _ncolls = 0; _ncalls = 0;
291 } else {
292 SEN_LOG(sen_log_notice, "total:%d collisions:%d nentries:%d maxoffset:%d",
293 _ncalls, _ncolls, set->n_entries, set->max_offset);
294 }
295 }
296 }
297 if (np) {
298 set->n_garbages--;
299 ep = np;
300 }
301 if (!(e = entry_new(set))) { return NULL; }
302 e->key = h;
303 *ep = e;
304 set->n_entries++;
305 exit :
306 if (value) { *value = e->dummy; }
307 return ep;
308 }
309
310 inline static sen_set_eh *
sen_set_str_get(sen_set * set,const char * key,void ** value)311 sen_set_str_get(sen_set *set, const char *key, void **value)
312 {
313 sen_ctx *ctx = set->ctx;
314 entry *e, **ep, **np = NULL, **index = set->index;
315 uint32_t h = str_hash((unsigned char *)key), i, m = set->max_offset, s = STEP(h);
316 if (!index) { return NULL; }
317 for (i = h; ep = index + (i & m), e = *ep; i += s) {
318 if (e == GARBAGE) {
319 if (!np) { np = ep; }
320 } else {
321 if (SEN_SET_STRHASH(e) == h && !strcmp(key, SEN_SET_STRKEY(e))) { goto exit; }
322 }
323 }
324 {
325 char *keybuf = SEN_STRDUP(key);
326 if (!keybuf) { return NULL; }
327 if (!(e = entry_new(set))) {
328 SEN_FREE(keybuf);
329 return NULL;
330 }
331 SEN_SET_STRHASH(e) = h;
332 SEN_SET_STRKEY(e) = keybuf;
333 if (np) {
334 set->n_garbages--;
335 ep = np;
336 }
337 *ep = e;
338 set->n_entries++;
339 }
340 exit :
341 if (value) { *value = SEN_SET_STRVAL(e); }
342 return ep;
343 }
344
345 inline static sen_set_eh *
sen_set_bin_get(sen_set * set,const void * key,void ** value)346 sen_set_bin_get(sen_set *set, const void *key, void **value)
347 {
348 entry *e, **ep, **np = NULL, **index = set->index;
349 uint32_t h = bin_hash(key, set->key_size), i, m = set->max_offset, s = STEP(h);
350 if (!index) { return NULL; }
351 for (i = h; ep = index + (i & m), e = *ep; i += s) {
352 if (e == GARBAGE) {
353 if (!np) { np = ep; }
354 } else {
355 if (e->key == h && !memcmp(key, e->dummy, set->key_size)) {
356 goto exit;
357 }
358 }
359 }
360 if (np) {
361 set->n_garbages--;
362 ep = np;
363 }
364 if (!(e = entry_new(set))) { return NULL; }
365 e->key = h;
366 memcpy(e->dummy, key, set->key_size);
367 *ep = e;
368 set->n_entries++;
369 exit :
370 if (value) { *value = &e->dummy[set->key_size]; }
371 return ep;
372 }
373
374 sen_set_eh *
sen_set_get(sen_set * set,const void * key,void ** value)375 sen_set_get(sen_set *set, const void *key, void **value)
376 {
377 if (!set) { return NULL; }
378 if (set->arrayp) {
379 if (sen_set_reset(set, 0)) { return NULL; }
380 // set->curr_entry = 0;
381 set->arrayp = 0;
382 } else if ((set->n_entries + set->n_garbages) * 2 > set->max_offset) {
383 sen_set_reset(set, 0);
384 }
385 switch (set->key_size) {
386 case 0 :
387 return sen_set_str_get(set, key, value);
388 case sizeof(uint32_t) :
389 return sen_set_int_get(set, key, value);
390 default :
391 return sen_set_bin_get(set, key, value);
392 }
393 }
394
395 sen_rc
sen_set_del(sen_set * set,sen_set_eh * ep)396 sen_set_del(sen_set *set, sen_set_eh *ep)
397 {
398 entry *e;
399 sen_ctx *ctx = set->ctx;
400 if (!set || !ep || !*ep) { return sen_invalid_argument; }
401 e = *ep;
402 *ep = GARBAGE;
403 if (!set->key_size) { SEN_FREE(SEN_SET_STRKEY(e)); }
404 *((entry **)e) = set->garbages;
405 set->garbages = e;
406 set->n_entries--;
407 set->n_garbages++;
408 return sen_success;
409 }
410
411 sen_set_cursor *
sen_set_cursor_open(sen_set * set)412 sen_set_cursor_open(sen_set *set)
413 {
414 sen_set_cursor *c;
415 sen_ctx *ctx = set->ctx;
416 if (!set || !set->index) { return NULL; }
417 if (!(c = SEN_MALLOC(sizeof(sen_set_cursor)))) { return NULL; }
418 c->set = set;
419 c->index = set->index;
420 c->curr = set->index;
421 c->rest = set->max_offset + 1;
422 return c;
423 }
424
425 sen_set_eh *
sen_set_cursor_next(sen_set_cursor * c,void ** key,void ** value)426 sen_set_cursor_next(sen_set_cursor *c, void **key, void **value)
427 {
428 uint32_t i;
429 entry *e, **ep;
430 if (!c || !c->rest) { return NULL; }
431 if (c->index != c->set->index) {
432 SEN_LOG(sen_log_alert, "sen_reset invoked during sen_set_cursor is opened!");
433 return NULL;
434 }
435 for (i = c->rest, ep = c->curr;;i--, ep++) {
436 if (!i) {
437 c->rest = 0;
438 return NULL;
439 }
440 e = *ep;
441 if (e && e != GARBAGE) { break; }
442 }
443 switch (c->set->key_size) {
444 case 0 :
445 if (key) { *key = SEN_SET_STRKEY(e); }
446 if (value) { *value = SEN_SET_STRVAL(e); }
447 break;
448 case sizeof(uint32_t) :
449 if (key) { *key = SEN_SET_INTKEY(e); }
450 if (value) { *value = SEN_SET_INTVAL(e); }
451 break;
452 default :
453 if (key) { *key = SEN_SET_BINKEY(e); }
454 if (value) { *value = SEN_SET_BINVAL(e, c->set); }
455 break;
456 }
457 c->curr = ep + 1;
458 c->rest = i - 1;
459 return ep;
460 }
461
462 sen_rc
sen_set_cursor_close(sen_set_cursor * cursor)463 sen_set_cursor_close(sen_set_cursor *cursor)
464 {
465 sen_ctx *ctx = cursor->set->ctx;
466 SEN_FREE(cursor);
467 return sen_success;
468 }
469
470 inline static void
swap(entry ** a,entry ** b)471 swap(entry **a, entry **b)
472 {
473 entry *c = *a;
474 *a = *b;
475 *b = c;
476 }
477
478 #define INT_OFFSET_VAL(x) (((int32_t *)(x))[offset] * dir)
479
480 inline static entry **
pack_int(sen_set * set,entry ** res,int offset,int dir)481 pack_int(sen_set *set, entry **res, int offset, int dir)
482 {
483 uint32_t i, n, m = set->max_offset;
484 int32_t ck;
485 entry **head, **tail, *e, *c;
486 for (i = m >> 1;; i = (i + 1) & m) {
487 if ((c = set->index[i]) && (c != GARBAGE)) { break; }
488 }
489 head = res;
490 n = set->n_entries - 1;
491 tail = res + n;
492 ck = INT_OFFSET_VAL(c);
493 while (n--) {
494 for (;;) {
495 i = (i + 1) & m;
496 if ((e = set->index[i]) && (e != GARBAGE)) { break; }
497 }
498 if (INT_OFFSET_VAL(e) < ck) {
499 *head++ = e;
500 } else {
501 *tail-- = e;
502 }
503 }
504 *head = c;
505 return set->n_entries > 2 ? head : NULL;
506 }
507
508 inline static entry **
part_int(entry ** b,entry ** e,int offset,int dir)509 part_int(entry **b, entry **e, int offset, int dir)
510 {
511 int32_t ck;
512 intptr_t d = e - b;
513 entry **c;
514 if (INT_OFFSET_VAL(*b) > INT_OFFSET_VAL(*e)) { swap(b, e); }
515 if (d < 2) { return NULL; }
516 c = b + (d >> 1);
517 if (INT_OFFSET_VAL(*b) > INT_OFFSET_VAL(*c)) {
518 swap(b, c);
519 } else {
520 if (INT_OFFSET_VAL(*c) > INT_OFFSET_VAL(*e)) { swap(c, e); }
521 }
522 if (d < 3) { return NULL; }
523 b++;
524 ck = INT_OFFSET_VAL(*c);
525 swap(b, c);
526 c = b;
527 for (;;) {
528 while (INT_OFFSET_VAL(*++b) < ck) ;
529 while (INT_OFFSET_VAL(*--e) > ck) ;
530 if (b >= e) { break; }
531 swap(b, e);
532 }
533 swap(c, e);
534 return e;
535 }
536
537 static void
_sort_int(entry ** head,entry ** tail,int limit,int offset,int dir)538 _sort_int(entry **head, entry **tail, int limit, int offset, int dir)
539 {
540 intptr_t rest;
541 entry **c;
542 if (head < tail && (c = part_int(head, tail, offset, dir))) {
543 rest = limit - 1 - (c - head);
544 _sort_int(head, c - 1, limit, offset, dir);
545 if (rest > 0) { _sort_int(c + 1, tail, (int)rest, offset, dir); }
546 }
547 }
548
549 inline static void
sort_int(sen_set * set,entry ** res,int limit,int offset,int dir)550 sort_int(sen_set *set, entry **res, int limit, int offset, int dir)
551 {
552 entry **c = pack_int(set, res, offset, dir);
553 if (c) {
554 intptr_t rest = limit - 1 - (c - res);
555 _sort_int(res, c - 1, limit, offset, dir);
556 if (rest > 0 ) { _sort_int(c + 1, res + set->n_entries - 1, (int)rest, offset, dir); }
557 }
558 }
559
560 inline static entry **
pack_func(sen_set * set,entry ** res,int (* func)(sen_set *,entry **,sen_set *,entry **,void *),void * arg,int dir)561 pack_func(sen_set *set, entry **res,
562 int(*func)(sen_set *, entry **, sen_set *, entry **, void *),
563 void *arg, int dir)
564 {
565 uint32_t i, n, m = set->max_offset;
566 entry **head, **tail, *e, *c;
567 for (i = m >> 1;; i = (i + 1) & m) {
568 if ((c = set->index[i]) && (c != GARBAGE)) { break; }
569 }
570 head = res;
571 n = set->n_entries - 1;
572 tail = res + n;
573 while (n--) {
574 for (;;) {
575 i = (i + 1) & m;
576 if ((e = set->index[i]) && (e != GARBAGE)) { break; }
577 }
578 if (func(set, &e, set, &c, arg) * dir < 0) {
579 *head++ = e;
580 } else {
581 *tail-- = e;
582 }
583 }
584 *head = c;
585 return set->n_entries > 2 ? head : NULL;
586 }
587
588 inline static entry **
part_func(entry ** b,entry ** e,int (* func)(sen_set *,entry **,sen_set *,entry **,void *),void * arg,sen_set * set,int dir)589 part_func(entry **b, entry **e,
590 int(*func)(sen_set *, entry **, sen_set *, entry **, void *),
591 void *arg, sen_set *set, int dir)
592 {
593 intptr_t d = e - b;
594 entry **c;
595 if (func(set, b, set, e, arg) * dir > 0) { swap(b, e); }
596 if (d < 2) { return NULL; }
597 c = b + (d >> 1);
598 if (func(set, b, set, c, arg) * dir > 0) {
599 swap(b, c);
600 } else {
601 if (func(set, c, set, e, arg) * dir > 0) { swap(c, e); }
602 }
603 if (d < 3) { return NULL; }
604 b++;
605 swap(b, c);
606 c = b;
607 for (;;) {
608 while (func(set, ++b, set, c, arg) * dir < 0) ;
609 while (func(set, --e, set, c, arg) * dir > 0) ;
610 if (b >= e) { break; }
611 swap(b, e);
612 }
613 swap(c, e);
614 return e;
615 }
616
617 static void
_sort_func(entry ** head,entry ** tail,int limit,int (* func)(sen_set *,entry **,sen_set *,entry **,void *),void * arg,sen_set * set,int dir)618 _sort_func(entry **head, entry **tail, int limit,
619 int(*func)(sen_set *, entry **, sen_set *, entry **, void *),
620 void *arg, sen_set *set, int dir)
621 {
622 entry **c;
623 if (head < tail && (c = part_func(head, tail, func, arg, set, dir))) {
624 intptr_t rest = limit - 1 - (c - head);
625 _sort_func(head, c - 1, limit, func, arg, set, dir);
626 if (rest > 0) { _sort_func(c + 1, tail, (int)rest, func, arg, set, dir); }
627 }
628 }
629
630 inline static void
sort_func(sen_set * set,entry ** res,int limit,int (* func)(sen_set *,entry **,sen_set *,entry **,void *),void * arg,int dir)631 sort_func(sen_set *set, entry **res, int limit,
632 int(*func)(sen_set *, entry **, sen_set *, entry **, void *), void *arg, int dir)
633 {
634 entry **c = pack_func(set, res, func, arg, dir);
635 if (c) {
636 intptr_t rest = limit - 1 - (c - res);
637 _sort_func(res, c - 1, limit, func, arg, set, dir);
638 if (rest > 0 ) {
639 _sort_func(c + 1, res + set->n_entries - 1, (int)rest, func, arg, set, dir);
640 }
641 }
642 }
643
644 inline static int
func_str(sen_set * sa,entry ** a,sen_set * sb,entry ** b,void * arg)645 func_str(sen_set *sa, entry **a, sen_set *sb, entry **b, void *arg)
646 {
647 return strcmp(SEN_SET_STRKEY(*a), SEN_SET_STRKEY(*b));
648 }
649
650 inline static int
func_bin(sen_set * sa,entry ** a,sen_set * sb,entry ** b,void * arg)651 func_bin(sen_set *sa, entry **a, sen_set *sb, entry **b, void *arg)
652 {
653 return memcmp(SEN_SET_BINKEY(*a), SEN_SET_BINKEY(*b), (uintptr_t)arg);
654 }
655
656 sen_set_eh *
sen_set_sort(sen_set * set,int limit,sen_set_sort_optarg * optarg)657 sen_set_sort(sen_set *set, int limit, sen_set_sort_optarg *optarg)
658 {
659 sen_ctx *ctx = set->ctx;
660 entry **res;
661 int dir = 1;
662 if (!set || !set->index) {
663 SEN_LOG(sen_log_warning, "sen_set_sort: invalid argument !");
664 return NULL;
665 }
666 if (!set->n_entries) { return NULL; }
667 if (!(res = SEN_MALLOC(sizeof(entry *) * set->n_entries))) {
668 SEN_LOG(sen_log_alert, "allocation of entries failed on sen_set_sort !");
669 return NULL;
670 }
671 if (limit <= 0) {
672 limit += set->n_entries;
673 if (limit <= 0) {
674 SEN_LOG(sen_log_alert, "limit is too small in sen_set_sort !");
675 return NULL;
676 }
677 }
678 if (limit > set->n_entries) { limit = set->n_entries; }
679 set->limit = limit;
680 if (optarg) {
681 dir = (optarg->mode == sen_sort_ascending) ? 1 : -1;
682 if (optarg->compar) {
683 sort_func(set, res, limit, optarg->compar, optarg->compar_arg, dir);
684 goto exit;
685 } else if (optarg->compar_arg) {
686 sort_int(set, res, limit, ((intptr_t)optarg->compar_arg) / sizeof(int32_t), dir);
687 goto exit;
688 }
689 }
690 switch (set->key_size) {
691 case 0 :
692 sort_func(set, res, limit, func_str, NULL, dir);
693 break;
694 case sizeof(uint32_t) :
695 sort_int(set, res, limit, 0, dir);
696 break;
697 default :
698 sort_func(set, res, limit, func_bin, (void *)(intptr_t)set->key_size, dir);
699 break;
700 }
701 exit :
702 return res;
703 }
704
705 sen_rc
sen_set_element_info(sen_set * set,const sen_set_eh * e,void ** key,void ** value)706 sen_set_element_info(sen_set *set, const sen_set_eh *e, void **key, void **value)
707 {
708 if (!set || !e) { return sen_invalid_argument; }
709 switch (set->key_size) {
710 case 0 :
711 if (key) { *key = SEN_SET_STRKEY(*e); }
712 if (value) { *value = SEN_SET_STRVAL(*e); }
713 break;
714 case sizeof(uint32_t) :
715 if (key) { *key = SEN_SET_INTKEY(*e); }
716 if (value) { *value = SEN_SET_INTVAL(*e); }
717 break;
718 default :
719 if (key) { *key = SEN_SET_BINKEY(*e); }
720 if (value) { *value = SEN_SET_BINVAL(*e, set); }
721 break;
722 }
723 return sen_success;
724 }
725
726 sen_set *
sen_set_union(sen_set * a,sen_set * b)727 sen_set_union(sen_set *a, sen_set *b)
728 {
729 void *key, *va, *vb;
730 entry *e, **ep;
731 uint32_t i, key_size = a->key_size, value_size = a->value_size;
732 if (key_size != b->key_size || value_size != b->value_size) { return NULL; }
733 for (i = b->n_entries, ep = b->index; i; ep++) {
734 if ((e = *ep) && e != GARBAGE) {
735 switch (key_size) {
736 case 0 :
737 key = SEN_SET_STRKEY(e);
738 vb = SEN_SET_STRVAL(e);
739 break;
740 case sizeof(uint32_t) :
741 key = SEN_SET_INTKEY(e);
742 vb = SEN_SET_INTVAL(e);
743 break;
744 default :
745 key = SEN_SET_BINKEY(e);
746 vb = &e->dummy[key_size];
747 break;
748 }
749 if (sen_set_at(a, key, &va)) {
750 /* do copy of merge? */
751 } else {
752 if (sen_set_get(a, key, &va)) { memcpy(va, vb, value_size); }
753 }
754 i--;
755 }
756 }
757 return a;
758 }
759
760 sen_set *
sen_set_subtract(sen_set * a,sen_set * b)761 sen_set_subtract(sen_set *a, sen_set *b)
762 {
763 void *key;
764 entry *e, **ep, **dp;
765 uint32_t i, key_size = a->key_size;
766 if (key_size != b->key_size) { return NULL; }
767 for (i = b->n_entries, ep = b->index; i; ep++) {
768 if ((e = *ep) && e != GARBAGE) {
769 switch (key_size) {
770 case 0 :
771 key = SEN_SET_STRKEY(e);
772 break;
773 case sizeof(uint32_t) :
774 key = SEN_SET_INTKEY(e);
775 break;
776 default :
777 key = SEN_SET_BINKEY(e);
778 break;
779 }
780 if ((dp = sen_set_at(a, key, NULL))) { sen_set_del(a, dp); }
781 i--;
782 }
783 }
784 return a;
785 }
786
787 sen_set *
sen_set_intersect(sen_set * a,sen_set * b)788 sen_set_intersect(sen_set *a, sen_set *b)
789 {
790 void *key;
791 entry *e, **ep;
792 uint32_t i, key_size = a->key_size;
793 if (key_size != b->key_size) { return NULL; }
794 for (i = a->n_entries, ep = a->index; i; ep++) {
795 if ((e = *ep) && e != GARBAGE) {
796 switch (key_size) {
797 case 0 :
798 key = SEN_SET_STRKEY(e);
799 break;
800 case sizeof(uint32_t) :
801 key = SEN_SET_INTKEY(e);
802 break;
803 default :
804 key = SEN_SET_BINKEY(e);
805 break;
806 }
807 if (!sen_set_at(b, key, NULL)) { sen_set_del(a, ep); }
808 i--;
809 }
810 }
811 return a;
812 }
813
814 int
sen_set_difference(sen_set * a,sen_set * b)815 sen_set_difference(sen_set *a, sen_set *b)
816 {
817 void *key;
818 entry *e, **ep, **dp;
819 uint32_t count = 0, i, key_size = a->key_size;
820 if (key_size != b->key_size) { return -1; }
821 for (i = a->n_entries, ep = a->index; i; ep++) {
822 if ((e = *ep) && e != GARBAGE) {
823 switch (key_size) {
824 case 0 :
825 key = SEN_SET_STRKEY(e);
826 break;
827 case sizeof(uint32_t) :
828 key = SEN_SET_INTKEY(e);
829 break;
830 default :
831 key = SEN_SET_BINKEY(e);
832 break;
833 }
834 if ((dp = sen_set_at(b, key, NULL))) {
835 sen_set_del(b, dp);
836 sen_set_del(a, ep);
837 count++;
838 }
839 i--;
840 }
841 }
842 return count;
843 }
844
845 sen_rc
sen_set_array_init(sen_set * set,uint32_t size)846 sen_set_array_init(sen_set *set, uint32_t size)
847 {
848 // sen_ctx *ctx = set->ctx;
849 SEN_ASSERT(!set->n_entries);
850 SEN_ASSERT(!set->garbages);
851 set->arrayp = 1;
852 /*
853 set->curr_entry = 0;
854 if (set->chunks[SEN_SET_MAX_CHUNK]) {
855 SEN_FREE(set->chunks[SEN_SET_MAX_CHUNK]);
856 }
857 if (!(set->chunks[SEN_SET_MAX_CHUNK] = SEN_CALLOC(set->entry_size * size))) {
858 return sen_memory_exhausted;
859 }
860 */
861 return sen_set_reset(set, size);
862 }
863
864 /* rset : sets with subrecs */
865
866 inline static int
rec_unit_size(sen_rec_unit unit,int rec_size)867 rec_unit_size(sen_rec_unit unit, int rec_size)
868 {
869 switch (unit) {
870 case sen_rec_document :
871 return sizeof(sen_id);
872 case sen_rec_section :
873 return sizeof(sen_id) + sizeof(int);
874 case sen_rec_position :
875 return sizeof(sen_id) + sizeof(int) + sizeof(int);
876 default :
877 return rec_size;
878 }
879 }
880
881 sen_rc
sen_rset_init(sen_ctx * ctx,sen_set * set,sen_rec_unit record_unit,int record_size,sen_rec_unit subrec_unit,int subrec_size,unsigned int max_n_subrecs)882 sen_rset_init(sen_ctx *ctx, sen_set *set, sen_rec_unit record_unit, int record_size,
883 sen_rec_unit subrec_unit, int subrec_size, unsigned int max_n_subrecs)
884 {
885 sen_rc rc;
886 record_size = rec_unit_size(record_unit, record_size);
887 subrec_size = rec_unit_size(subrec_unit, subrec_size);
888 if (record_unit != sen_rec_userdef && subrec_unit != sen_rec_userdef) {
889 subrec_size -= record_size;
890 }
891 if (!set) { return sen_invalid_argument; }
892 if (record_size < 0) { return sen_invalid_argument; }
893 if ((rc = sen_set_init(ctx, set, record_size,
894 SEN_RSET_SCORE_SIZE + sizeof(int) +
895 max_n_subrecs * (SEN_RSET_SCORE_SIZE + subrec_size), 0))) {
896 return rc;
897 }
898 set->record_unit = record_unit;
899 set->subrec_unit = subrec_unit;
900 set->record_size = record_size;
901 set->subrec_size = subrec_size;
902 set->max_n_subrecs = max_n_subrecs;
903 return rc;
904 }
905
906 inline static void
subrecs_push(byte * subrecs,int size,int n_subrecs,int score,void * body,int dir)907 subrecs_push(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
908 {
909 byte *v;
910 int *c2;
911 int n = n_subrecs - 1, n2;
912 while (n) {
913 n2 = (n - 1) >> 1;
914 c2 = SEN_RSET_SUBRECS_NTH(subrecs,size,n2);
915 if (SEN_RSET_SUBRECS_CMP(score, *c2, dir)) { break; }
916 SEN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
917 n = n2;
918 }
919 v = subrecs + n * (size + SEN_RSET_SCORE_SIZE);
920 *((int *)v) = score;
921 memcpy(v + SEN_RSET_SCORE_SIZE, body, size);
922 }
923
924 inline static void
subrecs_replace_min(byte * subrecs,int size,int n_subrecs,int score,void * body,int dir)925 subrecs_replace_min(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
926 {
927 byte *v;
928 int n = 0, n1, n2, *c1, *c2;
929 for (;;) {
930 n1 = n * 2 + 1;
931 n2 = n1 + 1;
932 c1 = n1 < n_subrecs ? SEN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
933 c2 = n2 < n_subrecs ? SEN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
934 if (c1 && SEN_RSET_SUBRECS_CMP(score, *c1, dir)) {
935 if (c2 &&
936 SEN_RSET_SUBRECS_CMP(score, *c2, dir) &&
937 SEN_RSET_SUBRECS_CMP(*c1, *c2, dir)) {
938 SEN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
939 n = n2;
940 } else {
941 SEN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
942 n = n1;
943 }
944 } else {
945 if (c2 && SEN_RSET_SUBRECS_CMP(score, *c2, dir)) {
946 SEN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
947 n = n2;
948 } else {
949 break;
950 }
951 }
952 }
953 v = subrecs + n * (size + SEN_RSET_SCORE_SIZE);
954 memcpy(v, &score, SEN_RSET_SCORE_SIZE);
955 memcpy(v + SEN_RSET_SCORE_SIZE, body, size);
956 }
957
958 void
sen_rset_add_subrec(sen_set * s,sen_rset_recinfo * ri,int score,void * body,int dir)959 sen_rset_add_subrec(sen_set *s, sen_rset_recinfo *ri, int score, void *body, int dir)
960 {
961 int limit = s->max_n_subrecs;
962 ri->score += score;
963 ri->n_subrecs += 1;
964 if (limit) {
965 int ssize = s->subrec_size;
966 int n_subrecs = SEN_RSET_N_SUBRECS(ri);
967 if (limit < n_subrecs) {
968 if (SEN_RSET_SUBRECS_CMP(score, *ri->subrecs, dir)) {
969 subrecs_replace_min(ri->subrecs, ssize, limit, score, body, dir);
970 }
971 } else {
972 subrecs_push(ri->subrecs, ssize, n_subrecs, score, body, dir);
973 }
974 }
975 }
976
977 sen_set *
sen_rset_group(sen_set * s,int limit,sen_group_optarg * optarg)978 sen_rset_group(sen_set *s, int limit, sen_group_optarg *optarg)
979 {
980 sen_ctx *ctx = s->ctx;
981 sen_set *g;
982 sen_rset_recinfo *ri;
983 sen_rec_unit unit;
984 sen_set_cursor *c;
985 const sen_recordh *rh;
986 byte *key, *ekey, *gkey = NULL;
987 int funcp, dir;
988 unsigned int rsize;
989 if (!s || !s->index) { return NULL; }
990 if (optarg) {
991 unit = sen_rec_userdef;
992 rsize = optarg->key_size;
993 funcp = optarg->func ? 1 : 0;
994 dir = (optarg->mode == sen_sort_ascending) ? -1 : 1;
995 } else {
996 unit = sen_rec_document;
997 rsize = rec_unit_size(unit, sizeof(sen_id));
998 funcp = 0;
999 dir = 1;
1000 }
1001 if (funcp) {
1002 gkey = SEN_MALLOC(rsize ? rsize : 8192);
1003 if (!gkey) {
1004 SEN_LOG(sen_log_alert, "allocation for gkey failed !");
1005 return NULL;
1006 }
1007 } else {
1008 if (s->record_size <= rsize) { return NULL; }
1009 }
1010 if (!(c = sen_set_cursor_open(s))) {
1011 SEN_LOG(sen_log_alert, "sen_set_cursor_open on sen_set_group failed !");
1012 if (gkey) { SEN_FREE(gkey); }
1013 return NULL;
1014 }
1015 if (!(g = SEN_MALLOC(sizeof(sen_set)))) {
1016 sen_set_cursor_close(c);
1017 if (gkey) { SEN_FREE(gkey); }
1018 return NULL;
1019 }
1020 if (sen_rset_init(ctx, g, unit, rsize, s->record_unit, s->record_size, limit)) {
1021 SEN_LOG(sen_log_alert, "sen_rset_init in sen_set_group failed !");
1022 sen_set_cursor_close(c);
1023 SEN_FREE(g);
1024 if (gkey) { SEN_FREE(gkey); }
1025 return NULL;
1026 }
1027 while ((rh = sen_set_cursor_next(c, (void **)&key, (void **)&ri))) {
1028 if (funcp) {
1029 if (optarg->func(s, rh, gkey, optarg->func_arg)) { continue; }
1030 ekey = key;
1031 } else {
1032 gkey = key;
1033 ekey = key + rsize;
1034 }
1035 {
1036 sen_rset_recinfo *gri;
1037 if (sen_set_get(g, gkey, (void **)&gri)) {
1038 sen_rset_add_subrec(g, gri, ri->score, ekey, dir);
1039 }
1040 }
1041 }
1042 sen_set_cursor_close(c);
1043 if (funcp) { SEN_FREE(gkey); }
1044 return g;
1045 }
1046
1047 sen_rc
sen_rset_subrec_info(sen_set * s,const sen_recordh * rh,int index,sen_id * rid,int * section,int * pos,int * score,void ** subrec)1048 sen_rset_subrec_info(sen_set *s, const sen_recordh *rh, int index,
1049 sen_id *rid, int *section, int *pos, int *score, void **subrec)
1050 {
1051 sen_rc rc;
1052 sen_rset_posinfo *pi;
1053 sen_rset_recinfo *ri;
1054 int *p, unit_size = SEN_RSET_SCORE_SIZE + s->subrec_size;
1055 if (!s || !rh || index < 0) { return sen_invalid_argument; }
1056 if ((unsigned int)index >= s->max_n_subrecs) { return sen_invalid_argument; }
1057 rc = sen_set_element_info(s, rh, (void **)&pi, (void **)&ri);
1058 if (rc) { return rc; }
1059 if (index >= ri->n_subrecs) { return sen_invalid_argument; }
1060 p = (int *)(ri->subrecs + index * unit_size);
1061 if (score) { *score = p[0]; }
1062 if (subrec) { *subrec = &p[1]; }
1063 switch (s->record_unit) {
1064 case sen_rec_document :
1065 if (rid) { *rid = pi->rid; }
1066 if (section) { *section = (s->subrec_unit != sen_rec_userdef) ? p[1] : 0; }
1067 if (pos) { *pos = (s->subrec_unit == sen_rec_position) ? p[2] : 0; }
1068 break;
1069 case sen_rec_section :
1070 if (rid) { *rid = pi->rid; }
1071 if (section) { *section = pi->sid; }
1072 if (pos) { *pos = (s->subrec_unit == sen_rec_position) ? p[1] : 0; }
1073 break;
1074 default :
1075 pi = (sen_rset_posinfo *)&p[1];
1076 switch (s->subrec_unit) {
1077 case sen_rec_document :
1078 if (rid) { *rid = pi->rid; }
1079 if (section) { *section = 0; }
1080 if (pos) { *pos = 0; }
1081 break;
1082 case sen_rec_section :
1083 if (rid) { *rid = pi->rid; }
1084 if (section) { *section = pi->sid; }
1085 if (pos) { *pos = 0; }
1086 break;
1087 case sen_rec_position :
1088 if (rid) { *rid = pi->rid; }
1089 if (section) { *section = pi->sid; }
1090 if (pos) { *pos = pi->pos; }
1091 break;
1092 default :
1093 if (rid) { *rid = 0; }
1094 if (section) { *section = 0; }
1095 if (pos) { *pos = 0; }
1096 break;
1097 }
1098 break;
1099 }
1100 return sen_success;
1101 }
1102
1103 /* sen_records : sets with keys or/and cursor */
1104
1105 sen_records *
sen_records_open(sen_rec_unit record_unit,sen_rec_unit subrec_unit,unsigned int max_n_subrecs)1106 sen_records_open(sen_rec_unit record_unit,
1107 sen_rec_unit subrec_unit, unsigned int max_n_subrecs)
1108 {
1109 sen_records *r;
1110 if (!(r = SEN_GMALLOC(sizeof(sen_records)))) { return NULL; }
1111 if (sen_rset_init(&sen_gctx, r, record_unit, 0, subrec_unit, 0, max_n_subrecs)) {
1112 SEN_GFREE(r);
1113 return NULL;
1114 }
1115 return r;
1116 }
1117
1118 void
sen_records_cursor_clear(sen_records * r)1119 sen_records_cursor_clear(sen_records *r)
1120 {
1121 sen_ctx *ctx = r->ctx;
1122 if (r->sorted) {
1123 SEN_FREE(r->sorted);
1124 r->sorted = NULL;
1125 }
1126 if (r->cursor) {
1127 sen_set_cursor_close(r->cursor);
1128 r->cursor = NULL;
1129 }
1130 r->curr_rec = NULL;
1131 }
1132
1133 sen_rc
sen_records_close(sen_records * r)1134 sen_records_close(sen_records *r)
1135 {
1136 sen_ctx *ctx;
1137 if (!r) { return sen_invalid_argument; }
1138 ctx = r->ctx;
1139 if (r->curr_rec) {
1140 sen_id *rid;
1141 sen_rset_recinfo *ri;
1142 if (!sen_set_element_info(r, r->curr_rec, (void **)&rid, (void **)&ri)) {
1143 SEN_LOG(sen_log_debug, "curr_rec: %d:%d", *rid, ri->score);
1144 // sen_log("sen_record_next=%d,%d", *rid, *(_sen_sym_key(r->keys, *rid)));
1145 }
1146 }
1147 sen_records_cursor_clear(r);
1148 return sen_set_close(r);
1149 }
1150
1151 sen_rc
sen_records_reopen(sen_records * r,sen_rec_unit record_unit,sen_rec_unit subrec_unit,unsigned int max_n_subrecs)1152 sen_records_reopen(sen_records *r, sen_rec_unit record_unit,
1153 sen_rec_unit subrec_unit, unsigned int max_n_subrecs)
1154 {
1155 sen_ctx *ctx;
1156 int record_size = rec_unit_size(record_unit, 0);
1157 int subrec_size = rec_unit_size(subrec_unit, 0);
1158 if (!r || record_size < 0 || (max_n_subrecs && subrec_size <= record_size)) {
1159 return sen_invalid_argument;
1160 }
1161 ctx = r->ctx;
1162 sen_records_cursor_clear(r);
1163 sen_set_fin(r);
1164 return sen_rset_init(ctx, r, record_unit, 0, subrec_unit, 0, max_n_subrecs);
1165 }
1166
1167 sen_rc
sen_records_sort(sen_records * r,int limit,sen_sort_optarg * optarg)1168 sen_records_sort(sen_records *r, int limit, sen_sort_optarg *optarg)
1169 {
1170 if (!r) { return sen_invalid_argument; }
1171 sen_records_cursor_clear(r);
1172 if (optarg) {
1173 r->sorted = sen_set_sort(r, limit, optarg);
1174 } else {
1175 sen_set_sort_optarg arg;
1176 arg.mode = sen_sort_descending;
1177 arg.compar = NULL;
1178 arg.compar_arg = (void *)(intptr_t)r->key_size;
1179 r->sorted = sen_set_sort(r, limit, &arg);
1180 }
1181 return r->sorted ? sen_success : sen_internal_error;
1182 }
1183
1184 sen_rc
sen_records_rewind(sen_records * r)1185 sen_records_rewind(sen_records *r)
1186 {
1187 if (!r) { return sen_invalid_argument; }
1188 if (r->sorted) {
1189 r->curr_rec = NULL;
1190 return sen_success;
1191 } else {
1192 sen_records_cursor_clear(r);
1193 r->cursor = sen_set_cursor_open(r);
1194 return r->cursor ? sen_success : sen_internal_error;
1195 }
1196 }
1197
1198 int
sen_records_next(sen_records * r,void * keybuf,int bufsize,int * score)1199 sen_records_next(sen_records *r, void *keybuf, int bufsize, int *score)
1200 {
1201 if (!r) { return 0; }
1202 if (r->sorted) {
1203 if (r->curr_rec) {
1204 if (r->curr_rec - r->sorted >= r->limit - 1) { return 0; }
1205 r->curr_rec++;
1206 } else {
1207 if (r->limit > 0) { r->curr_rec = r->sorted; }
1208 }
1209 } else {
1210 if (!r->cursor && sen_records_rewind(r)) { return 0; }
1211 r->curr_rec = sen_set_cursor_next(r->cursor, NULL, NULL);
1212 }
1213 if (r->curr_rec) {
1214 sen_id *rid;
1215 sen_rset_recinfo *ri;
1216 if (!sen_set_element_info(r, r->curr_rec, (void **)&rid, (void **)&ri)) {
1217 if (score) { *score = ri->score; }
1218 if (r->record_unit != sen_rec_userdef) {
1219 return r->keys ? sen_sym_key(r->keys, *rid, keybuf, bufsize) : r->record_size;
1220 } else {
1221 if (r->record_size <= bufsize) { memcpy(keybuf, rid, r->record_size); }
1222 return r->record_size;
1223 }
1224 }
1225 }
1226 return 0;
1227 }
1228
1229 int
sen_records_find(sen_records * r,const void * key)1230 sen_records_find(sen_records *r, const void *key)
1231 {
1232 sen_id rid;
1233 sen_rset_recinfo *ri;
1234 if (!r || !r->keys || r->record_unit != sen_rec_document) { return 0; }
1235 if (!(rid = sen_sym_at(r->keys, key))) { return 0; }
1236 if (!sen_set_at(r, &rid, (void **) &ri)) { return 0; }
1237 return ri->score;
1238 }
1239
1240 int
sen_records_nhits(sen_records * r)1241 sen_records_nhits(sen_records *r)
1242 {
1243 if (!r) { return 0; }
1244 return r->n_entries;
1245 }
1246
1247 int
sen_records_curr_score(sen_records * r)1248 sen_records_curr_score(sen_records *r)
1249 {
1250 sen_rset_recinfo *ri;
1251 if (!r || !r->curr_rec) { return 0; }
1252 if (sen_set_element_info(r, r->curr_rec, NULL, (void **)&ri)) { return 0; }
1253 return ri->score;
1254 }
1255
1256 int
sen_records_curr_key(sen_records * r,void * keybuf,int bufsize)1257 sen_records_curr_key(sen_records *r, void *keybuf, int bufsize)
1258 {
1259 sen_id *rid;
1260 if (!r || !r->curr_rec) { return 0; }
1261 if (sen_set_element_info(r, r->curr_rec, (void **)&rid, NULL)) {
1262 return 0;
1263 }
1264 if (r->record_unit != sen_rec_userdef) {
1265 return sen_sym_key(r->keys, *rid, keybuf, bufsize);
1266 } else {
1267 if (r->record_size <= bufsize) { memcpy(keybuf, rid, r->record_size); }
1268 return r->record_size;
1269 }
1270 }
1271
1272 const sen_recordh *
sen_records_curr_rec(sen_records * r)1273 sen_records_curr_rec(sen_records *r)
1274 {
1275 if (!r) { return NULL; }
1276 return r->curr_rec;
1277 }
1278
1279 sen_records *
sen_records_union(sen_records * a,sen_records * b)1280 sen_records_union(sen_records *a, sen_records *b)
1281 {
1282 if (!a || !b) { return NULL; }
1283 if (a->keys != b->keys) { return NULL; }
1284 if (!sen_set_union(a, b)) { return NULL; }
1285 sen_records_close(b);
1286 sen_records_cursor_clear(a);
1287 return a;
1288 }
1289
1290 sen_records *
sen_records_subtract(sen_records * a,sen_records * b)1291 sen_records_subtract(sen_records *a, sen_records *b)
1292 {
1293 if (!a || !b) { return NULL; }
1294 if (a->keys != b->keys) { return NULL; }
1295 if (!sen_set_subtract(a, b)) { return NULL; }
1296 sen_records_close(b);
1297 sen_records_cursor_clear(a);
1298 return a;
1299 }
1300
1301 sen_records *
sen_records_intersect(sen_records * a,sen_records * b)1302 sen_records_intersect(sen_records *a, sen_records *b)
1303 {
1304 if (!a || !b) { return NULL; }
1305 if (a->keys != b->keys) { return NULL; }
1306 if (a->n_entries > b->n_entries) {
1307 sen_set c;
1308 memcpy(&c, a, sizeof(sen_records));
1309 memcpy(a, b, sizeof(sen_records));
1310 memcpy(b, &c, sizeof(sen_records));
1311 }
1312 if (!sen_set_intersect(a, b)) { return NULL; }
1313 sen_records_close(b);
1314 sen_records_cursor_clear(a);
1315 return a;
1316 }
1317
1318 int
sen_records_difference(sen_records * a,sen_records * b)1319 sen_records_difference(sen_records *a, sen_records *b)
1320 {
1321 int count;
1322 if (!a || !b) { return -1; }
1323 if (a->keys != b->keys) { return -1; }
1324 if ((count = sen_set_difference(a, b)) >= 0) {
1325 sen_records_cursor_clear(a);
1326 sen_records_cursor_clear(b);
1327 }
1328 return count;
1329 }
1330
1331 #define SUBRECS_CMP(a,b,dir) (((a) - (b))*(dir) > 0)
1332 #define SUBRECS_NTH(subrecs,size,n) ((int *)(subrecs + n * (size + SEN_RSET_SCORE_SIZE)))
1333 #define SUBRECS_COPY(subrecs,size,n,src) \
1334 (memcpy(subrecs + n * (size + SEN_RSET_SCORE_SIZE), src, size + SEN_RSET_SCORE_SIZE))
1335
1336 sen_rc
sen_records_group(sen_records * r,int limit,sen_group_optarg * optarg)1337 sen_records_group(sen_records *r, int limit, sen_group_optarg *optarg)
1338 {
1339 sen_ctx *ctx;
1340 sen_set *g;
1341 if (!(g = sen_rset_group(r, limit, optarg))) {
1342 return sen_internal_error;
1343 }
1344 ctx = r->ctx;
1345 sen_records_cursor_clear(r);
1346 sen_set_fin(r);
1347 memcpy(r, g, sizeof(sen_set));
1348 SEN_FREE(g);
1349 return sen_success;
1350 }
1351
1352 const sen_recordh *
sen_records_at(sen_records * r,const void * key,unsigned section,unsigned pos,int * score,int * n_subrecs)1353 sen_records_at(sen_records *r, const void *key, unsigned section, unsigned pos,
1354 int *score, int *n_subrecs)
1355 {
1356 sen_rset_recinfo *ri;
1357 const sen_recordh *res;
1358 if (!r || !r->keys) { return NULL; }
1359 if (r->record_unit == sen_rec_userdef) {
1360 res = r->curr_rec = sen_set_at(r, key, (void **) &ri);
1361 } else {
1362 sen_rset_posinfo pi;
1363 if (!(pi.rid = sen_sym_at(r->keys, key))) { return NULL; }
1364 pi.sid = section;
1365 pi.pos = pos;
1366 res = r->curr_rec = sen_set_at(r, &pi, (void **) &ri);
1367 }
1368 if (res) {
1369 if (score) { *score = ri->score; }
1370 if (n_subrecs) { *n_subrecs = ri->n_subrecs; }
1371 }
1372 return res;
1373 }
1374
1375 sen_rc
sen_record_info(sen_records * r,const sen_recordh * rh,void * keybuf,int bufsize,int * keysize,int * section,int * pos,int * score,int * n_subrecs)1376 sen_record_info(sen_records *r, const sen_recordh *rh,
1377 void *keybuf, int bufsize, int *keysize,
1378 int *section, int *pos, int *score, int *n_subrecs)
1379 {
1380 sen_rc rc;
1381 sen_rset_posinfo *pi;
1382 sen_rset_recinfo *ri;
1383 if (!r || !rh) { return sen_invalid_argument; }
1384 rc = sen_set_element_info(r, rh, (void **)&pi, (void **)&ri);
1385 if (rc) { return rc; }
1386 switch (r->record_unit) {
1387 case sen_rec_document :
1388 if ((keybuf && bufsize) || keysize) {
1389 int len = sen_sym_key(r->keys, pi->rid, keybuf, bufsize);
1390 if (keysize) { *keysize = len; }
1391 }
1392 if (section) { *section = 0; }
1393 if (pos) { *pos = 0; }
1394 break;
1395 case sen_rec_section :
1396 if ((keybuf && bufsize) || keysize) {
1397 int len = sen_sym_key(r->keys, pi->rid, keybuf, bufsize);
1398 if (keysize) { *keysize = len; }
1399 }
1400 if (section) { *section = pi->sid; }
1401 if (pos) { *pos = 0; }
1402 break;
1403 case sen_rec_position :
1404 if ((keybuf && bufsize) || keysize) {
1405 int len = sen_sym_key(r->keys, pi->rid, keybuf, bufsize);
1406 if (keysize) { *keysize = len; }
1407 }
1408 if (section) { *section = pi->sid; }
1409 if (pos) { *pos = pi->pos; }
1410 break;
1411 case sen_rec_userdef :
1412 if ((keybuf && bufsize) || keysize) {
1413 unsigned int len = r->record_size;
1414 if (!len) { len = (unsigned int)strlen((const char *)pi) + 1; }
1415 if ((unsigned int)bufsize >= len) { memcpy(keybuf, pi, len); }
1416 if (keysize) { *keysize = len; }
1417 }
1418 if (section) { *section = 0; }
1419 if (pos) { *pos = 0; }
1420 break;
1421 default :
1422 return sen_invalid_format;
1423 break;
1424 }
1425 if (score) { *score = ri->score; }
1426 if (n_subrecs) { *n_subrecs = ri->n_subrecs; }
1427 return sen_success;
1428 }
1429
1430 sen_rc
sen_record_subrec_info(sen_records * r,const sen_recordh * rh,int index,void * keybuf,int bufsize,int * keysize,int * section,int * pos,int * score)1431 sen_record_subrec_info(sen_records *r, const sen_recordh *rh, int index,
1432 void *keybuf, int bufsize, int *keysize,
1433 int *section, int *pos, int *score)
1434 {
1435 sen_rc rc;
1436 sen_id rid;
1437 void *subrec;
1438 if ((rc = sen_rset_subrec_info(r, rh, index, &rid, section, pos, score, &subrec))) {
1439 return rc;
1440 }
1441 if ((keybuf && bufsize) || keysize) {
1442 if (rid) {
1443 int len = sen_sym_key(r->keys, rid, keybuf, bufsize);
1444 if (keysize) { *keysize = len; }
1445 } else if (r->record_unit == sen_rec_userdef && r->subrec_unit == sen_rec_userdef) {
1446 int len = (int) r->subrec_size;
1447 if (!len) { len = (unsigned int)strlen((char *)subrec) + 1; }
1448 if ((unsigned int)bufsize >= len) { memcpy(keybuf, subrec, len); }
1449 if (keysize) { *keysize = len; }
1450 }
1451 }
1452 return sen_success;
1453 }
1454