Happy new year.
[idzebra-moved-to-github.git] / rset / rsbool.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2011 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24
25 #include <idzebra/util.h>
26 #include <rset.h>
27
28 #ifndef RSET_DEBUG
29 #define RSET_DEBUG 0
30 #endif
31
32 static RSFD r_open(RSET ct, int flag);
33 static void r_close(RSFD rfd);
34 static void r_delete(RSET ct);
35 static int r_forward(RSFD rfd, void *buf, TERMID *term, const void *untilbuf);
36 static void r_pos(RSFD rfd, double *current, double *total); 
37 static int r_read_not(RSFD rfd, void *buf, TERMID *term);
38 static int r_write(RSFD rfd, const void *buf);
39 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm);
40
41 static const struct rset_control control_not = 
42 {
43     "not",
44     r_delete,
45     r_get_terms,
46     r_open,
47     r_close,
48     r_forward, 
49     r_pos,
50     r_read_not,
51     r_write,
52 };
53
54 struct rset_private {
55     RSET rset_l;
56     RSET rset_r;
57 };
58
59 struct rfd_private {
60     zint hits;
61     RSFD rfd_l;
62     RSFD rfd_r;
63     int  more_l;
64     int  more_r;
65     void *buf_l;
66     void *buf_r;
67     TERMID term_l;
68     TERMID term_r;
69     int tail;
70 };    
71
72 static RSET rsbool_create_base(const struct rset_control *ctrl,
73                                NMEM nmem,
74                                struct rset_key_control *kcontrol,
75                                int scope, RSET rset_l, RSET rset_r)
76 {
77     RSET children[2], rnew;
78     struct rset_private *info;
79
80     children[0] = rset_l;
81     children[1] = rset_r;
82     rnew = rset_create_base(ctrl, nmem, kcontrol, scope, 0, 2, children);
83     info = (struct rset_private *) nmem_malloc(rnew->nmem, sizeof(*info));
84     info->rset_l = rset_l;
85     info->rset_r = rset_r;
86     rnew->priv = info;
87     return rnew;
88 }
89
90 RSET rset_create_not(NMEM nmem, struct rset_key_control *kcontrol,
91                      int scope, RSET rset_l, RSET rset_r)
92 {
93     return rsbool_create_base(&control_not, nmem, kcontrol,
94                               scope, rset_l, rset_r);
95 }
96
97 static void r_delete(RSET ct)
98 {
99 }
100
101 static RSFD r_open(RSET ct, int flag)
102 {
103     struct rset_private *info = (struct rset_private *) ct->priv;
104     RSFD rfd;
105     struct rfd_private *p;
106
107     if (flag & RSETF_WRITE)
108     {
109         yaz_log(YLOG_FATAL, "bool set type is read-only");
110         return NULL;
111     }
112     rfd = rfd_create_base(ct);
113     if (rfd->priv)
114         p = (struct rfd_private *)rfd->priv;
115     else {
116         p = nmem_malloc(ct->nmem,sizeof(*p));
117         rfd->priv = p;
118         p->buf_l = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
119         p->buf_r = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
120     }
121
122     yaz_log(YLOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
123     p->hits=0;
124
125     p->rfd_l = rset_open (info->rset_l, RSETF_READ);
126     p->rfd_r = rset_open (info->rset_r, RSETF_READ);
127     p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
128     p->more_r = rset_read(p->rfd_r, p->buf_r, &p->term_r);
129     p->tail = 0;
130     return rfd;
131 }
132
133 static void r_close (RSFD rfd)
134 {
135     struct rfd_private *prfd=(struct rfd_private *)rfd->priv;
136
137     rset_close (prfd->rfd_l);
138     rset_close (prfd->rfd_r);
139 }
140
141 static int r_forward(RSFD rfd, void *buf, TERMID *term,
142                      const void *untilbuf)
143 {
144     struct rfd_private *p = (struct rfd_private *)rfd->priv;
145     const struct rset_key_control *kctrl=rfd->rset->keycontrol;
146
147     if ( p->more_l && ((kctrl->cmp)(untilbuf,p->buf_l)>=rfd->rset->scope) )
148         p->more_l = rset_forward(p->rfd_l, p->buf_l, &p->term_l, untilbuf);
149     if ( p->more_r && ((kctrl->cmp)(untilbuf,p->buf_r)>=rfd->rset->scope))
150         p->more_r = rset_forward(p->rfd_r, p->buf_r, &p->term_r, untilbuf);
151     p->tail = 0; 
152     return rset_read(rfd,buf,term); 
153 }
154
155
156 /*
157     1,1         1,3
158     1,9         2,1
159     1,11        3,1
160     2,9
161
162   1,1     1,1
163   1,3     1,3
164           1,9
165           1,11
166   2,1     2,1
167           2,9
168           3,1
169 */
170
171 static int r_read_not(RSFD rfd, void *buf, TERMID *term)
172 {
173     struct rfd_private *p = (struct rfd_private *)rfd->priv;
174     const struct rset_key_control *kctrl = rfd->rset->keycontrol;
175
176     while (p->more_l)
177     {
178         int cmp;
179
180         if (p->more_r)
181             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
182         else
183             cmp = -rfd->rset->scope;
184
185         if (cmp <= -rfd->rset->scope)
186         { /* cmp == -2 */
187             memcpy (buf, p->buf_l, kctrl->key_size);
188             if (term)
189                 *term=p->term_l;
190             p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
191             p->hits++;
192             return 1;
193         }
194         else if (cmp >= rfd->rset->scope)   /* cmp >1 */
195         {
196             p->more_r = rset_forward( p->rfd_r, p->buf_r, 
197                                       &p->term_r, p->buf_l);
198         }
199         else
200         { /* cmp== -1, 0, or 1 */
201             memcpy (buf, p->buf_l, kctrl->key_size);
202             if (term)
203                 *term = p->term_l;
204             do
205             { 
206                 p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
207                 if (!p->more_l)
208                     break;
209                 cmp = (*kctrl->cmp)(p->buf_l, buf);
210             } while (abs(cmp)<rfd->rset->scope);
211                 /*  (cmp >= -1 && cmp <= 1) */
212             do
213             {
214                 p->more_r = rset_read(p->rfd_r, p->buf_r, &p->term_r);
215                 if (!p->more_r)
216                     break;
217                 cmp = (*kctrl->cmp)(p->buf_r, buf);
218             } while (abs(cmp)<rfd->rset->scope);
219                /* (cmp >= -1 && cmp <= 1) */
220         }
221     }
222     return 0;
223 }
224
225
226 static int r_write(RSFD rfd, const void *buf)
227 {
228     yaz_log(YLOG_FATAL, "bool set type is read-only");
229     return -1;
230 }
231
232 static void r_pos(RSFD rfd, double *current, double *total)
233 {
234     struct rfd_private *p = (struct rfd_private *)rfd->priv;
235     double lcur, ltot;
236     double rcur, rtot;
237     double r;
238     ltot = -1;
239     rtot = -1;
240     rset_pos(p->rfd_l, &lcur, &ltot);
241     rset_pos(p->rfd_r, &rcur, &rtot);
242     if ( (rtot<0) && (ltot<0)) { /*no position */
243         *current = rcur;  /* return same as you got */
244         *total = rtot;    /* probably -1 for not available */
245     }
246     if (rtot < 0) 
247         rtot = rcur = 0; /* if only one useful, use it */ 
248     if (ltot < 0) 
249         ltot = lcur = 0;
250     if (rtot+ltot < 1) 
251     {   /* empty rset */
252         *current = *total = 0;
253         return;
254     }
255     r = 1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
256     *current = (double) (p->hits);
257     *total = *current/r ; 
258 #if RSET_DEBUG
259     yaz_log(YLOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
260                     info->rset_l->control->desc, info->rset_r->control->desc,
261                     *current, *total, r);
262 #endif
263 }
264
265 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm)
266 {
267     struct rset_private *info = (struct rset_private *) ct->priv;
268     rset_getterms(info->rset_l, terms, maxterms, curterm);
269     rset_getterms(info->rset_r, terms, maxterms, curterm);
270 }
271
272 /*
273  * Local variables:
274  * c-basic-offset: 4
275  * c-file-style: "Stroustrup"
276  * indent-tabs-mode: nil
277  * End:
278  * vim: shiftwidth=4 tabstop=8 expandtab
279  */
280