idl_common.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. if (NULL == idl) {
  46. return 0;
  47. }
  48. return (2 + idl->b_nmax) * sizeof(ID);
  49. }
  50. NIDS idl_length(IDList *idl)
  51. {
  52. if (NULL == idl) {
  53. return 0;
  54. }
  55. return (idl->b_nmax == ALLIDSBLOCK) ? UINT_MAX : idl->b_nids;
  56. }
  57. int idl_is_allids(IDList *idl)
  58. {
  59. if (NULL == idl) {
  60. return 0;
  61. }
  62. return (idl->b_nmax == ALLIDSBLOCK);
  63. }
  64. IDList *
  65. idl_alloc( NIDS nids )
  66. {
  67. IDList *new;
  68. /* nmax + nids + space for the ids */
  69. new = (IDList *) slapi_ch_calloc( (2 + nids), sizeof(ID) );
  70. new->b_nmax = nids;
  71. new->b_nids = 0;
  72. return( new );
  73. }
  74. IDList *
  75. idl_allids( backend *be )
  76. {
  77. IDList *idl;
  78. idl = idl_alloc( 0 );
  79. idl->b_nmax = ALLIDSBLOCK;
  80. idl->b_nids = next_id_get( be );
  81. return( idl );
  82. }
  83. void
  84. idl_free( IDList **idl )
  85. {
  86. if ((NULL == idl) || (NULL == *idl)) {
  87. return;
  88. }
  89. slapi_ch_free((void**)idl);
  90. }
  91. /*
  92. * idl_append - append an id to an id list.
  93. *
  94. * Warning: The ID List must be maintained in order.
  95. * Use idl_insert if the id may not
  96. *
  97. * returns
  98. * 0 - appended
  99. * 1 - already in there
  100. * 2 - not enough room
  101. */
  102. int
  103. idl_append( IDList *idl, ID id)
  104. {
  105. if (NULL == idl) {
  106. return 2;
  107. }
  108. if ( ALLIDS( idl ) || ( (idl->b_nids) && (idl->b_ids[idl->b_nids - 1] == id)) ) {
  109. return( 1 ); /* already there */
  110. }
  111. if ( idl->b_nids == idl->b_nmax ) {
  112. return( 2 ); /* not enough room */
  113. }
  114. idl->b_ids[idl->b_nids] = id;
  115. idl->b_nids++;
  116. return( 0 );
  117. }
  118. /* Append an ID to an IDL, realloc-ing the space if needs be */
  119. /* ID presented is not to be already in the IDL. */
  120. /* moved from idl_new.c */
  121. int
  122. idl_append_extend(IDList **orig_idl, ID id)
  123. {
  124. IDList *idl = *orig_idl;
  125. if (idl == NULL) {
  126. idl = idl_alloc(32); /* used to be 0 */
  127. idl_append(idl, id);
  128. *orig_idl = idl;
  129. return 0;
  130. }
  131. if ( idl->b_nids == idl->b_nmax ) {
  132. /* No more room, need to extend */
  133. /* Allocate new IDL with twice the space of this one */
  134. IDList *idl_new = NULL;
  135. idl_new = idl_alloc(idl->b_nmax * 2);
  136. if (NULL == idl_new) {
  137. return ENOMEM;
  138. }
  139. /* copy over the existing contents */
  140. idl_new->b_nids = idl->b_nids;
  141. memcpy(idl_new->b_ids, idl->b_ids, sizeof(ID) * idl->b_nids);
  142. idl_free(&idl);
  143. idl = idl_new;
  144. }
  145. idl->b_ids[idl->b_nids] = id;
  146. idl->b_nids++;
  147. *orig_idl = idl;
  148. return 0;
  149. }
  150. static IDList *
  151. idl_dup( IDList *idl )
  152. {
  153. IDList *new;
  154. if ( idl == NULL ) {
  155. return( NULL );
  156. }
  157. new = idl_alloc( idl->b_nmax );
  158. SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2)
  159. * sizeof(ID) );
  160. return( new );
  161. }
  162. static IDList *
  163. idl_min( IDList *a, IDList *b )
  164. {
  165. return( a->b_nids > b->b_nids ? b : a );
  166. }
  167. int
  168. idl_id_is_in_idlist(IDList *idl, ID id)
  169. {
  170. NIDS i;
  171. if (NULL == idl || NOID == id) {
  172. return 0; /* not in the list */
  173. }
  174. if (ALLIDS(idl)) {
  175. return 1; /* in the list */
  176. }
  177. for (i = 0; i < idl->b_nids; i++) {
  178. if (id == idl->b_ids[i]) {
  179. return 1; /* in the list */
  180. }
  181. }
  182. return 0; /* not in the list */
  183. }
  184. /*
  185. * idl_intersection - return a intersection b
  186. */
  187. IDList *
  188. idl_intersection(
  189. backend *be,
  190. IDList *a,
  191. IDList *b
  192. )
  193. {
  194. NIDS ai, bi, ni;
  195. IDList *n;
  196. if ( a == NULL || b == NULL ) {
  197. return( NULL );
  198. }
  199. if ( ALLIDS( a ) ) {
  200. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  201. return( idl_dup( b ) );
  202. }
  203. if ( ALLIDS( b ) ) {
  204. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  205. return( idl_dup( a ) );
  206. }
  207. n = idl_dup( idl_min( a, b ) );
  208. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  209. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ )
  210. ; /* NULL */
  211. if ( bi == b->b_nids ) {
  212. break;
  213. }
  214. if ( b->b_ids[bi] == a->b_ids[ai] ) {
  215. n->b_ids[ni++] = a->b_ids[ai];
  216. }
  217. }
  218. if ( ni == 0 ) {
  219. idl_free( &n );
  220. return( NULL );
  221. }
  222. n->b_nids = ni;
  223. return( n );
  224. }
  225. /*
  226. * idl_union - return a union b
  227. */
  228. IDList *
  229. idl_union(
  230. backend *be,
  231. IDList *a,
  232. IDList *b
  233. )
  234. {
  235. NIDS ai, bi, ni;
  236. IDList *n;
  237. if ( a == NULL ) {
  238. return( idl_dup( b ) );
  239. }
  240. if ( b == NULL ) {
  241. return( idl_dup( a ) );
  242. }
  243. if ( ALLIDS( a ) || ALLIDS( b ) ) {
  244. return( idl_allids( be ) );
  245. }
  246. if ( b->b_nids < a->b_nids ) {
  247. n = a;
  248. a = b;
  249. b = n;
  250. }
  251. n = idl_alloc( a->b_nids + b->b_nids );
  252. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) {
  253. if ( a->b_ids[ai] < b->b_ids[bi] ) {
  254. n->b_ids[ni++] = a->b_ids[ai++];
  255. } else if ( b->b_ids[bi] < a->b_ids[ai] ) {
  256. n->b_ids[ni++] = b->b_ids[bi++];
  257. } else {
  258. n->b_ids[ni++] = a->b_ids[ai];
  259. ai++, bi++;
  260. }
  261. }
  262. for ( ; ai < a->b_nids; ai++ ) {
  263. n->b_ids[ni++] = a->b_ids[ai];
  264. }
  265. for ( ; bi < b->b_nids; bi++ ) {
  266. n->b_ids[ni++] = b->b_ids[bi];
  267. }
  268. n->b_nids = ni;
  269. return( n );
  270. }
  271. /*
  272. * idl_notin - return a intersection ~b (or a minus b)
  273. * DB --- changed the interface of this function (no code called it),
  274. * such that it can modify IDL a in place (it'll always be the same
  275. * or smaller than the a passed in if not allids).
  276. * If a new list is generated, it's returned in new_result and the function
  277. * returns 1. Otherwise the result remains in a, and the function returns 0.
  278. * The intention is to optimize for the interesting case in filterindex.c
  279. * where we are computing foo AND NOT bar, and both foo and bar are not allids.
  280. */
  281. int
  282. idl_notin(
  283. backend *be,
  284. IDList *a,
  285. IDList *b,
  286. IDList **new_result
  287. )
  288. {
  289. NIDS ni, ai, bi;
  290. IDList *n;
  291. *new_result = NULL;
  292. if ( a == NULL ) {
  293. return( 0 );
  294. }
  295. if ( b == NULL || ALLIDS( b ) ) {
  296. *new_result = idl_dup( a );
  297. return( 1 );
  298. }
  299. if ( ALLIDS( a ) ) { /* Not convinced that this code is really worth it */
  300. /* It's trying to do allids notin b, where maxid is smaller than some size */
  301. n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
  302. ni = 0;
  303. for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax &&
  304. bi < b->b_nmax; ai++ ) {
  305. if ( b->b_ids[bi] == ai ) {
  306. bi++;
  307. } else {
  308. n->b_ids[ni++] = ai;
  309. }
  310. }
  311. for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) {
  312. n->b_ids[ni++] = ai;
  313. }
  314. if ( ni == n->b_nmax ) {
  315. idl_free( &n );
  316. *new_result = idl_allids( be );
  317. } else {
  318. n->b_nids = ni;
  319. *new_result = n;
  320. }
  321. return( 1 );
  322. }
  323. /* This is the case we're interested in, we want to detect where a and b don't overlap */
  324. {
  325. size_t ahii, aloi, bhii, bloi;
  326. size_t ahi, alo, bhi, blo;
  327. int aloblo, ahiblo, alobhi, ahibhi;
  328. aloi = bloi = 0;
  329. ahii = a->b_nids - 1;
  330. bhii = b->b_nids - 1;
  331. ahi = a->b_ids[ahii];
  332. alo = a->b_ids[aloi];
  333. bhi = b->b_ids[bhii];
  334. blo = b->b_ids[bloi];
  335. /* if the ranges don't overlap, we're done, current a is the result */
  336. aloblo = alo < blo;
  337. ahiblo = ahi < blo;
  338. alobhi = ahi > bhi;
  339. ahibhi = alo > bhi;
  340. if ( (aloblo & ahiblo) || (alobhi & ahibhi) ) {
  341. return 0;
  342. } else {
  343. /* Do what we did before */
  344. n = idl_dup( a );
  345. ni = 0;
  346. for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  347. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai];
  348. bi++ ) {
  349. ; /* NULL */
  350. }
  351. if ( bi == b->b_nids ) {
  352. break;
  353. }
  354. if ( b->b_ids[bi] != a->b_ids[ai] ) {
  355. n->b_ids[ni++] = a->b_ids[ai];
  356. }
  357. }
  358. for ( ; ai < a->b_nids; ai++ ) {
  359. n->b_ids[ni++] = a->b_ids[ai];
  360. }
  361. n->b_nids = ni;
  362. *new_result = n;
  363. return( 1 );
  364. }
  365. }
  366. }
  367. ID
  368. idl_firstid( IDList *idl )
  369. {
  370. if ( idl == NULL || idl->b_nids == 0 ) {
  371. return( NOID );
  372. }
  373. if ( ALLIDS( idl ) ) {
  374. return( idl->b_nids == 1 ? NOID : 1 );
  375. }
  376. return( idl->b_ids[0] );
  377. }
  378. ID
  379. idl_nextid( IDList *idl, ID id )
  380. {
  381. NIDS i;
  382. if (NULL == idl) {
  383. return NOID;
  384. }
  385. if ( ALLIDS( idl ) ) {
  386. return( ++id < idl->b_nids ? id : NOID );
  387. }
  388. for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) {
  389. ; /* NULL */
  390. }
  391. i++;
  392. if ( i >= idl->b_nids ) {
  393. return( NOID );
  394. } else {
  395. return( idl->b_ids[i] );
  396. }
  397. }
  398. /* Make an ID list iterator */
  399. idl_iterator idl_iterator_init(const IDList *idl)
  400. {
  401. return (idl_iterator) 0;
  402. }
  403. idl_iterator idl_iterator_increment(idl_iterator *i)
  404. {
  405. size_t t = (size_t) *i;
  406. t += 1;
  407. *i = (idl_iterator) t;
  408. return *i;
  409. }
  410. idl_iterator idl_iterator_decrement(idl_iterator *i)
  411. {
  412. size_t t = (size_t) *i;
  413. if (t > 0) {
  414. t -= 1;
  415. }
  416. *i = (idl_iterator) t;
  417. return *i;
  418. }
  419. ID idl_iterator_dereference(idl_iterator i, const IDList *idl)
  420. {
  421. if ( (NULL == idl) || (i >= idl->b_nids)) {
  422. return NOID;
  423. }
  424. if (ALLIDS(idl)) {
  425. return (ID) i + 1;
  426. } else {
  427. return idl->b_ids[i];
  428. }
  429. }
  430. ID idl_iterator_dereference_increment(idl_iterator *i, const IDList *idl)
  431. {
  432. ID t = idl_iterator_dereference(*i,idl);
  433. idl_iterator_increment(i);
  434. return t;
  435. }
  436. ID idl_iterator_dereference_decrement(idl_iterator *i, const IDList *idl)
  437. {
  438. idl_iterator_decrement(i);
  439. return idl_iterator_dereference(*i,idl);
  440. }