Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BTreeItemsTemplate.c 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. /*****************************************************************************
  2. Copyright (c) 2001, 2002 Zope Foundation and Contributors.
  3. All Rights Reserved.
  4. This software is subject to the provisions of the Zope Public License,
  5. Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  6. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  7. WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  8. WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  9. FOR A PARTICULAR PURPOSE
  10. ****************************************************************************/
  11. #define BTREEITEMSTEMPLATE_C "$Id$\n"
  12. /* A BTreeItems struct is returned from calling .items(), .keys() or
  13. * .values() on a BTree-based data structure, and is also the result of
  14. * taking slices of those. It represents a contiguous slice of a BTree.
  15. *
  16. * The start of the slice is in firstbucket, at offset first. The end of
  17. * the slice is in lastbucket, at offset last. Both endpoints are inclusive.
  18. * It must possible to get from firstbucket to lastbucket via following
  19. * bucket 'next' pointers zero or more times. firstbucket, first, lastbucket,
  20. * and last are readonly after initialization. An empty slice is represented
  21. * by firstbucket == lastbucket == currentbucket == NULL.
  22. *
  23. * 'kind' determines whether this slice represents 'k'eys alone, 'v'alues
  24. * alone, or 'i'items (key+value pairs). 'kind' is also readonly after
  25. * initialization.
  26. *
  27. * The combination of currentbucket, currentoffset and pseudoindex acts as
  28. * a search finger. Offset currentoffset in bucket currentbucket is at index
  29. * pseudoindex, where pseudoindex==0 corresponds to offset first in bucket
  30. * firstbucket, and pseudoindex==-1 corresponds to offset last in bucket
  31. * lastbucket. The function BTreeItems_seek() can be used to set this combo
  32. * correctly for any in-bounds index, and uses this combo on input to avoid
  33. * needing to search from the start (or end) on each call. Calling
  34. * BTreeItems_seek() with consecutive larger positions is very efficent.
  35. * Calling it with consecutive smaller positions is more efficient than if
  36. * a search finger weren't being used at all, but is still quadratic time
  37. * in the number of buckets in the slice.
  38. */
  39. typedef struct
  40. {
  41. PyObject_HEAD
  42. Bucket *firstbucket; /* First bucket */
  43. Bucket *currentbucket; /* Current bucket (search finger) */
  44. Bucket *lastbucket; /* Last bucket */
  45. int currentoffset; /* Offset in currentbucket */
  46. int pseudoindex; /* search finger index */
  47. int first; /* Start offset in firstbucket */
  48. int last; /* End offset in lastbucket */
  49. char kind; /* 'k', 'v', 'i' */
  50. } BTreeItems;
  51. #define ITEMS(O)((BTreeItems*)(O))
  52. static PyObject *
  53. newBTreeItems(char kind,
  54. Bucket *lowbucket, int lowoffset,
  55. Bucket *highbucket, int highoffset);
  56. static void
  57. BTreeItems_dealloc(BTreeItems *self)
  58. {
  59. Py_XDECREF(self->firstbucket);
  60. Py_XDECREF(self->lastbucket);
  61. Py_XDECREF(self->currentbucket);
  62. PyObject_DEL(self);
  63. }
  64. static Py_ssize_t
  65. BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero)
  66. {
  67. Py_ssize_t r;
  68. Bucket *b, *next;
  69. b = self->firstbucket;
  70. if (b == NULL)
  71. return 0;
  72. r = self->last + 1 - self->first;
  73. if (nonzero && r > 0)
  74. /* Short-circuit if all we care about is nonempty */
  75. return 1;
  76. if (b == self->lastbucket)
  77. return r;
  78. Py_INCREF(b);
  79. PER_USE_OR_RETURN(b, -1);
  80. while ((next = b->next))
  81. {
  82. r += b->len;
  83. if (nonzero && r > 0)
  84. /* Short-circuit if all we care about is nonempty */
  85. break;
  86. if (next == self->lastbucket)
  87. break; /* we already counted the last bucket */
  88. Py_INCREF(next);
  89. PER_UNUSE(b);
  90. Py_DECREF(b);
  91. b = next;
  92. PER_USE_OR_RETURN(b, -1);
  93. }
  94. PER_UNUSE(b);
  95. Py_DECREF(b);
  96. return r >= 0 ? r : 0;
  97. }
  98. static Py_ssize_t
  99. BTreeItems_length(BTreeItems *self)
  100. {
  101. return BTreeItems_length_or_nonzero(self, 0);
  102. }
  103. /*
  104. ** BTreeItems_seek
  105. **
  106. ** Find the ith position in the BTreeItems.
  107. **
  108. ** Arguments: self The BTree
  109. ** i the index to seek to, in 0 .. len(self)-1, or in
  110. ** -len(self) .. -1, as for indexing a Python sequence.
  111. **
  112. **
  113. ** Returns 0 if successful, -1 on failure to seek (like out-of-bounds).
  114. ** Upon successful return, index i is at offset self->currentoffset in bucket
  115. ** self->currentbucket.
  116. */
  117. static int
  118. BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
  119. {
  120. int delta, pseudoindex, currentoffset;
  121. Bucket *b, *currentbucket;
  122. int error;
  123. pseudoindex = self->pseudoindex;
  124. currentoffset = self->currentoffset;
  125. currentbucket = self->currentbucket;
  126. if (currentbucket == NULL)
  127. goto no_match;
  128. delta = i - pseudoindex;
  129. while (delta > 0) /* move right */
  130. {
  131. int max;
  132. /* Want to move right delta positions; the most we can move right in
  133. * this bucket is currentbucket->len - currentoffset - 1 positions.
  134. */
  135. PER_USE_OR_RETURN(currentbucket, -1);
  136. max = currentbucket->len - currentoffset - 1;
  137. b = currentbucket->next;
  138. PER_UNUSE(currentbucket);
  139. if (delta <= max)
  140. {
  141. currentoffset += delta;
  142. pseudoindex += delta;
  143. if (currentbucket == self->lastbucket
  144. && currentoffset > self->last)
  145. goto no_match;
  146. break;
  147. }
  148. /* Move to start of next bucket. */
  149. if (currentbucket == self->lastbucket || b == NULL)
  150. goto no_match;
  151. currentbucket = b;
  152. pseudoindex += max + 1;
  153. delta -= max + 1;
  154. currentoffset = 0;
  155. }
  156. while (delta < 0) /* move left */
  157. {
  158. int status;
  159. /* Want to move left -delta positions; the most we can move left in
  160. * this bucket is currentoffset positions.
  161. */
  162. if ((-delta) <= currentoffset)
  163. {
  164. currentoffset += delta;
  165. pseudoindex += delta;
  166. if (currentbucket == self->firstbucket
  167. && currentoffset < self->first)
  168. goto no_match;
  169. break;
  170. }
  171. /* Move to end of previous bucket. */
  172. if (currentbucket == self->firstbucket)
  173. goto no_match;
  174. status = PreviousBucket(&currentbucket, self->firstbucket);
  175. if (status == 0)
  176. goto no_match;
  177. else if (status < 0)
  178. return -1;
  179. pseudoindex -= currentoffset + 1;
  180. delta += currentoffset + 1;
  181. PER_USE_OR_RETURN(currentbucket, -1);
  182. currentoffset = currentbucket->len - 1;
  183. PER_UNUSE(currentbucket);
  184. }
  185. assert(pseudoindex == i);
  186. /* Alas, the user may have mutated the bucket since the last time we
  187. * were called, and if they deleted stuff, we may be pointing into
  188. * trash memory now.
  189. */
  190. PER_USE_OR_RETURN(currentbucket, -1);
  191. error = currentoffset < 0 || currentoffset >= currentbucket->len;
  192. PER_UNUSE(currentbucket);
  193. if (error)
  194. {
  195. PyErr_SetString(PyExc_RuntimeError,
  196. "the bucket being iterated changed size");
  197. return -1;
  198. }
  199. Py_INCREF(currentbucket);
  200. Py_DECREF(self->currentbucket);
  201. self->currentbucket = currentbucket;
  202. self->currentoffset = currentoffset;
  203. self->pseudoindex = pseudoindex;
  204. return 0;
  205. no_match:
  206. IndexError(i);
  207. return -1;
  208. }
  209. /* Return the right kind ('k','v','i') of entry from bucket b at offset i.
  210. * b must be activated. Returns NULL on error.
  211. */
  212. static PyObject *
  213. getBucketEntry(Bucket *b, int i, char kind)
  214. {
  215. PyObject *result = NULL;
  216. assert(b);
  217. assert(0 <= i && i < b->len);
  218. switch (kind)
  219. {
  220. case 'k':
  221. COPY_KEY_TO_OBJECT(result, b->keys[i]);
  222. break;
  223. case 'v':
  224. COPY_VALUE_TO_OBJECT(result, b->values[i]);
  225. break;
  226. case 'i':
  227. {
  228. PyObject *key;
  229. PyObject *value;;
  230. COPY_KEY_TO_OBJECT(key, b->keys[i]);
  231. if (!key)
  232. break;
  233. COPY_VALUE_TO_OBJECT(value, b->values[i]);
  234. if (!value)
  235. {
  236. Py_DECREF(key);
  237. break;
  238. }
  239. result = PyTuple_New(2);
  240. if (result)
  241. {
  242. PyTuple_SET_ITEM(result, 0, key);
  243. PyTuple_SET_ITEM(result, 1, value);
  244. }
  245. else
  246. {
  247. Py_DECREF(key);
  248. Py_DECREF(value);
  249. }
  250. break;
  251. }
  252. default:
  253. PyErr_SetString(PyExc_AssertionError,
  254. "getBucketEntry: unknown kind");
  255. break;
  256. }
  257. return result;
  258. }
  259. /*
  260. ** BTreeItems_item
  261. **
  262. ** Arguments: self a BTreeItems structure
  263. ** i Which item to inspect
  264. **
  265. ** Returns: the BTreeItems_item_BTree of self->kind, i
  266. ** (ie pulls the ith item out)
  267. */
  268. static PyObject *
  269. BTreeItems_item(BTreeItems *self, Py_ssize_t i)
  270. {
  271. PyObject *result;
  272. if (BTreeItems_seek(self, i) < 0)
  273. return NULL;
  274. PER_USE_OR_RETURN(self->currentbucket, NULL);
  275. result = getBucketEntry(self->currentbucket, self->currentoffset,
  276. self->kind);
  277. PER_UNUSE(self->currentbucket);
  278. return result;
  279. }
  280. /*
  281. ** BTreeItems_slice
  282. **
  283. ** Creates a new BTreeItems structure representing the slice
  284. ** between the low and high range
  285. **
  286. ** Arguments: self The old BTreeItems structure
  287. ** ilow The start index
  288. ** ihigh The end index
  289. **
  290. ** Returns: BTreeItems item
  291. */
  292. static PyObject *
  293. BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
  294. {
  295. Bucket *lowbucket;
  296. Bucket *highbucket;
  297. int lowoffset;
  298. int highoffset;
  299. Py_ssize_t length = -1; /* len(self), but computed only if needed */
  300. /* Complications:
  301. * A Python slice never raises IndexError, but BTreeItems_seek does.
  302. * Python did only part of index normalization before calling this:
  303. * ilow may be < 0 now, and ihigh may be arbitrarily large. It's
  304. * our responsibility to clip them.
  305. * A Python slice is exclusive of the high index, but a BTreeItems
  306. * struct is inclusive on both ends.
  307. */
  308. /* First adjust ilow and ihigh to be legit endpoints in the Python
  309. * sense (ilow inclusive, ihigh exclusive). This block duplicates the
  310. * logic from Python's list_slice function (slicing for builtin lists).
  311. */
  312. if (ilow < 0)
  313. ilow = 0;
  314. else
  315. {
  316. if (length < 0)
  317. length = BTreeItems_length(self);
  318. if (ilow > length)
  319. ilow = length;
  320. }
  321. if (ihigh < ilow)
  322. ihigh = ilow;
  323. else
  324. {
  325. if (length < 0)
  326. length = BTreeItems_length(self);
  327. if (ihigh > length)
  328. ihigh = length;
  329. }
  330. assert(0 <= ilow && ilow <= ihigh);
  331. assert(length < 0 || ihigh <= length);
  332. /* Now adjust for that our struct is inclusive on both ends. This is
  333. * easy *except* when the slice is empty: there's no good way to spell
  334. * that in an inclusive-on-both-ends scheme. For example, if the
  335. * slice is btree.items([:0]), ilow == ihigh == 0 at this point, and if
  336. * we were to subtract 1 from ihigh that would get interpreted by
  337. * BTreeItems_seek as meaning the *entire* set of items. Setting ilow==1
  338. * and ihigh==0 doesn't work either, as BTreeItems_seek raises IndexError
  339. * if we attempt to seek to ilow==1 when the underlying sequence is empty.
  340. * It seems simplest to deal with empty slices as a special case here.
  341. */
  342. if (ilow == ihigh) /* empty slice */
  343. {
  344. lowbucket = highbucket = NULL;
  345. lowoffset = 1;
  346. highoffset = 0;
  347. }
  348. else
  349. {
  350. assert(ilow < ihigh);
  351. --ihigh; /* exclusive -> inclusive */
  352. if (BTreeItems_seek(self, ilow) < 0)
  353. return NULL;
  354. lowbucket = self->currentbucket;
  355. lowoffset = self->currentoffset;
  356. if (BTreeItems_seek(self, ihigh) < 0)
  357. return NULL;
  358. highbucket = self->currentbucket;
  359. highoffset = self->currentoffset;
  360. }
  361. return newBTreeItems(self->kind,
  362. lowbucket, lowoffset, highbucket, highoffset);
  363. }
  364. static PyObject *
  365. BTreeItems_subscript(BTreeItems *self, PyObject* subscript)
  366. {
  367. Py_ssize_t len = BTreeItems_length_or_nonzero(self, 0);
  368. if (PyIndex_Check(subscript))
  369. {
  370. Py_ssize_t i = PyNumber_AsSsize_t(subscript, PyExc_IndexError);
  371. if (i == -1 && PyErr_Occurred())
  372. return NULL;
  373. if (i < 0)
  374. i += len;
  375. return BTreeItems_item(self, i);
  376. }
  377. if (PySlice_Check(subscript))
  378. {
  379. Py_ssize_t start, stop, step, slicelength;
  380. #ifdef PY3K
  381. #define SLICEOBJ(x) (x)
  382. #else
  383. #define SLICEOBJ(x) (PySliceObject*)(x)
  384. #endif
  385. if (PySlice_GetIndicesEx(SLICEOBJ(subscript), len,
  386. &start, &stop, &step, &slicelength) < 0)
  387. {
  388. return NULL;
  389. }
  390. if (step != 1)
  391. {
  392. PyErr_SetString(PyExc_RuntimeError,
  393. "slices must have step size of 1");
  394. return NULL;
  395. }
  396. return BTreeItems_slice(self, start, stop);
  397. }
  398. PyErr_SetString(PyExc_RuntimeError,
  399. "Unknown index type: must be int or slice");
  400. return NULL;
  401. }
  402. /* Py3K doesn't honor sequence slicing, so implement via mapping */
  403. static PyMappingMethods BTreeItems_as_mapping = {
  404. (lenfunc)BTreeItems_length, /* mp_length */
  405. (binaryfunc)BTreeItems_subscript, /* mp_subscript */
  406. };
  407. static PySequenceMethods BTreeItems_as_sequence =
  408. {
  409. (lenfunc) BTreeItems_length, /* sq_length */
  410. (binaryfunc)0, /* sq_concat */
  411. (ssizeargfunc)0, /* sq_repeat */
  412. (ssizeargfunc) BTreeItems_item, /* sq_item */
  413. #ifndef PY3K
  414. /* Py3K doesn't honor this slot */
  415. (ssizessizeargfunc) BTreeItems_slice, /* sq_slice */
  416. #endif
  417. };
  418. /* Number Method items (just for nb_nonzero!) */
  419. static int
  420. BTreeItems_nonzero(BTreeItems *self)
  421. {
  422. return BTreeItems_length_or_nonzero(self, 1);
  423. }
  424. static PyNumberMethods BTreeItems_as_number_for_nonzero = {
  425. 0, /* nb_add */
  426. 0, /* nb_subtract */
  427. 0, /* nb_multiply */
  428. #ifndef PY3K
  429. 0, /* nb_divide */
  430. #endif
  431. 0, /* nb_remainder */
  432. 0, /* nb_divmod */
  433. 0, /* nb_power */
  434. 0, /* nb_negative */
  435. 0, /* nb_positive */
  436. 0, /* nb_absolute */
  437. (inquiry)BTreeItems_nonzero /* nb_nonzero */
  438. };
  439. static PyTypeObject BTreeItemsType = {
  440. PyVarObject_HEAD_INIT(NULL, 0)
  441. MOD_NAME_PREFIX "BTreeItems", /* tp_name */
  442. sizeof(BTreeItems), /* tp_basicsize */
  443. 0, /* tp_itemsize */
  444. /* methods */
  445. (destructor) BTreeItems_dealloc, /* tp_dealloc */
  446. 0, /* tp_print */
  447. 0, /* obsolete tp_getattr */
  448. 0, /* obsolete tp_setattr */
  449. 0, /* tp_compare */
  450. 0, /* tp_repr */
  451. &BTreeItems_as_number_for_nonzero, /* tp_as_number */
  452. &BTreeItems_as_sequence, /* tp_as_sequence */
  453. &BTreeItems_as_mapping, /* tp_as_mapping */
  454. (hashfunc)0, /* tp_hash */
  455. (ternaryfunc)0, /* tp_call */
  456. (reprfunc)0, /* tp_str */
  457. 0, /* tp_getattro */
  458. 0, /* tp_setattro */
  459. /* Space for future expansion */
  460. 0L,0L,
  461. "Sequence type used to iterate over BTree items." /* Documentation string */
  462. };
  463. /* Returns a new BTreeItems object representing the contiguous slice from
  464. * offset lowoffset in bucket lowbucket through offset highoffset in bucket
  465. * highbucket, inclusive. Pass lowbucket == NULL for an empty slice.
  466. * The currentbucket is set to lowbucket, currentoffset ot lowoffset, and
  467. * pseudoindex to 0. kind is 'k', 'v' or 'i' (see BTreeItems struct docs).
  468. */
  469. static PyObject *
  470. newBTreeItems(char kind,
  471. Bucket *lowbucket, int lowoffset,
  472. Bucket *highbucket, int highoffset)
  473. {
  474. BTreeItems *self;
  475. UNLESS (self = PyObject_NEW(BTreeItems, &BTreeItemsType))
  476. return NULL;
  477. self->kind=kind;
  478. self->first=lowoffset;
  479. self->last=highoffset;
  480. if (! lowbucket || ! highbucket
  481. || (lowbucket == highbucket && lowoffset > highoffset))
  482. {
  483. self->firstbucket = 0;
  484. self->lastbucket = 0;
  485. self->currentbucket = 0;
  486. }
  487. else
  488. {
  489. Py_INCREF(lowbucket);
  490. self->firstbucket = lowbucket;
  491. Py_INCREF(highbucket);
  492. self->lastbucket = highbucket;
  493. Py_INCREF(lowbucket);
  494. self->currentbucket = lowbucket;
  495. }
  496. self->currentoffset = lowoffset;
  497. self->pseudoindex = 0;
  498. return OBJECT(self);
  499. }
  500. static int
  501. nextBTreeItems(SetIteration *i)
  502. {
  503. if (i->position >= 0)
  504. {
  505. if (i->position)
  506. {
  507. DECREF_KEY(i->key);
  508. DECREF_VALUE(i->value);
  509. }
  510. if (BTreeItems_seek(ITEMS(i->set), i->position) >= 0)
  511. {
  512. Bucket *currentbucket;
  513. currentbucket = BUCKET(ITEMS(i->set)->currentbucket);
  514. UNLESS(PER_USE(currentbucket))
  515. {
  516. /* Mark iteration terminated, so that finiSetIteration doesn't
  517. * try to redundantly decref the key and value
  518. */
  519. i->position = -1;
  520. return -1;
  521. }
  522. COPY_KEY(i->key, currentbucket->keys[ITEMS(i->set)->currentoffset]);
  523. INCREF_KEY(i->key);
  524. COPY_VALUE(i->value,
  525. currentbucket->values[ITEMS(i->set)->currentoffset]);
  526. INCREF_VALUE(i->value);
  527. i->position ++;
  528. PER_UNUSE(currentbucket);
  529. }
  530. else
  531. {
  532. i->position = -1;
  533. PyErr_Clear();
  534. }
  535. }
  536. return 0;
  537. }
  538. static int
  539. nextTreeSetItems(SetIteration *i)
  540. {
  541. if (i->position >= 0)
  542. {
  543. if (i->position)
  544. {
  545. DECREF_KEY(i->key);
  546. }
  547. if (BTreeItems_seek(ITEMS(i->set), i->position) >= 0)
  548. {
  549. Bucket *currentbucket;
  550. currentbucket = BUCKET(ITEMS(i->set)->currentbucket);
  551. UNLESS(PER_USE(currentbucket))
  552. {
  553. /* Mark iteration terminated, so that finiSetIteration doesn't
  554. * try to redundantly decref the key and value
  555. */
  556. i->position = -1;
  557. return -1;
  558. }
  559. COPY_KEY(i->key, currentbucket->keys[ITEMS(i->set)->currentoffset]);
  560. INCREF_KEY(i->key);
  561. i->position ++;
  562. PER_UNUSE(currentbucket);
  563. }
  564. else
  565. {
  566. i->position = -1;
  567. PyErr_Clear();
  568. }
  569. }
  570. return 0;
  571. }
  572. /* Support for the iteration protocol new in Python 2.2. */
  573. static PyTypeObject BTreeIter_Type;
  574. /* The type of iterator objects, returned by e.g. iter(IIBTree()). */
  575. typedef struct
  576. {
  577. PyObject_HEAD
  578. /* We use a BTreeItems object because it's convenient and flexible.
  579. * We abuse it two ways:
  580. * 1. We set currentbucket to NULL when the iteration is finished.
  581. * 2. We don't bother keeping pseudoindex in synch.
  582. */
  583. BTreeItems *pitems;
  584. } BTreeIter;
  585. /* Return a new iterator object, to traverse the keys and/or values
  586. * represented by pitems. pitems must not be NULL. Returns NULL if error.
  587. */
  588. static BTreeIter *
  589. BTreeIter_new(BTreeItems *pitems)
  590. {
  591. BTreeIter *result;
  592. assert(pitems != NULL);
  593. result = PyObject_New(BTreeIter, &BTreeIter_Type);
  594. if (result)
  595. {
  596. Py_INCREF(pitems);
  597. result->pitems = pitems;
  598. }
  599. return result;
  600. }
  601. /* The iterator's tp_dealloc slot. */
  602. static void
  603. BTreeIter_dealloc(BTreeIter *bi)
  604. {
  605. Py_DECREF(bi->pitems);
  606. PyObject_Del(bi);
  607. }
  608. /* The implementation of the iterator's tp_iternext slot. Returns "the next"
  609. * item; returns NULL if error; returns NULL without setting an error if the
  610. * iteration is exhausted (that's the way to terminate the iteration protocol).
  611. */
  612. static PyObject *
  613. BTreeIter_next(BTreeIter *bi, PyObject *args)
  614. {
  615. PyObject *result = NULL; /* until proven innocent */
  616. BTreeItems *items = bi->pitems;
  617. int i = items->currentoffset;
  618. Bucket *bucket = items->currentbucket;
  619. if (bucket == NULL) /* iteration termination is sticky */
  620. return NULL;
  621. PER_USE_OR_RETURN(bucket, NULL);
  622. if (i >= bucket->len)
  623. {
  624. /* We never leave this routine normally with i >= len: somebody
  625. * else mutated the current bucket.
  626. */
  627. PyErr_SetString(PyExc_RuntimeError,
  628. "the bucket being iterated changed size");
  629. /* Arrange for that this error is sticky too. */
  630. items->currentoffset = INT_MAX;
  631. goto Done;
  632. }
  633. /* Build the result object, from bucket at offset i. */
  634. result = getBucketEntry(bucket, i, items->kind);
  635. /* Advance position for next call. */
  636. if (bucket == items->lastbucket && i >= items->last)
  637. {
  638. /* Next call should terminate the iteration. */
  639. Py_DECREF(items->currentbucket);
  640. items->currentbucket = NULL;
  641. }
  642. else
  643. {
  644. ++i;
  645. if (i >= bucket->len)
  646. {
  647. Py_XINCREF(bucket->next);
  648. items->currentbucket = bucket->next;
  649. Py_DECREF(bucket);
  650. i = 0;
  651. }
  652. items->currentoffset = i;
  653. }
  654. Done:
  655. PER_UNUSE(bucket);
  656. return result;
  657. }
  658. static PyObject *
  659. BTreeIter_getiter(PyObject *it)
  660. {
  661. Py_INCREF(it);
  662. return it;
  663. }
  664. static PyTypeObject BTreeIter_Type = {
  665. PyVarObject_HEAD_INIT(NULL, 0)
  666. MODULE_NAME MOD_NAME_PREFIX "TreeIterator", /* tp_name */
  667. sizeof(BTreeIter), /* tp_basicsize */
  668. 0, /* tp_itemsize */
  669. /* methods */
  670. (destructor)BTreeIter_dealloc, /* tp_dealloc */
  671. 0, /* tp_print */
  672. 0, /* tp_getattr */
  673. 0, /* tp_setattr */
  674. 0, /* tp_compare */
  675. 0, /* tp_repr */
  676. 0, /* tp_as_number */
  677. 0, /* tp_as_sequence */
  678. 0, /* tp_as_mapping */
  679. 0, /* tp_hash */
  680. 0, /* tp_call */
  681. 0, /* tp_str */
  682. 0, /*PyObject_GenericGetAttr,*/ /* tp_getattro */
  683. 0, /* tp_setattro */
  684. 0, /* tp_as_buffer */
  685. Py_TPFLAGS_DEFAULT, /* tp_flags */
  686. 0, /* tp_doc */
  687. 0, /* tp_traverse */
  688. 0, /* tp_clear */
  689. 0, /* tp_richcompare */
  690. 0, /* tp_weaklistoffset */
  691. (getiterfunc)BTreeIter_getiter, /* tp_iter */
  692. (iternextfunc)BTreeIter_next, /* tp_iternext */
  693. 0, /* tp_methods */
  694. 0, /* tp_members */
  695. 0, /* tp_getset */
  696. 0, /* tp_base */
  697. 0, /* tp_dict */
  698. 0, /* tp_descr_get */
  699. 0, /* tp_descr_set */
  700. };