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