Next wave of _63 VMS patches
[p5sagit/p5-mst-13.2.git] / ext / SDBM_File / sdbm / pair.c
1 /*
2  * sdbm - ndbm work-alike hashed database library
3  * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
4  * author: oz@nexus.yorku.ca
5  * status: public domain.
6  *
7  * page-level routines
8  */
9
10 #ifndef lint
11 static char rcsid[] = "$Id: pair.c,v 1.10 90/12/13 13:00:35 oz Exp $";
12 #endif
13
14 #include "config.h"
15 #include "EXTERN.h"
16 #include "sdbm.h"
17 #include "tune.h"
18 #include "pair.h"
19
20 #define exhash(item)    sdbm_hash((item).dptr, (item).dsize)
21
22 /* 
23  * forward 
24  */
25 static int seepair proto((char *, int, char *, int));
26
27 /*
28  * page format:
29  *      +------------------------------+
30  * ino  | n | keyoff | datoff | keyoff |
31  *      +------------+--------+--------+
32  *      | datoff | - - - ---->         |
33  *      +--------+---------------------+
34  *      |        F R E E A R E A       |
35  *      +--------------+---------------+
36  *      |  <---- - - - | data          |
37  *      +--------+-----+----+----------+
38  *      |  key   | data     | key      |
39  *      +--------+----------+----------+
40  *
41  * calculating the offsets for free area:  if the number
42  * of entries (ino[0]) is zero, the offset to the END of
43  * the free area is the block size. Otherwise, it is the
44  * nth (ino[ino[0]]) entry's offset.
45  */
46
47 int
48 fitpair(char *pag, int need)
49 {
50         register int n;
51         register int off;
52         register int free;
53         register short *ino = (short *) pag;
54
55         off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
56         free = off - (n + 1) * sizeof(short);
57         need += 2 * sizeof(short);
58
59         debug(("free %d need %d\n", free, need));
60
61         return need <= free;
62 }
63
64 void
65 putpair(char *pag, datum key, datum val)
66 {
67         register int n;
68         register int off;
69         register short *ino = (short *) pag;
70
71         off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
72 /*
73  * enter the key first
74  */
75         off -= key.dsize;
76         (void) memcpy(pag + off, key.dptr, key.dsize);
77         ino[n + 1] = off;
78 /*
79  * now the data
80  */
81         off -= val.dsize;
82         (void) memcpy(pag + off, val.dptr, val.dsize);
83         ino[n + 2] = off;
84 /*
85  * adjust item count
86  */
87         ino[0] += 2;
88 }
89
90 datum
91 getpair(char *pag, datum key)
92 {
93         register int i;
94         register int n;
95         datum val;
96         register short *ino = (short *) pag;
97
98         if ((n = ino[0]) == 0)
99                 return nullitem;
100
101         if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
102                 return nullitem;
103
104         val.dptr = pag + ino[i + 1];
105         val.dsize = ino[i] - ino[i + 1];
106         return val;
107 }
108
109 #ifdef SEEDUPS
110 int
111 duppair(char *pag, datum key)
112 {
113         register short *ino = (short *) pag;
114         return ino[0] > 0 && seepair(pag, ino[0], key.dptr, key.dsize) > 0;
115 }
116 #endif
117
118 datum
119 getnkey(char *pag, int num)
120 {
121         datum key;
122         register int off;
123         register short *ino = (short *) pag;
124
125         num = num * 2 - 1;
126         if (ino[0] == 0 || num > ino[0])
127                 return nullitem;
128
129         off = (num > 1) ? ino[num - 1] : PBLKSIZ;
130
131         key.dptr = pag + ino[num];
132         key.dsize = off - ino[num];
133
134         return key;
135 }
136
137 int
138 delpair(char *pag, datum key)
139 {
140         register int n;
141         register int i;
142         register short *ino = (short *) pag;
143
144         if ((n = ino[0]) == 0)
145                 return 0;
146
147         if ((i = seepair(pag, n, key.dptr, key.dsize)) == 0)
148                 return 0;
149 /*
150  * found the key. if it is the last entry
151  * [i.e. i == n - 1] we just adjust the entry count.
152  * hard case: move all data down onto the deleted pair,
153  * shift offsets onto deleted offsets, and adjust them.
154  * [note: 0 < i < n]
155  */
156         if (i < n - 1) {
157                 register int m;
158                 register char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]);
159                 register char *src = pag + ino[i + 1];
160                 register int   zoo = dst - src;
161
162                 debug(("free-up %d ", zoo));
163 /*
164  * shift data/keys down
165  */
166                 m = ino[i + 1] - ino[n];
167 #ifdef DUFF
168 #define MOVB    *--dst = *--src
169
170                 if (m > 0) {
171                         register int loop = (m + 8 - 1) >> 3;
172
173                         switch (m & (8 - 1)) {
174                         case 0: do {
175                                 MOVB;   case 7: MOVB;
176                         case 6: MOVB;   case 5: MOVB;
177                         case 4: MOVB;   case 3: MOVB;
178                         case 2: MOVB;   case 1: MOVB;
179                                 } while (--loop);
180                         }
181                 }
182 #else
183 #ifdef HAS_MEMMOVE
184                 dst -= m;
185                 src -= m;
186                 memmove(dst, src, m);
187 #else
188                 while (m--)
189                         *--dst = *--src;
190 #endif
191 #endif
192 /*
193  * adjust offset index up
194  */
195                 while (i < n - 1) {
196                         ino[i] = ino[i + 2] + zoo;
197                         i++;
198                 }
199         }
200         ino[0] -= 2;
201         return 1;
202 }
203
204 /*
205  * search for the key in the page.
206  * return offset index in the range 0 < i < n.
207  * return 0 if not found.
208  */
209 static int
210 seepair(char *pag, register int n, register char *key, register int siz)
211 {
212         register int i;
213         register int off = PBLKSIZ;
214         register short *ino = (short *) pag;
215
216         for (i = 1; i < n; i += 2) {
217                 if (siz == off - ino[i] &&
218                     memEQ(key, pag + ino[i], siz))
219                         return i;
220                 off = ino[i + 1];
221         }
222         return 0;
223 }
224
225 void
226 splpage(char *pag, char *New, long int sbit)
227 {
228         datum key;
229         datum val;
230
231         register int n;
232         register int off = PBLKSIZ;
233         char cur[PBLKSIZ];
234         register short *ino = (short *) cur;
235
236         (void) memcpy(cur, pag, PBLKSIZ);
237         (void) memset(pag, 0, PBLKSIZ);
238         (void) memset(New, 0, PBLKSIZ);
239
240         n = ino[0];
241         for (ino++; n > 0; ino += 2) {
242                 key.dptr = cur + ino[0]; 
243                 key.dsize = off - ino[0];
244                 val.dptr = cur + ino[1];
245                 val.dsize = ino[0] - ino[1];
246 /*
247  * select the page pointer (by looking at sbit) and insert
248  */
249                 (void) putpair((exhash(key) & sbit) ? New : pag, key, val);
250
251                 off = ino[1];
252                 n -= 2;
253         }
254
255         debug(("%d split %d/%d\n", ((short *) cur)[0] / 2, 
256                ((short *) New)[0] / 2,
257                ((short *) pag)[0] / 2));
258 }
259
260 /*
261  * check page sanity: 
262  * number of entries should be something
263  * reasonable, and all offsets in the index should be in order.
264  * this could be made more rigorous.
265  */
266 int
267 chkpage(char *pag)
268 {
269         register int n;
270         register int off;
271         register short *ino = (short *) pag;
272
273         if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof(short))
274                 return 0;
275
276         if (n > 0) {
277                 off = PBLKSIZ;
278                 for (ino++; n > 0; ino += 2) {
279                         if (ino[0] > off || ino[1] > off ||
280                             ino[1] > ino[0])
281                                 return 0;
282                         off = ino[1];
283                         n -= 2;
284                 }
285         }
286         return 1;
287 }