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