Major restructuring in rsets.
[idzebra-moved-to-github.git] / rset / rsbool.c
1 /* $Id: rsbool.c,v 1.45 2004-08-31 10:43:39 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include <zebrautl.h>
29 #include <rset.h>
30 #include <rsbool.h>
31
32 #ifndef RSET_DEBUG
33 #define RSET_DEBUG 0
34 #endif
35
36 static RSFD r_open (RSET ct, int flag);
37 static void r_close (RSFD rfd);
38 static void r_delete (RSET ct);
39 static void r_rewind (RSFD rfd);
40 static int r_forward(RSFD rfd, void *buf,
41                      int (*cmpfunc)(const void *p1, const void *p2),
42                      const void *untilbuf);
43 static void r_pos (RSFD rfd, double *current, double *total); 
44 static int r_read_and (RSFD rfd, void *buf);
45 static int r_read_or (RSFD rfd, void *buf);
46 static int r_read_not (RSFD rfd, void *buf);
47 static int r_write (RSFD rfd, const void *buf);
48
49 static const struct rset_control control_and = 
50 {
51     "and",
52     r_delete,
53     r_open,
54     r_close,
55     r_rewind,
56     r_forward, 
57     r_pos,    
58     r_read_and,
59     r_write,
60 };
61
62 static const struct rset_control control_or = 
63 {
64     "or",
65     r_delete,
66     r_open,
67     r_close,
68     r_rewind,
69     r_forward, 
70     r_pos,
71     r_read_or,
72     r_write,
73 };
74
75 static const struct rset_control control_not = 
76 {
77     "not",
78     r_delete,
79     r_open,
80     r_close,
81     r_rewind,
82     r_forward, 
83     r_pos,
84     r_read_not,
85     r_write,
86 };
87
88
89 const struct rset_control *rset_kind_and = &control_and;
90 const struct rset_control *rset_kind_or = &control_or;
91 const struct rset_control *rset_kind_not = &control_not;
92
93 struct rset_bool_info {
94     int key_size;
95     RSET rset_l;
96     RSET rset_r;
97     int (*cmp)(const void *p1, const void *p2);
98     void (*log_item)(int logmask, const void *p, const char *txt);
99 };
100
101 struct rset_bool_rfd {
102     zint hits;
103     RSFD rfd_l;
104     RSFD rfd_r;
105     int  more_l;
106     int  more_r;
107     void *buf_l;
108     void *buf_r;
109     int tail;
110     struct rset_bool_rfd *next;
111     struct rset_bool_info *info;
112 };    
113
114 static RSET rsbool_create_base( const struct rset_control *ctrl,
115             NMEM nmem, int key_size, 
116             int (*cmp)(const void *p1, const void *p2),
117             RSET rset_l, RSET rset_r, 
118             void (*log_item)(int logmask, const void *p, const char *txt) )
119 {
120     RSET rnew=rset_create_base(ctrl, nmem);
121     struct rset_bool_info *info;
122     info = (struct rset_bool_info *) nmem_malloc(rnew->nmem,sizeof(*info));
123     info->key_size = key_size;
124     info->rset_l = rset_l;
125     info->rset_r = rset_r;
126     info->cmp = cmp;
127     info->log_item = log_item;
128     
129     rnew->priv=info;
130     return rnew;
131 }
132
133
134 RSET rsbool_create_and( NMEM nmem, int key_size, 
135             int (*cmp)(const void *p1, const void *p2),
136             RSET rset_l, RSET rset_r, 
137             void (*log_item)(int logmask, const void *p, const char *txt) )
138 {
139     return rsbool_create_base(rset_kind_and, nmem, key_size, cmp,
140                               rset_l, rset_r, log_item);
141 }
142
143 RSET rsbool_create_or( NMEM nmem, int key_size, 
144             int (*cmp)(const void *p1, const void *p2),
145             RSET rset_l, RSET rset_r, 
146             void (*log_item)(int logmask, const void *p, const char *txt) )
147 {
148     return rsbool_create_base(rset_kind_or, nmem, key_size, cmp,
149                               rset_l, rset_r, log_item);
150 }
151
152 RSET rsbool_create_not( NMEM nmem, int key_size, 
153             int (*cmp)(const void *p1, const void *p2),
154             RSET rset_l, RSET rset_r, 
155             void (*log_item)(int logmask, const void *p, const char *txt) )
156 {
157     return rsbool_create_base(rset_kind_not, nmem, key_size, cmp,
158                               rset_l, rset_r, log_item);
159 }
160
161 static void r_delete (RSET ct)
162 {
163     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
164     rset_delete (info->rset_l);
165     rset_delete (info->rset_r);
166 }
167
168
169 static RSFD r_open (RSET ct, int flag)
170 {
171     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
172     RSFD rfd;
173     struct rset_bool_rfd *p;
174    
175
176     if (flag & RSETF_WRITE)
177     {
178         logf (LOG_FATAL, "bool set type is read-only");
179         return NULL;
180     }
181     rfd = rfd_create_base(ct);
182     if (rfd->priv)
183         p=(struct rset_bool_rfd *)rfd->priv;
184     else {
185         p=nmem_malloc(ct->nmem,sizeof(*p));
186         rfd->priv=p;
187         p->buf_l = nmem_malloc(ct->nmem, info->key_size);
188         p->buf_r = nmem_malloc(ct->nmem, info->key_size);
189     }
190
191     logf(LOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
192     p->hits=0;
193
194     p->rfd_l = rset_open (info->rset_l, RSETF_READ);
195     p->rfd_r = rset_open (info->rset_r, RSETF_READ);
196     p->more_l = rset_read (p->rfd_l, p->buf_l);
197     p->more_r = rset_read (p->rfd_r, p->buf_r);
198     p->tail = 0;
199     return rfd;
200 }
201
202 static void r_close (RSFD rfd)
203 {
204  /* struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv); */
205     struct rset_bool_rfd *prfd=(struct rset_bool_rfd *)rfd->priv;
206
207     rset_close (prfd->rfd_l);
208     rset_close (prfd->rfd_r);
209     rfd_delete_base(rfd);
210 }
211
212
213 static void r_rewind (RSFD rfd)
214 {
215  /* struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv); */
216     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
217
218     logf (LOG_DEBUG, "rsbool_rewind");
219     rset_rewind (p->rfd_l);
220     rset_rewind (p->rfd_r);
221     p->more_l = rset_read (p->rfd_l, p->buf_l);
222     p->more_r = rset_read (p->rfd_r, p->buf_r);
223     p->hits=0;
224 }
225
226 static int r_forward (RSFD rfd, void *buf,
227                      int (*cmpfunc)(const void *p1, const void *p2),
228                      const void *untilbuf)
229 {
230     struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv);
231     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
232     int rc;
233
234     if ( p->more_l && ((cmpfunc)(untilbuf,p->buf_l)==2) )
235         p->more_l = rset_forward(p->rfd_l, p->buf_l,
236                         info->cmp, untilbuf);
237     if ( p->more_r && ((cmpfunc)(untilbuf,p->buf_r)==2))
238         p->more_r = rset_forward(p->rfd_r, p->buf_r,
239                         info->cmp, untilbuf);
240     p->tail=0; 
241     rc = rset_read(rfd,buf); 
242     return rc;
243 }
244
245
246 /*
247     1,1         1,3
248     1,9         2,1
249     1,11        3,1
250     2,9
251
252   1,1     1,1
253   1,3     1,3
254           1,9
255           1,11
256   2,1     2,1
257           2,9
258           3,1
259 */
260
261 static int r_read_and (RSFD rfd, void *buf)
262 {
263     struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv);
264     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
265
266     while (p->more_l || p->more_r)
267     {
268         int cmp;
269
270         if (p->more_l && p->more_r)
271             cmp = (*info->cmp)(p->buf_l, p->buf_r);
272         else if (p->more_l)
273             cmp = -2;
274         else
275             cmp = 2;
276 #if RSET_DEBUG
277         logf (LOG_DEBUG, "r_read_and [%p] looping: m=%d/%d c=%d t=%d",
278                         rfd, p->more_l, p->more_r, cmp, p->tail);
279         (*info->log_item)(LOG_DEBUG, p->buf_l, "left ");
280         (*info->log_item)(LOG_DEBUG, p->buf_r, "right ");
281 #endif
282         if (!cmp)
283         {
284             memcpy (buf, p->buf_l, info->key_size);
285             p->more_l = rset_read (p->rfd_l, p->buf_l);
286             p->tail = 1;
287         }
288         else if (cmp == 1)
289         {
290             memcpy (buf, p->buf_r, info->key_size);
291             p->more_r = rset_read (p->rfd_r, p->buf_r);
292             p->tail = 1;
293 #if RSET_DEBUG
294             logf (LOG_DEBUG, "r_read_and [%p] returning R m=%d/%d c=%d",
295                     rfd, p->more_l, p->more_r, cmp);
296             key_logdump(LOG_DEBUG,buf);
297             (*info->log_item)(LOG_DEBUG, buf, "");
298 #endif
299             p->hits++;
300             return 1;
301         }
302         else if (cmp == -1)
303         {
304             memcpy (buf, p->buf_l, info->key_size);
305             p->more_l = rset_read (p->rfd_l, p->buf_l);
306             p->tail = 1;
307 #if RSET_DEBUG
308             logf (LOG_DEBUG, "r_read_and [%p] returning L m=%d/%d c=%d",
309                     rfd, p->more_l, p->more_r, cmp);
310             (*info->log_item)(LOG_DEBUG, buf, "");
311 #endif
312             p->hits++;
313             return 1;
314         }
315         else if (cmp > 1)  /* cmp == 2 */
316         {
317 #define OLDCODE 0
318 #if OLDCODE
319             memcpy (buf, p->buf_r, info->key_size);
320             
321             p->more_r = rset_read (p->rfd_r, p->buf_r);
322             if (p->tail)
323             {
324                 if (!p->more_r || (*info->cmp)(p->buf_r, buf) > 1)
325                     p->tail = 0;
326 #if RSET_DEBUG
327                 logf (LOG_DEBUG, "r_read_and returning C m=%d/%d c=%d",
328                         p->more_l, p->more_r, cmp);
329                 (*info->log_item)(LOG_DEBUG, buf, "");
330 #endif
331                 p->hits++;
332                 return 1;
333             }
334 #else
335             
336             if (p->tail)
337             {
338                 memcpy (buf, p->buf_r, info->key_size);
339                 p->more_r = rset_read (p->rfd_r, p->buf_r);
340                 if (!p->more_r || (*info->cmp)(p->buf_r, buf) > 1)
341                     p->tail = 0;
342 #if RSET_DEBUG
343                 logf (LOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
344                         rfd, p->more_l, p->more_r, cmp);
345                 (*info->log_item)(LOG_DEBUG, buf, "");
346 #endif
347                 p->hits++;
348                 return 1;
349             }
350             else
351             {
352 #if RSET_DEBUG
353                 logf (LOG_DEBUG, "r_read_and [%p] about to forward R m=%d/%d c=%d",
354                         rfd, p->more_l, p->more_r, cmp);
355 #endif
356                 if (p->more_r && p->more_l)
357                     p->more_r = rset_forward( p->rfd_r, 
358                                     p->buf_r, (info->cmp), p->buf_l);
359                 else 
360                     return 0; /* no point in reading further */
361             }
362 #endif
363         }
364         else  /* cmp == -2 */
365         {
366 #if OLDCODE
367              memcpy (buf, p->buf_l, info->key_size);
368              p->more_l = rset_read (p->rfd_l, p->buf_l);
369              if (p->tail)
370              {
371                  if (!p->more_l || (*info->cmp)(p->buf_l, buf) > 1)
372                      p->tail = 0;
373 #if RSET_DEBUG
374                  logf (LOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
375                         rfd, p->more_l, p->more_r, cmp);
376                  (*info->log_item)(LOG_DEBUG, buf, "");
377 #endif
378                  p->hits++;
379                  return 1;
380              }
381 #else
382             if (p->tail)
383             {
384                 memcpy (buf, p->buf_l, info->key_size);
385                 p->more_l = rset_read (p->rfd_l, p->buf_l);
386                 if (!p->more_l || (*info->cmp)(p->buf_l, buf) > 1)
387                     p->tail = 0;
388 #if RSET_DEBUG
389                 logf (LOG_DEBUG, "r_read_and [%p] returning L tail m=%d/%d c=%d",
390                         rfd, p->more_l, p->more_r, cmp);
391                 (*info->log_item)(LOG_DEBUG, buf, "");
392 #endif
393                 p->hits++;
394                 return 1;
395             }
396             else
397             {
398 #if RSET_DEBUG
399                 logf (LOG_DEBUG, "r_read_and [%p] about to forward L m=%d/%d c=%d",
400                         rfd, p->more_l, p->more_r, cmp);
401 #endif
402                 if (p->more_r && p->more_l)
403                     p->more_l = rset_forward(p->rfd_l, 
404                                     p->buf_l, (info->cmp), p->buf_r);
405                 else 
406                     return 0; /* no point in reading further */
407             }
408 #endif
409         }
410     }
411 #if RSET_DEBUG
412     logf (LOG_DEBUG, "r_read_and [%p] reached its end",rfd);
413 #endif
414     return 0;
415 }
416
417 static int r_read_or (RSFD rfd, void *buf)
418 {
419     struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv);
420     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
421
422     while (p->more_l || p->more_r)
423     {
424         int cmp;
425
426         if (p->more_l && p->more_r)
427             cmp = (*info->cmp)(p->buf_l, p->buf_r);
428         else if (p->more_r)
429             cmp = 2;
430         else
431             cmp = -2;
432         if (!cmp)
433         {
434             memcpy (buf, p->buf_l, info->key_size);
435             p->more_l = rset_read (p->rfd_l, p->buf_l);
436             p->more_r = rset_read (p->rfd_r, p->buf_r);
437 #if RSET_DEBUG
438             logf (LOG_DEBUG, "r_read_or returning A m=%d/%d c=%d",
439                     p->more_l, p->more_r, cmp);
440             (*info->log_item)(LOG_DEBUG, buf, "");
441 #endif
442             p->hits++;
443             return 1;
444         }
445         else if (cmp > 0)
446         {
447             memcpy (buf, p->buf_r, info->key_size);
448             p->more_r = rset_read (p->rfd_r, p->buf_r);
449 #if RSET_DEBUG
450             logf (LOG_DEBUG, "r_read_or returning B m=%d/%d c=%d",
451                     p->more_l, p->more_r, cmp);
452             (*info->log_item)(LOG_DEBUG, buf, "");
453 #endif
454             p->hits++;
455             return 1;
456         }
457         else
458         {
459             memcpy (buf, p->buf_l, info->key_size);
460             p->more_l = rset_read ( p->rfd_l, p->buf_l);
461 #if RSET_DEBUG
462             logf (LOG_DEBUG, "r_read_or returning C m=%d/%d c=%d",
463                     p->more_l, p->more_r, cmp);
464             (*info->log_item)(LOG_DEBUG, buf, "");
465 #endif
466             p->hits++;
467             return 1;
468         }
469     }
470     return 0;
471 }
472
473 static int r_read_not (RSFD rfd, void *buf)
474 {
475     struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv);
476     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
477
478     while (p->more_l || p->more_r)
479     {
480         int cmp;
481
482         if (p->more_l && p->more_r)
483             cmp = (*info->cmp)(p->buf_l, p->buf_r);
484         else if (p->more_r)
485             cmp = 2;
486         else
487             cmp = -2;
488         if (cmp < -1)
489         {
490             memcpy (buf, p->buf_l, info->key_size);
491             p->more_l = rset_read (p->rfd_l, p->buf_l);
492             p->hits++;
493             return 1;
494         }
495         else if (cmp > 1)
496         {
497                 p->more_r = rset_forward( p->rfd_r, 
498                     p->buf_r, (info->cmp), p->buf_l);
499         }
500         else
501         {
502             memcpy (buf, p->buf_l, info->key_size);
503             do
504             { 
505                 p->more_l = rset_read (p->rfd_l, p->buf_l);
506                 if (!p->more_l)
507                     break;
508                 cmp = (*info->cmp)(p->buf_l, buf);
509             } while (cmp >= -1 && cmp <= 1);
510             do
511             {
512                 p->more_r = rset_read (p->rfd_r, p->buf_r);
513                 if (!p->more_r)
514                     break;
515                 cmp = (*info->cmp)(p->buf_r, buf);
516             } while (cmp >= -1 && cmp <= 1);
517         }
518     }
519     return 0;
520 }
521
522
523 static int r_write (RSFD rfd, const void *buf)
524 {
525     logf (LOG_FATAL, "bool set type is read-only");
526     return -1;
527 }
528
529 static void r_pos (RSFD rfd, double *current, double *total)
530 {
531     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
532     double lcur,ltot;
533     double rcur,rtot;
534     double r;
535     ltot=-1; rtot=-1;
536     rset_pos(p->rfd_l,  &lcur, &ltot);
537     rset_pos(p->rfd_r,  &rcur, &rtot);
538     if ( (rtot<0) && (ltot<0)) { /*no position */
539         *current=rcur;  /* return same as you got */
540         *total=rtot;    /* probably -1 for not available */
541     }
542     if ( rtot<0) { rtot=0; rcur=0;} /* if only one useful, use it */
543     if ( ltot<0) { ltot=0; lcur=0;}
544     if ( rtot+ltot < 1 ) { /* empty rset */
545         *current=0;
546         *total=0;
547         return;
548     }
549     r=1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
550     *current=(double) (p->hits);
551     *total=*current/r ; 
552 #if RSET_DEBUG
553     yaz_log(LOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
554                     info->rset_l->control->desc, info->rset_r->control->desc,
555                     *current, *total, r);
556 #endif
557 }