idl_common.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. static IDList *
  107. idl_dup( IDList *idl )
  108. {
  109. IDList *new;
  110. if ( idl == NULL ) {
  111. return( NULL );
  112. }
  113. new = idl_alloc( idl->b_nmax );
  114. SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2)
  115. * sizeof(ID) );
  116. return( new );
  117. }
  118. static IDList *
  119. idl_min( IDList *a, IDList *b )
  120. {
  121. return( a->b_nids > b->b_nids ? b : a );
  122. }
  123. /*
  124. * idl_intersection - return a intersection b
  125. */
  126. IDList *
  127. idl_intersection(
  128. backend *be,
  129. IDList *a,
  130. IDList *b
  131. )
  132. {
  133. NIDS ai, bi, ni;
  134. IDList *n;
  135. if ( a == NULL || b == NULL ) {
  136. return( NULL );
  137. }
  138. if ( ALLIDS( a ) ) {
  139. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  140. return( idl_dup( b ) );
  141. }
  142. if ( ALLIDS( b ) ) {
  143. slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
  144. return( idl_dup( a ) );
  145. }
  146. n = idl_dup( idl_min( a, b ) );
  147. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  148. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ )
  149. ; /* NULL */
  150. if ( bi == b->b_nids ) {
  151. break;
  152. }
  153. if ( b->b_ids[bi] == a->b_ids[ai] ) {
  154. n->b_ids[ni++] = a->b_ids[ai];
  155. }
  156. }
  157. if ( ni == 0 ) {
  158. idl_free( n );
  159. return( NULL );
  160. }
  161. n->b_nids = ni;
  162. return( n );
  163. }
  164. /*
  165. * idl_union - return a union b
  166. */
  167. IDList *
  168. idl_union(
  169. backend *be,
  170. IDList *a,
  171. IDList *b
  172. )
  173. {
  174. NIDS ai, bi, ni;
  175. IDList *n;
  176. if ( a == NULL ) {
  177. return( idl_dup( b ) );
  178. }
  179. if ( b == NULL ) {
  180. return( idl_dup( a ) );
  181. }
  182. if ( ALLIDS( a ) || ALLIDS( b ) ) {
  183. return( idl_allids( be ) );
  184. }
  185. if ( b->b_nids < a->b_nids ) {
  186. n = a;
  187. a = b;
  188. b = n;
  189. }
  190. n = idl_alloc( a->b_nids + b->b_nids );
  191. for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) {
  192. if ( a->b_ids[ai] < b->b_ids[bi] ) {
  193. n->b_ids[ni++] = a->b_ids[ai++];
  194. } else if ( b->b_ids[bi] < a->b_ids[ai] ) {
  195. n->b_ids[ni++] = b->b_ids[bi++];
  196. } else {
  197. n->b_ids[ni++] = a->b_ids[ai];
  198. ai++, bi++;
  199. }
  200. }
  201. for ( ; ai < a->b_nids; ai++ ) {
  202. n->b_ids[ni++] = a->b_ids[ai];
  203. }
  204. for ( ; bi < b->b_nids; bi++ ) {
  205. n->b_ids[ni++] = b->b_ids[bi];
  206. }
  207. n->b_nids = ni;
  208. return( n );
  209. }
  210. /*
  211. * idl_notin - return a intersection ~b (or a minus b)
  212. * DB --- changed the interface of this function (no code called it),
  213. * such that it can modify IDL a in place (it'll always be the same
  214. * or smaller than the a passed in if not allids).
  215. * If a new list is generated, it's returned in new_result and the function
  216. * returns 1. Otherwise the result remains in a, and the function returns 0.
  217. * The intention is to optimize for the interesting case in filterindex.c
  218. * where we are computing foo AND NOT bar, and both foo and bar are not allids.
  219. */
  220. int
  221. idl_notin(
  222. backend *be,
  223. IDList *a,
  224. IDList *b,
  225. IDList **new_result
  226. )
  227. {
  228. NIDS ni, ai, bi;
  229. IDList *n;
  230. *new_result = NULL;
  231. if ( a == NULL ) {
  232. return( 0 );
  233. }
  234. if ( b == NULL || ALLIDS( b ) ) {
  235. *new_result = idl_dup( a );
  236. return( 1 );
  237. }
  238. if ( ALLIDS( a ) ) { /* Not convinced that this code is really worth it */
  239. /* It's trying to do allids notin b, where maxid is smaller than some size */
  240. n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
  241. ni = 0;
  242. for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax &&
  243. bi < b->b_nmax; ai++ ) {
  244. if ( b->b_ids[bi] == ai ) {
  245. bi++;
  246. } else {
  247. n->b_ids[ni++] = ai;
  248. }
  249. }
  250. for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) {
  251. n->b_ids[ni++] = ai;
  252. }
  253. if ( ni == n->b_nmax ) {
  254. idl_free( n );
  255. *new_result = idl_allids( be );
  256. } else {
  257. n->b_nids = ni;
  258. *new_result = n;
  259. }
  260. return( 1 );
  261. }
  262. /* This is the case we're interested in, we want to detect where a and b don't overlap */
  263. {
  264. size_t ahii, aloi, bhii, bloi;
  265. size_t ahi, alo, bhi, blo;
  266. int aloblo, ahiblo, alobhi, ahibhi;
  267. aloi = bloi = 0;
  268. ahii = a->b_nids - 1;
  269. bhii = b->b_nids - 1;
  270. ahi = a->b_ids[ahii];
  271. alo = a->b_ids[aloi];
  272. bhi = b->b_ids[bhii];
  273. blo = b->b_ids[bloi];
  274. /* if the ranges don't overlap, we're done, current a is the result */
  275. aloblo = alo < blo;
  276. ahiblo = ahi < blo;
  277. alobhi = ahi > bhi;
  278. ahibhi = alo > bhi;
  279. if ( (aloblo & ahiblo) || (alobhi & ahibhi) ) {
  280. return 0;
  281. } else {
  282. /* Do what we did before */
  283. n = idl_dup( a );
  284. ni = 0;
  285. for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
  286. for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai];
  287. bi++ ) {
  288. ; /* NULL */
  289. }
  290. if ( bi == b->b_nids ) {
  291. break;
  292. }
  293. if ( b->b_ids[bi] != a->b_ids[ai] ) {
  294. n->b_ids[ni++] = a->b_ids[ai];
  295. }
  296. }
  297. for ( ; ai < a->b_nids; ai++ ) {
  298. n->b_ids[ni++] = a->b_ids[ai];
  299. }
  300. n->b_nids = ni;
  301. *new_result = n;
  302. return( 1 );
  303. }
  304. }
  305. }
  306. ID
  307. idl_firstid( IDList *idl )
  308. {
  309. if ( idl == NULL || idl->b_nids == 0 ) {
  310. return( NOID );
  311. }
  312. if ( ALLIDS( idl ) ) {
  313. return( idl->b_nids == 1 ? NOID : 1 );
  314. }
  315. return( idl->b_ids[0] );
  316. }
  317. ID
  318. idl_nextid( IDList *idl, ID id )
  319. {
  320. NIDS i;
  321. if ( ALLIDS( idl ) ) {
  322. return( ++id < idl->b_nids ? id : NOID );
  323. }
  324. for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) {
  325. ; /* NULL */
  326. }
  327. i++;
  328. if ( i >= idl->b_nids ) {
  329. return( NOID );
  330. } else {
  331. return( idl->b_ids[i] );
  332. }
  333. }
  334. /* Make an ID list iterator */
  335. idl_iterator idl_iterator_init(const IDList *idl)
  336. {
  337. return (idl_iterator) 0;
  338. }
  339. idl_iterator idl_iterator_increment(idl_iterator *i)
  340. {
  341. size_t t = (size_t) *i;
  342. t += 1;
  343. *i = (idl_iterator) t;
  344. return *i;
  345. }
  346. idl_iterator idl_iterator_decrement(idl_iterator *i)
  347. {
  348. size_t t = (size_t) *i;
  349. if (t > 0) {
  350. t -= 1;
  351. }
  352. *i = (idl_iterator) t;
  353. return *i;
  354. }
  355. ID idl_iterator_dereference(idl_iterator i, const IDList *idl)
  356. {
  357. if ( (NULL == idl) || (i >= idl->b_nids)) {
  358. return NOID;
  359. }
  360. if (ALLIDS(idl)) {
  361. return (ID) i + 1;
  362. } else {
  363. return idl->b_ids[i];
  364. }
  365. }
  366. ID idl_iterator_dereference_increment(idl_iterator *i, const IDList *idl)
  367. {
  368. ID t = idl_iterator_dereference(*i,idl);
  369. idl_iterator_increment(i);
  370. return t;
  371. }