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