idl_common.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* Common IDL code, used in both old and new indexing schemes */
  42. #include "back-ldbm.h"
  43. size_t idl_sizeof(IDList *idl)
  44. {
  45. return (2 + idl->b_nmax) * sizeof(ID);
  46. }
  47. NIDS idl_length(IDList *idl)
  48. {
  49. return (idl->b_nmax == ALLIDSBLOCK) ? UINT_MAX : idl->b_nids;
  50. }
  51. int idl_is_allids(IDList *idl)
  52. {
  53. return (idl->b_nmax == ALLIDSBLOCK);
  54. }
  55. IDList *
  56. idl_alloc( NIDS nids )
  57. {
  58. IDList *new;
  59. /* nmax + nids + space for the ids */
  60. new = (IDList *) slapi_ch_calloc( (2 + nids), sizeof(ID) );
  61. new->b_nmax = nids;
  62. new->b_nids = 0;
  63. return( new );
  64. }
  65. IDList *
  66. idl_allids( backend *be )
  67. {
  68. IDList *idl;
  69. idl = idl_alloc( 0 );
  70. idl->b_nmax = ALLIDSBLOCK;
  71. idl->b_nids = next_id_get( be );
  72. return( idl );
  73. }
  74. void
  75. idl_free( IDList *idl ) /* JCM - pass in ** */
  76. {
  77. if ( idl == NULL ) {
  78. return;
  79. }
  80. slapi_ch_free((void**)&idl );
  81. }
  82. /*
  83. * idl_append - append an id to an id list.
  84. *
  85. * Warning: The ID List must be maintained in order.
  86. * Use idl_insert if the id may not
  87. *
  88. * returns
  89. * 0 - appended
  90. * 1 - already in there
  91. * 2 - not enough room
  92. */
  93. int
  94. idl_append( IDList *idl, ID id)
  95. {
  96. if ( ALLIDS( idl ) || ( (idl->b_nids) && (idl->b_ids[idl->b_nids - 1] == id)) ) {
  97. return( 1 ); /* already there */
  98. }
  99. if ( idl->b_nids == idl->b_nmax ) {
  100. return( 2 ); /* not enough room */
  101. }
  102. idl->b_ids[idl->b_nids] = id;
  103. idl->b_nids++;
  104. return( 0 );
  105. }
  106. /* Append an ID to an IDL, realloc-ing the space if needs be */
  107. /* ID presented is not to be already in the IDL. */
  108. /* moved from idl_new.c */
  109. int
  110. idl_append_extend(IDList **orig_idl, ID id)
  111. {
  112. IDList *idl = *orig_idl;
  113. if (idl == NULL) {
  114. idl = idl_alloc(32); /* used to be 0 */
  115. idl_append(idl, id);
  116. *orig_idl = idl;
  117. return 0;
  118. }
  119. if ( idl->b_nids == idl->b_nmax ) {
  120. /* No more room, need to extend */
  121. /* Allocate new IDL with twice the space of this one */
  122. IDList *idl_new = NULL;
  123. idl_new = idl_alloc(idl->b_nmax * 2);
  124. if (NULL == idl_new) {
  125. return ENOMEM;
  126. }
  127. /* copy over the existing contents */
  128. idl_new->b_nids = idl->b_nids;
  129. memcpy(idl_new->b_ids, idl->b_ids, sizeof(ID) * idl->b_nids);
  130. idl_free(idl);
  131. idl = idl_new;
  132. }
  133. idl->b_ids[idl->b_nids] = id;
  134. idl->b_nids++;
  135. *orig_idl = idl;
  136. return 0;
  137. }
  138. static IDList *
  139. idl_dup( IDList *idl )
  140. {
  141. IDList *new;
  142. if ( idl == NULL ) {
  143. return( NULL );
  144. }
  145. new = idl_alloc( idl->b_nmax );
  146. SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2)
  147. * sizeof(ID) );
  148. return( new );
  149. }
  150. static IDList *
  151. idl_min( IDList *a, IDList *b )
  152. {
  153. return( a->b_nids > b->b_nids ? b : a );
  154. }
  155. int
  156. idl_id_is_in_idlist(IDList *idl, ID id)
  157. {
  158. NIDS i;
  159. if (NULL == idl || NOID == id) {
  160. return 0; /* not in the list */
  161. }
  162. if (ALLIDS(idl)) {
  163. return 1; /* in the list */
  164. }
  165. for (i = 0; i < idl->b_nids; i++) {
  166. if (id == idl->b_ids[i]) {
  167. return 1; /* in the list */
  168. }
  169. }
  170. return 0; /* not in the list */
  171. }
  172. /*
  173. * idl_intersection - return a intersection b
  174. */
  175. IDList *
  176. idl_intersection(
  177. backend *be,
  178. IDList *a,
  179. IDList *b
  180. )
  181. {
  182. NIDS ai, bi, ni;
  183. IDList *n;
  184. if ( a == NULL || b == NULL ) {
  185. return( NULL );
  186. }
  187. if ( ALLIDS( a ) ) {
  188. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  189. return( idl_dup( b ) );
  190. }
  191. if ( ALLIDS( b ) ) {
  192. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  193. return( idl_dup( a ) );
  194. }
  195. n = idl_dup( idl_min( a, b ) );
  196. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  197. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ )
  198. ; /* NULL */
  199. if ( bi == b->b_nids ) {
  200. break;
  201. }
  202. if ( b->b_ids[bi] == a->b_ids[ai] ) {
  203. n->b_ids[ni++] = a->b_ids[ai];
  204. }
  205. }
  206. if ( ni == 0 ) {
  207. idl_free( n );
  208. return( NULL );
  209. }
  210. n->b_nids = ni;
  211. return( n );
  212. }
  213. /*
  214. * idl_union - return a union b
  215. */
  216. IDList *
  217. idl_union(
  218. backend *be,
  219. IDList *a,
  220. IDList *b
  221. )
  222. {
  223. NIDS ai, bi, ni;
  224. IDList *n;
  225. if ( a == NULL ) {
  226. return( idl_dup( b ) );
  227. }
  228. if ( b == NULL ) {
  229. return( idl_dup( a ) );
  230. }
  231. if ( ALLIDS( a ) || ALLIDS( b ) ) {
  232. return( idl_allids( be ) );
  233. }
  234. if ( b->b_nids < a->b_nids ) {
  235. n = a;
  236. a = b;
  237. b = n;
  238. }
  239. n = idl_alloc( a->b_nids + b->b_nids );
  240. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) {
  241. if ( a->b_ids[ai] < b->b_ids[bi] ) {
  242. n->b_ids[ni++] = a->b_ids[ai++];
  243. } else if ( b->b_ids[bi] < a->b_ids[ai] ) {
  244. n->b_ids[ni++] = b->b_ids[bi++];
  245. } else {
  246. n->b_ids[ni++] = a->b_ids[ai];
  247. ai++, bi++;
  248. }
  249. }
  250. for ( ; ai < a->b_nids; ai++ ) {
  251. n->b_ids[ni++] = a->b_ids[ai];
  252. }
  253. for ( ; bi < b->b_nids; bi++ ) {
  254. n->b_ids[ni++] = b->b_ids[bi];
  255. }
  256. n->b_nids = ni;
  257. return( n );
  258. }
  259. /*
  260. * idl_notin - return a intersection ~b (or a minus b)
  261. * DB --- changed the interface of this function (no code called it),
  262. * such that it can modify IDL a in place (it'll always be the same
  263. * or smaller than the a passed in if not allids).
  264. * If a new list is generated, it's returned in new_result and the function
  265. * returns 1. Otherwise the result remains in a, and the function returns 0.
  266. * The intention is to optimize for the interesting case in filterindex.c
  267. * where we are computing foo AND NOT bar, and both foo and bar are not allids.
  268. */
  269. int
  270. idl_notin(
  271. backend *be,
  272. IDList *a,
  273. IDList *b,
  274. IDList **new_result
  275. )
  276. {
  277. NIDS ni, ai, bi;
  278. IDList *n;
  279. *new_result = NULL;
  280. if ( a == NULL ) {
  281. return( 0 );
  282. }
  283. if ( b == NULL || ALLIDS( b ) ) {
  284. *new_result = idl_dup( a );
  285. return( 1 );
  286. }
  287. if ( ALLIDS( a ) ) { /* Not convinced that this code is really worth it */
  288. /* It's trying to do allids notin b, where maxid is smaller than some size */
  289. n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
  290. ni = 0;
  291. for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax &&
  292. bi < b->b_nmax; ai++ ) {
  293. if ( b->b_ids[bi] == ai ) {
  294. bi++;
  295. } else {
  296. n->b_ids[ni++] = ai;
  297. }
  298. }
  299. for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) {
  300. n->b_ids[ni++] = ai;
  301. }
  302. if ( ni == n->b_nmax ) {
  303. idl_free( n );
  304. *new_result = idl_allids( be );
  305. } else {
  306. n->b_nids = ni;
  307. *new_result = n;
  308. }
  309. return( 1 );
  310. }
  311. /* This is the case we're interested in, we want to detect where a and b don't overlap */
  312. {
  313. size_t ahii, aloi, bhii, bloi;
  314. size_t ahi, alo, bhi, blo;
  315. int aloblo, ahiblo, alobhi, ahibhi;
  316. aloi = bloi = 0;
  317. ahii = a->b_nids - 1;
  318. bhii = b->b_nids - 1;
  319. ahi = a->b_ids[ahii];
  320. alo = a->b_ids[aloi];
  321. bhi = b->b_ids[bhii];
  322. blo = b->b_ids[bloi];
  323. /* if the ranges don't overlap, we're done, current a is the result */
  324. aloblo = alo < blo;
  325. ahiblo = ahi < blo;
  326. alobhi = ahi > bhi;
  327. ahibhi = alo > bhi;
  328. if ( (aloblo & ahiblo) || (alobhi & ahibhi) ) {
  329. return 0;
  330. } else {
  331. /* Do what we did before */
  332. n = idl_dup( a );
  333. ni = 0;
  334. for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  335. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai];
  336. bi++ ) {
  337. ; /* NULL */
  338. }
  339. if ( bi == b->b_nids ) {
  340. break;
  341. }
  342. if ( b->b_ids[bi] != a->b_ids[ai] ) {
  343. n->b_ids[ni++] = a->b_ids[ai];
  344. }
  345. }
  346. for ( ; ai < a->b_nids; ai++ ) {
  347. n->b_ids[ni++] = a->b_ids[ai];
  348. }
  349. n->b_nids = ni;
  350. *new_result = n;
  351. return( 1 );
  352. }
  353. }
  354. }
  355. ID
  356. idl_firstid( IDList *idl )
  357. {
  358. if ( idl == NULL || idl->b_nids == 0 ) {
  359. return( NOID );
  360. }
  361. if ( ALLIDS( idl ) ) {
  362. return( idl->b_nids == 1 ? NOID : 1 );
  363. }
  364. return( idl->b_ids[0] );
  365. }
  366. ID
  367. idl_nextid( IDList *idl, ID id )
  368. {
  369. NIDS i;
  370. if ( ALLIDS( idl ) ) {
  371. return( ++id < idl->b_nids ? id : NOID );
  372. }
  373. for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) {
  374. ; /* NULL */
  375. }
  376. i++;
  377. if ( i >= idl->b_nids ) {
  378. return( NOID );
  379. } else {
  380. return( idl->b_ids[i] );
  381. }
  382. }
  383. /* Make an ID list iterator */
  384. idl_iterator idl_iterator_init(const IDList *idl)
  385. {
  386. return (idl_iterator) 0;
  387. }
  388. idl_iterator idl_iterator_increment(idl_iterator *i)
  389. {
  390. size_t t = (size_t) *i;
  391. t += 1;
  392. *i = (idl_iterator) t;
  393. return *i;
  394. }
  395. idl_iterator idl_iterator_decrement(idl_iterator *i)
  396. {
  397. size_t t = (size_t) *i;
  398. if (t > 0) {
  399. t -= 1;
  400. }
  401. *i = (idl_iterator) t;
  402. return *i;
  403. }
  404. ID idl_iterator_dereference(idl_iterator i, const IDList *idl)
  405. {
  406. if ( (NULL == idl) || (i >= idl->b_nids)) {
  407. return NOID;
  408. }
  409. if (ALLIDS(idl)) {
  410. return (ID) i + 1;
  411. } else {
  412. return idl->b_ids[i];
  413. }
  414. }
  415. ID idl_iterator_dereference_increment(idl_iterator *i, const IDList *idl)
  416. {
  417. ID t = idl_iterator_dereference(*i,idl);
  418. idl_iterator_increment(i);
  419. return t;
  420. }