lmdb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,348 @@
1
+ /** @file midl.c
2
+ * @brief ldap bdb back-end ID List functions */
3
+ /* $OpenLDAP$ */
4
+ /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5
+ *
6
+ * Copyright 2000-2013 The OpenLDAP Foundation.
7
+ * All rights reserved.
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, are permitted only as authorized by the OpenLDAP
11
+ * Public License.
12
+ *
13
+ * A copy of this license is available in the file LICENSE in the
14
+ * top-level directory of the distribution or, alternatively, at
15
+ * <http://www.OpenLDAP.org/license.html>.
16
+ */
17
+
18
+ #include <limits.h>
19
+ #include <string.h>
20
+ #include <stdlib.h>
21
+ #include <errno.h>
22
+ #include <sys/types.h>
23
+ #include <assert.h>
24
+ #include "midl.h"
25
+
26
+ /** @defgroup internal MDB Internals
27
+ * @{
28
+ */
29
+ /** @defgroup idls ID List Management
30
+ * @{
31
+ */
32
+ #define CMP(x,y) ( (x) < (y) ? -1 : (x) > (y) )
33
+
34
+ unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id )
35
+ {
36
+ /*
37
+ * binary search of id in ids
38
+ * if found, returns position of id
39
+ * if not found, returns first position greater than id
40
+ */
41
+ unsigned base = 0;
42
+ unsigned cursor = 1;
43
+ int val = 0;
44
+ unsigned n = ids[0];
45
+
46
+ while( 0 < n ) {
47
+ unsigned pivot = n >> 1;
48
+ cursor = base + pivot + 1;
49
+ val = CMP( ids[cursor], id );
50
+
51
+ if( val < 0 ) {
52
+ n = pivot;
53
+
54
+ } else if ( val > 0 ) {
55
+ base = cursor;
56
+ n -= pivot + 1;
57
+
58
+ } else {
59
+ return cursor;
60
+ }
61
+ }
62
+
63
+ if( val > 0 ) {
64
+ ++cursor;
65
+ }
66
+ return cursor;
67
+ }
68
+
69
+ #if 0 /* superseded by append/sort */
70
+ int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
71
+ {
72
+ unsigned x, i;
73
+
74
+ x = mdb_midl_search( ids, id );
75
+ assert( x > 0 );
76
+
77
+ if( x < 1 ) {
78
+ /* internal error */
79
+ return -2;
80
+ }
81
+
82
+ if ( x <= ids[0] && ids[x] == id ) {
83
+ /* duplicate */
84
+ assert(0);
85
+ return -1;
86
+ }
87
+
88
+ if ( ++ids[0] >= MDB_IDL_DB_MAX ) {
89
+ /* no room */
90
+ --ids[0];
91
+ return -2;
92
+
93
+ } else {
94
+ /* insert id */
95
+ for (i=ids[0]; i>x; i--)
96
+ ids[i] = ids[i-1];
97
+ ids[x] = id;
98
+ }
99
+
100
+ return 0;
101
+ }
102
+ #endif
103
+
104
+ MDB_IDL mdb_midl_alloc(int num)
105
+ {
106
+ MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
107
+ if (ids) {
108
+ *ids++ = num;
109
+ *ids = 0;
110
+ }
111
+ return ids;
112
+ }
113
+
114
+ void mdb_midl_free(MDB_IDL ids)
115
+ {
116
+ if (ids)
117
+ free(ids-1);
118
+ }
119
+
120
+ int mdb_midl_shrink( MDB_IDL *idp )
121
+ {
122
+ MDB_IDL ids = *idp;
123
+ if (*(--ids) > MDB_IDL_UM_MAX &&
124
+ (ids = realloc(ids, (MDB_IDL_UM_MAX+1) * sizeof(MDB_ID))))
125
+ {
126
+ *ids++ = MDB_IDL_UM_MAX;
127
+ *idp = ids;
128
+ return 1;
129
+ }
130
+ return 0;
131
+ }
132
+
133
+ static int mdb_midl_grow( MDB_IDL *idp, int num )
134
+ {
135
+ MDB_IDL idn = *idp-1;
136
+ /* grow it */
137
+ idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID));
138
+ if (!idn)
139
+ return ENOMEM;
140
+ *idn++ += num;
141
+ *idp = idn;
142
+ return 0;
143
+ }
144
+
145
+ int mdb_midl_need( MDB_IDL *idp, unsigned num )
146
+ {
147
+ MDB_IDL ids = *idp;
148
+ num += ids[0];
149
+ if (num > ids[-1]) {
150
+ num = (num + num/4 + (256 + 2)) & -256;
151
+ if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
152
+ return ENOMEM;
153
+ *ids++ = num -= 2;
154
+ *idp = ids;
155
+ }
156
+ return 0;
157
+ }
158
+
159
+ int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
160
+ {
161
+ MDB_IDL ids = *idp;
162
+ /* Too big? */
163
+ if (ids[0] >= ids[-1]) {
164
+ if (mdb_midl_grow(idp, MDB_IDL_UM_MAX))
165
+ return ENOMEM;
166
+ ids = *idp;
167
+ }
168
+ ids[0]++;
169
+ ids[ids[0]] = id;
170
+ return 0;
171
+ }
172
+
173
+ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
174
+ {
175
+ MDB_IDL ids = *idp;
176
+ /* Too big? */
177
+ if (ids[0] + app[0] >= ids[-1]) {
178
+ if (mdb_midl_grow(idp, app[0]))
179
+ return ENOMEM;
180
+ ids = *idp;
181
+ }
182
+ memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID));
183
+ ids[0] += app[0];
184
+ return 0;
185
+ }
186
+
187
+ int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n )
188
+ {
189
+ MDB_ID *ids = *idp, len = ids[0];
190
+ /* Too big? */
191
+ if (len + n > ids[-1]) {
192
+ if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX))
193
+ return ENOMEM;
194
+ ids = *idp;
195
+ }
196
+ ids[0] = len + n;
197
+ ids += len;
198
+ while (n)
199
+ ids[n--] = id++;
200
+ return 0;
201
+ }
202
+
203
+ /* Quicksort + Insertion sort for small arrays */
204
+
205
+ #define SMALL 8
206
+ #define SWAP(a,b) { itmp=(a); (a)=(b); (b)=itmp; }
207
+
208
+ void
209
+ mdb_midl_sort( MDB_IDL ids )
210
+ {
211
+ /* Max possible depth of int-indexed tree * 2 items/level */
212
+ int istack[sizeof(int)*CHAR_BIT * 2];
213
+ int i,j,k,l,ir,jstack;
214
+ MDB_ID a, itmp;
215
+
216
+ ir = (int)ids[0];
217
+ l = 1;
218
+ jstack = 0;
219
+ for(;;) {
220
+ if (ir - l < SMALL) { /* Insertion sort */
221
+ for (j=l+1;j<=ir;j++) {
222
+ a = ids[j];
223
+ for (i=j-1;i>=1;i--) {
224
+ if (ids[i] >= a) break;
225
+ ids[i+1] = ids[i];
226
+ }
227
+ ids[i+1] = a;
228
+ }
229
+ if (jstack == 0) break;
230
+ ir = istack[jstack--];
231
+ l = istack[jstack--];
232
+ } else {
233
+ k = (l + ir) >> 1; /* Choose median of left, center, right */
234
+ SWAP(ids[k], ids[l+1]);
235
+ if (ids[l] < ids[ir]) {
236
+ SWAP(ids[l], ids[ir]);
237
+ }
238
+ if (ids[l+1] < ids[ir]) {
239
+ SWAP(ids[l+1], ids[ir]);
240
+ }
241
+ if (ids[l] < ids[l+1]) {
242
+ SWAP(ids[l], ids[l+1]);
243
+ }
244
+ i = l+1;
245
+ j = ir;
246
+ a = ids[l+1];
247
+ for(;;) {
248
+ do i++; while(ids[i] > a);
249
+ do j--; while(ids[j] < a);
250
+ if (j < i) break;
251
+ SWAP(ids[i],ids[j]);
252
+ }
253
+ ids[l+1] = ids[j];
254
+ ids[j] = a;
255
+ jstack += 2;
256
+ if (ir-i+1 >= j-l) {
257
+ istack[jstack] = ir;
258
+ istack[jstack-1] = i;
259
+ ir = j-1;
260
+ } else {
261
+ istack[jstack] = j-1;
262
+ istack[jstack-1] = l;
263
+ l = i;
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id )
270
+ {
271
+ /*
272
+ * binary search of id in ids
273
+ * if found, returns position of id
274
+ * if not found, returns first position greater than id
275
+ */
276
+ unsigned base = 0;
277
+ unsigned cursor = 1;
278
+ int val = 0;
279
+ unsigned n = (unsigned)ids[0].mid;
280
+
281
+ while( 0 < n ) {
282
+ unsigned pivot = n >> 1;
283
+ cursor = base + pivot + 1;
284
+ val = CMP( id, ids[cursor].mid );
285
+
286
+ if( val < 0 ) {
287
+ n = pivot;
288
+
289
+ } else if ( val > 0 ) {
290
+ base = cursor;
291
+ n -= pivot + 1;
292
+
293
+ } else {
294
+ return cursor;
295
+ }
296
+ }
297
+
298
+ if( val > 0 ) {
299
+ ++cursor;
300
+ }
301
+ return cursor;
302
+ }
303
+
304
+ int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id )
305
+ {
306
+ unsigned x, i;
307
+
308
+ x = mdb_mid2l_search( ids, id->mid );
309
+ assert( x > 0 );
310
+
311
+ if( x < 1 ) {
312
+ /* internal error */
313
+ return -2;
314
+ }
315
+
316
+ if ( x <= ids[0].mid && ids[x].mid == id->mid ) {
317
+ /* duplicate */
318
+ return -1;
319
+ }
320
+
321
+ if ( ids[0].mid >= MDB_IDL_UM_MAX ) {
322
+ /* too big */
323
+ return -2;
324
+
325
+ } else {
326
+ /* insert id */
327
+ ids[0].mid++;
328
+ for (i=(unsigned)ids[0].mid; i>x; i--)
329
+ ids[i] = ids[i-1];
330
+ ids[x] = *id;
331
+ }
332
+
333
+ return 0;
334
+ }
335
+
336
+ int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id )
337
+ {
338
+ /* Too big? */
339
+ if (ids[0].mid >= MDB_IDL_UM_MAX) {
340
+ return -2;
341
+ }
342
+ ids[0].mid++;
343
+ ids[ids[0].mid] = *id;
344
+ return 0;
345
+ }
346
+
347
+ /** @} */
348
+ /** @} */
@@ -0,0 +1,177 @@
1
+ /** @file midl.h
2
+ * @brief mdb ID List header file.
3
+ *
4
+ * This file was originally part of back-bdb but has been
5
+ * modified for use in libmdb. Most of the macros defined
6
+ * in this file are unused, just left over from the original.
7
+ *
8
+ * This file is only used internally in libmdb and its definitions
9
+ * are not exposed publicly.
10
+ */
11
+ /* $OpenLDAP$ */
12
+ /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
13
+ *
14
+ * Copyright 2000-2013 The OpenLDAP Foundation.
15
+ * All rights reserved.
16
+ *
17
+ * Redistribution and use in source and binary forms, with or without
18
+ * modification, are permitted only as authorized by the OpenLDAP
19
+ * Public License.
20
+ *
21
+ * A copy of this license is available in the file LICENSE in the
22
+ * top-level directory of the distribution or, alternatively, at
23
+ * <http://www.OpenLDAP.org/license.html>.
24
+ */
25
+
26
+ #ifndef _MDB_MIDL_H_
27
+ #define _MDB_MIDL_H_
28
+
29
+ #include <stddef.h>
30
+
31
+ #ifdef __cplusplus
32
+ extern "C" {
33
+ #endif
34
+
35
+ /** @defgroup internal MDB Internals
36
+ * @{
37
+ */
38
+
39
+ /** @defgroup idls ID List Management
40
+ * @{
41
+ */
42
+ /** A generic ID number. These were entryIDs in back-bdb.
43
+ * Preferably it should have the same size as a pointer.
44
+ */
45
+ typedef size_t MDB_ID;
46
+
47
+ /** An IDL is an ID List, a sorted array of IDs. The first
48
+ * element of the array is a counter for how many actual
49
+ * IDs are in the list. In the original back-bdb code, IDLs are
50
+ * sorted in ascending order. For libmdb IDLs are sorted in
51
+ * descending order.
52
+ */
53
+ typedef MDB_ID *MDB_IDL;
54
+
55
+ /* IDL sizes - likely should be even bigger
56
+ * limiting factors: sizeof(ID), thread stack size
57
+ */
58
+ #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
59
+ #define MDB_IDL_DB_SIZE (1<<MDB_IDL_LOGN)
60
+ #define MDB_IDL_UM_SIZE (1<<(MDB_IDL_LOGN+1))
61
+
62
+ #define MDB_IDL_DB_MAX (MDB_IDL_DB_SIZE-1)
63
+ #define MDB_IDL_UM_MAX (MDB_IDL_UM_SIZE-1)
64
+
65
+ #define MDB_IDL_SIZEOF(ids) (((ids)[0]+1) * sizeof(MDB_ID))
66
+ #define MDB_IDL_IS_ZERO(ids) ( (ids)[0] == 0 )
67
+ #define MDB_IDL_CPY( dst, src ) (memcpy( dst, src, MDB_IDL_SIZEOF( src ) ))
68
+ #define MDB_IDL_FIRST( ids ) ( (ids)[1] )
69
+ #define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] )
70
+
71
+ /** Append ID to IDL. The IDL must be big enough. */
72
+ #define mdb_midl_xappend(idl, id) do { \
73
+ MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \
74
+ xidl[xlen] = (id); \
75
+ } while (0)
76
+
77
+ /** Search for an ID in an IDL.
78
+ * @param[in] ids The IDL to search.
79
+ * @param[in] id The ID to search for.
80
+ * @return The index of the first ID greater than or equal to \b id.
81
+ */
82
+ unsigned mdb_midl_search( MDB_IDL ids, MDB_ID id );
83
+
84
+ /** Allocate an IDL.
85
+ * Allocates memory for an IDL of the given size.
86
+ * @return IDL on success, NULL on failure.
87
+ */
88
+ MDB_IDL mdb_midl_alloc(int num);
89
+
90
+ /** Free an IDL.
91
+ * @param[in] ids The IDL to free.
92
+ */
93
+ void mdb_midl_free(MDB_IDL ids);
94
+
95
+ /** Shrink an IDL.
96
+ * Return the IDL to the default size if it has grown larger.
97
+ * @param[in,out] idp Address of the IDL to shrink.
98
+ * @return 0 on no change, non-zero if shrunk.
99
+ */
100
+ int mdb_midl_shrink(MDB_IDL *idp);
101
+
102
+ /** Make room for num additional elements in an IDL.
103
+ * @param[in,out] idp Address of the IDL.
104
+ * @param[in] num Number of elements to make room for.
105
+ * @return 0 on success, ENOMEM on failure.
106
+ */
107
+ int mdb_midl_need(MDB_IDL *idp, unsigned num);
108
+
109
+ /** Append an ID onto an IDL.
110
+ * @param[in,out] idp Address of the IDL to append to.
111
+ * @param[in] id The ID to append.
112
+ * @return 0 on success, ENOMEM if the IDL is too large.
113
+ */
114
+ int mdb_midl_append( MDB_IDL *idp, MDB_ID id );
115
+
116
+ /** Append an IDL onto an IDL.
117
+ * @param[in,out] idp Address of the IDL to append to.
118
+ * @param[in] app The IDL to append.
119
+ * @return 0 on success, ENOMEM if the IDL is too large.
120
+ */
121
+ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app );
122
+
123
+ /** Append an ID range onto an IDL.
124
+ * @param[in,out] idp Address of the IDL to append to.
125
+ * @param[in] id The lowest ID to append.
126
+ * @param[in] n Number of IDs to append.
127
+ * @return 0 on success, ENOMEM if the IDL is too large.
128
+ */
129
+ int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n );
130
+
131
+ /** Sort an IDL.
132
+ * @param[in,out] ids The IDL to sort.
133
+ */
134
+ void mdb_midl_sort( MDB_IDL ids );
135
+
136
+ /** An ID2 is an ID/pointer pair.
137
+ */
138
+ typedef struct MDB_ID2 {
139
+ MDB_ID mid; /**< The ID */
140
+ void *mptr; /**< The pointer */
141
+ } MDB_ID2;
142
+
143
+ /** An ID2L is an ID2 List, a sorted array of ID2s.
144
+ * The first element's \b mid member is a count of how many actual
145
+ * elements are in the array. The \b mptr member of the first element is unused.
146
+ * The array is sorted in ascending order by \b mid.
147
+ */
148
+ typedef MDB_ID2 *MDB_ID2L;
149
+
150
+ /** Search for an ID in an ID2L.
151
+ * @param[in] ids The ID2L to search.
152
+ * @param[in] id The ID to search for.
153
+ * @return The index of the first ID2 whose \b mid member is greater than or equal to \b id.
154
+ */
155
+ unsigned mdb_mid2l_search( MDB_ID2L ids, MDB_ID id );
156
+
157
+
158
+ /** Insert an ID2 into a ID2L.
159
+ * @param[in,out] ids The ID2L to insert into.
160
+ * @param[in] id The ID2 to insert.
161
+ * @return 0 on success, -1 if the ID was already present in the ID2L.
162
+ */
163
+ int mdb_mid2l_insert( MDB_ID2L ids, MDB_ID2 *id );
164
+
165
+ /** Append an ID2 into a ID2L.
166
+ * @param[in,out] ids The ID2L to append into.
167
+ * @param[in] id The ID2 to append.
168
+ * @return 0 on success, -2 if the ID2L is too big.
169
+ */
170
+ int mdb_mid2l_append( MDB_ID2L ids, MDB_ID2 *id );
171
+
172
+ /** @} */
173
+ /** @} */
174
+ #ifdef __cplusplus
175
+ }
176
+ #endif
177
+ #endif /* _MDB_MIDL_H_ */