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