39f9ec13cb177a59d98927ff9321ec777fcf3f44
[idzebra-moved-to-github.git] / rset / rsbool.c
1 /* $Id: rsbool.c,v 1.51 2004-11-19 10:27:14 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
31 #ifndef RSET_DEBUG
32 #define RSET_DEBUG 0
33 #endif
34
35 static RSFD r_open (RSET ct, int flag);
36 static void r_close (RSFD rfd);
37 static void r_delete (RSET ct);
38 static int r_forward(RSFD rfd, void *buf, TERMID *term, const void *untilbuf);
39 static void r_pos (RSFD rfd, double *current, double *total); 
40 static int r_read_and (RSFD rfd, void *buf, TERMID *term);
41 static int r_read_or (RSFD rfd, void *buf, TERMID *term);
42 static int r_read_not (RSFD rfd, void *buf, TERMID *term);
43 static int r_write (RSFD rfd, const void *buf);
44 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm);
45
46
47 static const struct rset_control control_and = 
48 {
49     "and",
50     r_delete,
51     r_get_terms,
52     r_open,
53     r_close,
54     r_forward, 
55     r_pos,    
56     r_read_and,
57     r_write,
58 };
59
60 static const struct rset_control control_or = 
61 {
62     "or",
63     r_delete,
64     r_get_terms,
65     r_open,
66     r_close,
67     r_forward, 
68     r_pos,
69     r_read_or,
70     r_write,
71 };
72
73 static const struct rset_control control_not = 
74 {
75     "not",
76     r_delete,
77     r_get_terms,
78     r_open,
79     r_close,
80     r_forward, 
81     r_pos,
82     r_read_not,
83     r_write,
84 };
85
86
87 const struct rset_control *rset_kind_and = &control_and;
88 const struct rset_control *rset_kind_or  = &control_or;
89 const struct rset_control *rset_kind_not = &control_not;
90
91 struct rset_bool_info {
92     RSET rset_l;
93     RSET rset_r;
94 };
95
96 struct rset_bool_rfd {
97     zint hits;
98     RSFD rfd_l;
99     RSFD rfd_r;
100     int  more_l;
101     int  more_r;
102     void *buf_l;
103     void *buf_r;
104     TERMID term_l;
105     TERMID term_r;
106     int tail;
107 };    
108
109 static RSET rsbool_create_base( const struct rset_control *ctrl,
110             NMEM nmem, const struct key_control *kcontrol,
111             int scope, 
112             RSET rset_l, RSET rset_r)
113 {
114     RSET rnew=rset_create_base(ctrl, nmem, kcontrol, scope,0);
115     struct rset_bool_info *info;
116     info = (struct rset_bool_info *) nmem_malloc(rnew->nmem,sizeof(*info));
117     info->rset_l = rset_l;
118     info->rset_r = rset_r;
119     rnew->priv=info;
120     return rnew;
121 }
122
123
124 RSET rsbool_create_and( NMEM nmem, const struct key_control *kcontrol,
125                         int scope, 
126                         RSET rset_l, RSET rset_r)
127 {
128     return rsbool_create_base(rset_kind_and, nmem, kcontrol,
129                               scope,
130                               rset_l, rset_r);
131 }
132
133 RSET rsbool_create_or( NMEM nmem, const struct key_control *kcontrol,
134                         int scope, 
135                        RSET rset_l, RSET rset_r)
136 {
137     return rsbool_create_base(rset_kind_or, nmem, kcontrol,
138                               scope,
139                               rset_l, rset_r);
140 }
141
142 RSET rsbool_create_not( NMEM nmem, const struct key_control *kcontrol,
143                         int scope, 
144                         RSET rset_l, RSET rset_r)
145 {
146     return rsbool_create_base(rset_kind_not, nmem, kcontrol,
147                               scope, 
148                               rset_l, rset_r);
149 }
150
151 static void r_delete (RSET ct)
152 {
153     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
154     rset_delete (info->rset_l);
155     rset_delete (info->rset_r);
156 }
157
158
159 static RSFD r_open (RSET ct, int flag)
160 {
161     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
162     RSFD rfd;
163     struct rset_bool_rfd *p;
164    
165
166     if (flag & RSETF_WRITE)
167     {
168         yaz_log (YLOG_FATAL, "bool set type is read-only");
169         return NULL;
170     }
171     rfd = rfd_create_base(ct);
172     if (rfd->priv)
173         p=(struct rset_bool_rfd *)rfd->priv;
174     else {
175         p=nmem_malloc(ct->nmem,sizeof(*p));
176         rfd->priv=p;
177         p->buf_l = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
178         p->buf_r = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
179     }
180
181     yaz_log(YLOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
182     p->hits=0;
183
184     p->rfd_l = rset_open (info->rset_l, RSETF_READ);
185     p->rfd_r = rset_open (info->rset_r, RSETF_READ);
186     p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
187     p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
188     p->tail = 0;
189     return rfd;
190 }
191
192 static void r_close (RSFD rfd)
193 {
194  /* struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv); */
195     struct rset_bool_rfd *prfd=(struct rset_bool_rfd *)rfd->priv;
196
197     rset_close (prfd->rfd_l);
198     rset_close (prfd->rfd_r);
199     rfd_delete_base(rfd);
200 }
201
202
203
204 static int r_forward (RSFD rfd, void *buf, TERMID *term,
205                      const void *untilbuf)
206 {
207     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
208     const struct key_control *kctrl=rfd->rset->keycontrol;
209
210     if ( p->more_l && ((kctrl->cmp)(untilbuf,p->buf_l)>=rfd->rset->scope) )
211         p->more_l = rset_forward(p->rfd_l, p->buf_l, &p->term_l, untilbuf);
212     if ( p->more_r && ((kctrl->cmp)(untilbuf,p->buf_r)>=rfd->rset->scope))
213         p->more_r = rset_forward(p->rfd_r, p->buf_r, &p->term_r, untilbuf);
214     p->tail=0; 
215     return rset_read(rfd,buf,term); 
216 }
217
218
219 /*
220     1,1         1,3
221     1,9         2,1
222     1,11        3,1
223     2,9
224
225   1,1     1,1
226   1,3     1,3
227           1,9
228           1,11
229   2,1     2,1
230           2,9
231           3,1
232 */
233
234 static int r_read_and (RSFD rfd, void *buf, TERMID *term)
235 {
236     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
237     const struct key_control *kctrl=rfd->rset->keycontrol;
238
239     while (p->more_l || p->more_r)
240     {
241         int cmp;
242
243         if (p->more_l && p->more_r)
244             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
245         else if (p->more_l)
246             cmp = -rfd->rset->scope;
247         else
248             cmp = rfd->rset->scope;
249 #if RSET_DEBUG
250         yaz_log (YLOG_DEBUG, "r_read_and [%p] looping: m=%d/%d c=%d t=%d",
251                         rfd, p->more_l, p->more_r, cmp, p->tail);
252         (*kctrl->log_item)(YLOG_DEBUG, p->buf_l, "left ");
253         (*kctrl->log_item)(YLOG_DEBUG, p->buf_r, "right ");
254 #endif
255         if (!cmp)
256         {  /* cmp==0 */
257             memcpy (buf, p->buf_l, kctrl->key_size);
258             if (term)
259                 *term=p->term_l;
260             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
261             p->tail = 1;
262         }
263         else if ( (cmp>0) && (cmp<rfd->rset->scope))
264         {  /* typically cmp == 1 */
265             memcpy (buf, p->buf_r, kctrl->key_size);
266             if (term)
267                 *term=p->term_r;
268             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
269             p->tail = 1;
270 #if RSET_DEBUG
271             yaz_log (YLOG_DEBUG, "r_read_and [%p] returning R m=%d/%d c=%d",
272                     rfd, p->more_l, p->more_r, cmp);
273             key_logdump(YLOG_DEBUG,buf);
274             (*kctrl->log_item)(YLOG_DEBUG, buf, "");
275 #endif
276             p->hits++;
277             return 1;
278         }
279         else if ( (cmp<0) && (-cmp<rfd->rset->scope))
280         {  /* cmp == -1 */
281             memcpy (buf, p->buf_l, kctrl->key_size);
282             if (term)
283                 *term=p->term_l;
284             p->more_l = rset_read (p->rfd_l, p->buf_l,&p->term_l);
285             p->tail = 1;
286 #if RSET_DEBUG
287             yaz_log (YLOG_DEBUG, "r_read_and [%p] returning L m=%d/%d c=%d",
288                     rfd, p->more_l, p->more_r, cmp);
289             (*kctrl->log_item)(YLOG_DEBUG, buf, "");
290 #endif
291             p->hits++;
292             return 1;
293         }
294         else if (cmp >= rfd->rset->scope )  
295         {  /* cmp == 2 */
296             if (p->tail)
297             {
298                 memcpy (buf, p->buf_r, kctrl->key_size);
299                 if (term)
300                     *term=p->term_r;
301                 p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
302                 if (!p->more_r || (*kctrl->cmp)(p->buf_r, buf) > 1)
303                     p->tail = 0;
304 #if RSET_DEBUG
305                 yaz_log (YLOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
306                         rfd, p->more_l, p->more_r, cmp);
307                 (*kctrl->log_item)(YLOG_DEBUG, buf, "");
308 #endif
309                 p->hits++;
310                 return 1;
311             }
312             else
313             {
314 #if RSET_DEBUG
315                 yaz_log (YLOG_DEBUG, "r_read_and [%p] about to forward R "
316                                  "m=%d/%d c=%d",
317                         rfd, p->more_l, p->more_r, cmp);
318 #endif
319                 if (p->more_r && p->more_l)
320                     p->more_r = rset_forward( p->rfd_r, p->buf_r,
321                              &p->term_r, p->buf_l);
322                 else 
323                     return 0; /* no point in reading further */
324             }
325         }
326         else  
327         { /* cmp == -2 */
328             if (p->tail)
329             {
330                 memcpy (buf, p->buf_l, kctrl->key_size);
331                 if (term)
332                     *term=p->term_l;
333                 p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
334                 if (!p->more_l || (*kctrl->cmp)(p->buf_l, buf) > 1)
335                     p->tail = 0;
336 #if RSET_DEBUG
337                 yaz_log (YLOG_DEBUG, "r_read_and [%p] returning L tail m=%d/%d c=%d",
338                         rfd, p->more_l, p->more_r, cmp);
339                 (*kctrl->log_item)(YLOG_DEBUG, buf, "");
340 #endif
341                 p->hits++;
342                 return 1;
343             }
344             else
345             {
346 #if RSET_DEBUG
347                 yaz_log (YLOG_DEBUG, "r_read_and [%p] about to forward L "
348                                  "m=%d/%d c=%d",
349                         rfd, p->more_l, p->more_r, cmp);
350 #endif
351                 if (p->more_r && p->more_l)
352                     p->more_l = rset_forward(p->rfd_l, p->buf_l, 
353                                  &p->term_l, p->buf_r);
354                 else 
355                     return 0; /* no point in reading further */
356             }
357         }
358     }
359 #if RSET_DEBUG
360     yaz_log (YLOG_DEBUG, "r_read_and [%p] reached its end",rfd);
361 #endif
362     return 0;
363 }
364
365 static int r_read_or (RSFD rfd, void *buf, TERMID *term)
366 {
367     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
368     const struct key_control *kctrl=rfd->rset->keycontrol;
369
370     while (p->more_l || p->more_r)
371     {
372         int cmp;
373
374         if (p->more_l && p->more_r)
375             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
376         else if (p->more_r)
377             cmp = rfd->rset->scope;
378         else
379             cmp = -rfd->rset->scope;
380         if (!cmp)
381         { /* cmp==0 */
382             memcpy (buf, p->buf_l, kctrl->key_size);
383             if (term)
384                 *term=p->term_l;
385             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
386             /* FIXME - is this right, should we not leave _r as it is */
387             /* and return that in the next read, so that ranking etc */
388             /* get to see both? */
389             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
390 #if RSET_DEBUG
391             yaz_log (YLOG_DEBUG, "r_read_or returning A m=%d/%d c=%d",
392                     p->more_l, p->more_r, cmp);
393             (*kctrl->log_item)(YLOG_DEBUG, buf, "");
394 #endif
395             p->hits++;
396             return 1;
397         }
398         else if (cmp > 0)
399         {
400             memcpy (buf, p->buf_r, kctrl->key_size);
401             if (term)
402                 *term=p->term_r;
403             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
404 #if RSET_DEBUG
405             yaz_log (YLOG_DEBUG, "r_read_or returning B m=%d/%d c=%d",
406                     p->more_l, p->more_r, cmp);
407             (*kctrl->log_item)(YLOG_DEBUG, buf, "");
408 #endif
409             p->hits++;
410             return 1;
411         }
412         else
413         {
414             memcpy (buf, p->buf_l, kctrl->key_size);
415             if (term)
416                 *term=p->term_l;
417             p->more_l = rset_read ( p->rfd_l, p->buf_l, &p->term_l);
418 #if RSET_DEBUG
419             yaz_log (YLOG_DEBUG, "r_read_or returning C m=%d/%d c=%d",
420                     p->more_l, p->more_r, cmp);
421             (*kctrl->log_item)(YLOG_DEBUG, buf, "");
422 #endif
423             p->hits++;
424             return 1;
425         }
426     }
427     return 0;
428 }
429
430 static int r_read_not (RSFD rfd, void *buf, TERMID *term)
431 {
432     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
433     const struct key_control *kctrl=rfd->rset->keycontrol;
434
435     while (p->more_l || p->more_r)
436     {
437         int cmp;
438
439         if (p->more_l && p->more_r)
440             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
441         else if (p->more_r)
442             cmp = rfd->rset->scope;
443         else
444             cmp = -rfd->rset->scope;
445
446         if (cmp <= -rfd->rset->scope)
447         { /* cmp == -2 */
448             memcpy (buf, p->buf_l, kctrl->key_size);
449             if (term)
450                 *term=p->term_l;
451             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
452             p->hits++;
453             return 1;
454         }
455         else if (cmp >= rfd->rset->scope)   /* cmp >1 */
456             p->more_r = rset_forward( p->rfd_r, p->buf_r, 
457                           &p->term_r, p->buf_l);
458         else
459         { /* cmp== -1, 0, or 1 */
460             memcpy (buf, p->buf_l, kctrl->key_size);
461             if (term)
462                 *term=p->term_l;
463             do
464             { 
465                 p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
466                 if (!p->more_l)
467                     break;
468                 cmp = (*kctrl->cmp)(p->buf_l, buf);
469             } while (abs(cmp)<rfd->rset->scope);
470                 /*  (cmp >= -1 && cmp <= 1) */
471             do
472             {
473                 p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
474                 if (!p->more_r)
475                     break;
476                 cmp = (*kctrl->cmp)(p->buf_r, buf);
477             } while (abs(cmp)<rfd->rset->scope);
478                /* (cmp >= -1 && cmp <= 1) */
479         }
480     }
481     return 0;
482 }
483
484
485 static int r_write (RSFD rfd, const void *buf)
486 {
487     yaz_log (YLOG_FATAL, "bool set type is read-only");
488     return -1;
489 }
490
491 static void r_pos (RSFD rfd, double *current, double *total)
492 {
493     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
494     double lcur,ltot;
495     double rcur,rtot;
496     double r;
497     ltot=-1; rtot=-1;
498     rset_pos(p->rfd_l,  &lcur, &ltot);
499     rset_pos(p->rfd_r,  &rcur, &rtot);
500     if ( (rtot<0) && (ltot<0)) { /*no position */
501         *current=rcur;  /* return same as you got */
502         *total=rtot;    /* probably -1 for not available */
503     }
504     if ( rtot<0) { rtot=0; rcur=0;} /* if only one useful, use it */
505     if ( ltot<0) { ltot=0; lcur=0;}
506     if ( rtot+ltot < 1 ) { /* empty rset */
507         *current=0;
508         *total=0;
509         return;
510     }
511     r=1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
512     *current=(double) (p->hits);
513     *total=*current/r ; 
514 #if RSET_DEBUG
515     yaz_log(YLOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
516                     info->rset_l->control->desc, info->rset_r->control->desc,
517                     *current, *total, r);
518 #endif
519 }
520
521 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm)
522 {
523     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
524     rset_getterms(info->rset_l, terms, maxterms, curterm);
525     rset_getterms(info->rset_r, terms, maxterms, curterm);
526 }
527