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