zebrasrv: sortkeys args are optional
[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 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
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_not(RSFD rfd, void *buf, TERMID *term);
41 static int r_write(RSFD rfd, const void *buf);
42 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm);
43
44 static const struct rset_control control_not = 
45 {
46     "not",
47     r_delete,
48     r_get_terms,
49     r_open,
50     r_close,
51     r_forward, 
52     r_pos,
53     r_read_not,
54     r_write,
55 };
56
57 struct rset_private {
58     RSET rset_l;
59     RSET rset_r;
60 };
61
62 struct rfd_private {
63     zint hits;
64     RSFD rfd_l;
65     RSFD rfd_r;
66     int  more_l;
67     int  more_r;
68     void *buf_l;
69     void *buf_r;
70     TERMID term_l;
71     TERMID term_r;
72     int tail;
73 };    
74
75 static RSET rsbool_create_base(const struct rset_control *ctrl,
76                                NMEM nmem,
77                                struct rset_key_control *kcontrol,
78                                int scope, RSET rset_l, RSET rset_r)
79 {
80     RSET children[2], rnew;
81     struct rset_private *info;
82
83     children[0] = rset_l;
84     children[1] = rset_r;
85     rnew = rset_create_base(ctrl, nmem, kcontrol, scope, 0, 2, children);
86     info = (struct rset_private *) nmem_malloc(rnew->nmem, sizeof(*info));
87     info->rset_l = rset_l;
88     info->rset_r = rset_r;
89     rnew->priv = info;
90     return rnew;
91 }
92
93 RSET rset_create_not(NMEM nmem, struct rset_key_control *kcontrol,
94                      int scope, RSET rset_l, RSET rset_r)
95 {
96     return rsbool_create_base(&control_not, nmem, kcontrol,
97                               scope, rset_l, rset_r);
98 }
99
100 static void r_delete(RSET ct)
101 {
102 }
103
104 static RSFD r_open(RSET ct, int flag)
105 {
106     struct rset_private *info = (struct rset_private *) ct->priv;
107     RSFD rfd;
108     struct rfd_private *p;
109
110     if (flag & RSETF_WRITE)
111     {
112         yaz_log(YLOG_FATAL, "bool set type is read-only");
113         return NULL;
114     }
115     rfd = rfd_create_base(ct);
116     if (rfd->priv)
117         p = (struct rfd_private *)rfd->priv;
118     else {
119         p = nmem_malloc(ct->nmem,sizeof(*p));
120         rfd->priv = p;
121         p->buf_l = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
122         p->buf_r = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
123     }
124
125     yaz_log(YLOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
126     p->hits=0;
127
128     p->rfd_l = rset_open (info->rset_l, RSETF_READ);
129     p->rfd_r = rset_open (info->rset_r, RSETF_READ);
130     p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
131     p->more_r = rset_read(p->rfd_r, p->buf_r, &p->term_r);
132     p->tail = 0;
133     return rfd;
134 }
135
136 static void r_close (RSFD rfd)
137 {
138     struct rfd_private *prfd=(struct rfd_private *)rfd->priv;
139
140     rset_close (prfd->rfd_l);
141     rset_close (prfd->rfd_r);
142 }
143
144 static int r_forward(RSFD rfd, void *buf, TERMID *term,
145                      const void *untilbuf)
146 {
147     struct rfd_private *p = (struct rfd_private *)rfd->priv;
148     const struct rset_key_control *kctrl=rfd->rset->keycontrol;
149
150     if ( p->more_l && ((kctrl->cmp)(untilbuf,p->buf_l)>=rfd->rset->scope) )
151         p->more_l = rset_forward(p->rfd_l, p->buf_l, &p->term_l, untilbuf);
152     if ( p->more_r && ((kctrl->cmp)(untilbuf,p->buf_r)>=rfd->rset->scope))
153         p->more_r = rset_forward(p->rfd_r, p->buf_r, &p->term_r, untilbuf);
154     p->tail = 0; 
155     return rset_read(rfd,buf,term); 
156 }
157
158
159 /*
160     1,1         1,3
161     1,9         2,1
162     1,11        3,1
163     2,9
164
165   1,1     1,1
166   1,3     1,3
167           1,9
168           1,11
169   2,1     2,1
170           2,9
171           3,1
172 */
173
174 static int r_read_not(RSFD rfd, void *buf, TERMID *term)
175 {
176     struct rfd_private *p = (struct rfd_private *)rfd->priv;
177     const struct rset_key_control *kctrl = rfd->rset->keycontrol;
178
179     while (p->more_l)
180     {
181         int cmp;
182
183         if (p->more_r)
184             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
185         else
186             cmp = -rfd->rset->scope;
187
188         if (cmp <= -rfd->rset->scope)
189         { /* cmp == -2 */
190             memcpy (buf, p->buf_l, kctrl->key_size);
191             if (term)
192                 *term=p->term_l;
193             p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
194             p->hits++;
195             return 1;
196         }
197         else if (cmp >= rfd->rset->scope)   /* cmp >1 */
198         {
199             p->more_r = rset_forward( p->rfd_r, p->buf_r, 
200                                       &p->term_r, p->buf_l);
201         }
202         else
203         { /* cmp== -1, 0, or 1 */
204             memcpy (buf, p->buf_l, kctrl->key_size);
205             if (term)
206                 *term = p->term_l;
207             do
208             { 
209                 p->more_l = rset_read(p->rfd_l, p->buf_l, &p->term_l);
210                 if (!p->more_l)
211                     break;
212                 cmp = (*kctrl->cmp)(p->buf_l, buf);
213             } while (abs(cmp)<rfd->rset->scope);
214                 /*  (cmp >= -1 && cmp <= 1) */
215             do
216             {
217                 p->more_r = rset_read(p->rfd_r, p->buf_r, &p->term_r);
218                 if (!p->more_r)
219                     break;
220                 cmp = (*kctrl->cmp)(p->buf_r, buf);
221             } while (abs(cmp)<rfd->rset->scope);
222                /* (cmp >= -1 && cmp <= 1) */
223         }
224     }
225     return 0;
226 }
227
228
229 static int r_write(RSFD rfd, const void *buf)
230 {
231     yaz_log(YLOG_FATAL, "bool set type is read-only");
232     return -1;
233 }
234
235 static void r_pos(RSFD rfd, double *current, double *total)
236 {
237     struct rfd_private *p = (struct rfd_private *)rfd->priv;
238     double lcur, ltot;
239     double rcur, rtot;
240     double r;
241     ltot = -1;
242     rtot = -1;
243     rset_pos(p->rfd_l, &lcur, &ltot);
244     rset_pos(p->rfd_r, &rcur, &rtot);
245     if ( (rtot<0) && (ltot<0)) { /*no position */
246         *current = rcur;  /* return same as you got */
247         *total = rtot;    /* probably -1 for not available */
248     }
249     if (rtot < 0) 
250         rtot = rcur = 0; /* if only one useful, use it */ 
251     if (ltot < 0) 
252         ltot = lcur = 0;
253     if (rtot+ltot < 1) 
254     {   /* empty rset */
255         *current = *total = 0;
256         return;
257     }
258     r = 1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
259     *current = (double) (p->hits);
260     *total = *current/r ; 
261 #if RSET_DEBUG
262     yaz_log(YLOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
263                     info->rset_l->control->desc, info->rset_r->control->desc,
264                     *current, *total, r);
265 #endif
266 }
267
268 static void r_get_terms(RSET ct, TERMID *terms, int maxterms, int *curterm)
269 {
270     struct rset_private *info = (struct rset_private *) ct->priv;
271     rset_getterms(info->rset_l, terms, maxterms, curterm);
272     rset_getterms(info->rset_r, terms, maxterms, curterm);
273 }
274
275 /*
276  * Local variables:
277  * c-basic-offset: 4
278  * c-file-style: "Stroustrup"
279  * indent-tabs-mode: nil
280  * End:
281  * vim: shiftwidth=4 tabstop=8 expandtab
282  */
283