123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790 |
- /*****************************************************************************
-
- Copyright (c) 2001, 2002 Zope Foundation and Contributors.
- All Rights Reserved.
-
- This software is subject to the provisions of the Zope Public License,
- Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
- THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
- WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
- FOR A PARTICULAR PURPOSE
-
- ****************************************************************************/
-
- #define BTREEITEMSTEMPLATE_C "$Id$\n"
-
- /* A BTreeItems struct is returned from calling .items(), .keys() or
- * .values() on a BTree-based data structure, and is also the result of
- * taking slices of those. It represents a contiguous slice of a BTree.
- *
- * The start of the slice is in firstbucket, at offset first. The end of
- * the slice is in lastbucket, at offset last. Both endpoints are inclusive.
- * It must possible to get from firstbucket to lastbucket via following
- * bucket 'next' pointers zero or more times. firstbucket, first, lastbucket,
- * and last are readonly after initialization. An empty slice is represented
- * by firstbucket == lastbucket == currentbucket == NULL.
- *
- * 'kind' determines whether this slice represents 'k'eys alone, 'v'alues
- * alone, or 'i'items (key+value pairs). 'kind' is also readonly after
- * initialization.
- *
- * The combination of currentbucket, currentoffset and pseudoindex acts as
- * a search finger. Offset currentoffset in bucket currentbucket is at index
- * pseudoindex, where pseudoindex==0 corresponds to offset first in bucket
- * firstbucket, and pseudoindex==-1 corresponds to offset last in bucket
- * lastbucket. The function BTreeItems_seek() can be used to set this combo
- * correctly for any in-bounds index, and uses this combo on input to avoid
- * needing to search from the start (or end) on each call. Calling
- * BTreeItems_seek() with consecutive larger positions is very efficent.
- * Calling it with consecutive smaller positions is more efficient than if
- * a search finger weren't being used at all, but is still quadratic time
- * in the number of buckets in the slice.
- */
- typedef struct
- {
- PyObject_HEAD
- Bucket *firstbucket; /* First bucket */
- Bucket *currentbucket; /* Current bucket (search finger) */
- Bucket *lastbucket; /* Last bucket */
- int currentoffset; /* Offset in currentbucket */
- int pseudoindex; /* search finger index */
- int first; /* Start offset in firstbucket */
- int last; /* End offset in lastbucket */
- char kind; /* 'k', 'v', 'i' */
- } BTreeItems;
-
- #define ITEMS(O)((BTreeItems*)(O))
-
- static PyObject *
- newBTreeItems(char kind,
- Bucket *lowbucket, int lowoffset,
- Bucket *highbucket, int highoffset);
-
- static void
- BTreeItems_dealloc(BTreeItems *self)
- {
- Py_XDECREF(self->firstbucket);
- Py_XDECREF(self->lastbucket);
- Py_XDECREF(self->currentbucket);
- PyObject_DEL(self);
- }
-
- static Py_ssize_t
- BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero)
- {
- Py_ssize_t r;
- Bucket *b, *next;
-
- b = self->firstbucket;
- if (b == NULL)
- return 0;
-
- r = self->last + 1 - self->first;
-
- if (nonzero && r > 0)
- /* Short-circuit if all we care about is nonempty */
- return 1;
-
- if (b == self->lastbucket)
- return r;
-
- Py_INCREF(b);
- PER_USE_OR_RETURN(b, -1);
- while ((next = b->next))
- {
- r += b->len;
- if (nonzero && r > 0)
- /* Short-circuit if all we care about is nonempty */
- break;
-
- if (next == self->lastbucket)
- break; /* we already counted the last bucket */
-
- Py_INCREF(next);
- PER_UNUSE(b);
- Py_DECREF(b);
- b = next;
- PER_USE_OR_RETURN(b, -1);
- }
- PER_UNUSE(b);
- Py_DECREF(b);
-
- return r >= 0 ? r : 0;
- }
-
- static Py_ssize_t
- BTreeItems_length(BTreeItems *self)
- {
- return BTreeItems_length_or_nonzero(self, 0);
- }
-
- /*
- ** BTreeItems_seek
- **
- ** Find the ith position in the BTreeItems.
- **
- ** Arguments: self The BTree
- ** i the index to seek to, in 0 .. len(self)-1, or in
- ** -len(self) .. -1, as for indexing a Python sequence.
- **
- **
- ** Returns 0 if successful, -1 on failure to seek (like out-of-bounds).
- ** Upon successful return, index i is at offset self->currentoffset in bucket
- ** self->currentbucket.
- */
- static int
- BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
- {
- int delta, pseudoindex, currentoffset;
- Bucket *b, *currentbucket;
- int error;
-
- pseudoindex = self->pseudoindex;
- currentoffset = self->currentoffset;
- currentbucket = self->currentbucket;
- if (currentbucket == NULL)
- goto no_match;
-
- delta = i - pseudoindex;
- while (delta > 0) /* move right */
- {
- int max;
- /* Want to move right delta positions; the most we can move right in
- * this bucket is currentbucket->len - currentoffset - 1 positions.
- */
- PER_USE_OR_RETURN(currentbucket, -1);
- max = currentbucket->len - currentoffset - 1;
- b = currentbucket->next;
- PER_UNUSE(currentbucket);
- if (delta <= max)
- {
- currentoffset += delta;
- pseudoindex += delta;
- if (currentbucket == self->lastbucket
- && currentoffset > self->last)
- goto no_match;
- break;
- }
- /* Move to start of next bucket. */
- if (currentbucket == self->lastbucket || b == NULL)
- goto no_match;
- currentbucket = b;
- pseudoindex += max + 1;
- delta -= max + 1;
- currentoffset = 0;
- }
- while (delta < 0) /* move left */
- {
- int status;
- /* Want to move left -delta positions; the most we can move left in
- * this bucket is currentoffset positions.
- */
- if ((-delta) <= currentoffset)
- {
- currentoffset += delta;
- pseudoindex += delta;
- if (currentbucket == self->firstbucket
- && currentoffset < self->first)
- goto no_match;
- break;
- }
- /* Move to end of previous bucket. */
- if (currentbucket == self->firstbucket)
- goto no_match;
- status = PreviousBucket(¤tbucket, self->firstbucket);
- if (status == 0)
- goto no_match;
- else if (status < 0)
- return -1;
- pseudoindex -= currentoffset + 1;
- delta += currentoffset + 1;
- PER_USE_OR_RETURN(currentbucket, -1);
- currentoffset = currentbucket->len - 1;
- PER_UNUSE(currentbucket);
- }
-
- assert(pseudoindex == i);
-
- /* Alas, the user may have mutated the bucket since the last time we
- * were called, and if they deleted stuff, we may be pointing into
- * trash memory now.
- */
- PER_USE_OR_RETURN(currentbucket, -1);
- error = currentoffset < 0 || currentoffset >= currentbucket->len;
- PER_UNUSE(currentbucket);
- if (error)
- {
- PyErr_SetString(PyExc_RuntimeError,
- "the bucket being iterated changed size");
- return -1;
- }
-
- Py_INCREF(currentbucket);
- Py_DECREF(self->currentbucket);
- self->currentbucket = currentbucket;
- self->currentoffset = currentoffset;
- self->pseudoindex = pseudoindex;
- return 0;
-
- no_match:
- IndexError(i);
- return -1;
- }
-
-
- /* Return the right kind ('k','v','i') of entry from bucket b at offset i.
- * b must be activated. Returns NULL on error.
- */
- static PyObject *
- getBucketEntry(Bucket *b, int i, char kind)
- {
- PyObject *result = NULL;
-
- assert(b);
- assert(0 <= i && i < b->len);
-
- switch (kind)
- {
- case 'k':
- COPY_KEY_TO_OBJECT(result, b->keys[i]);
- break;
-
- case 'v':
- COPY_VALUE_TO_OBJECT(result, b->values[i]);
- break;
-
- case 'i':
- {
- PyObject *key;
- PyObject *value;;
-
- COPY_KEY_TO_OBJECT(key, b->keys[i]);
- if (!key)
- break;
-
- COPY_VALUE_TO_OBJECT(value, b->values[i]);
- if (!value)
- {
- Py_DECREF(key);
- break;
- }
-
- result = PyTuple_New(2);
- if (result)
- {
- PyTuple_SET_ITEM(result, 0, key);
- PyTuple_SET_ITEM(result, 1, value);
- }
- else
- {
- Py_DECREF(key);
- Py_DECREF(value);
- }
- break;
- }
-
- default:
- PyErr_SetString(PyExc_AssertionError,
- "getBucketEntry: unknown kind");
- break;
- }
- return result;
- }
-
- /*
- ** BTreeItems_item
- **
- ** Arguments: self a BTreeItems structure
- ** i Which item to inspect
- **
- ** Returns: the BTreeItems_item_BTree of self->kind, i
- ** (ie pulls the ith item out)
- */
- static PyObject *
- BTreeItems_item(BTreeItems *self, Py_ssize_t i)
- {
- PyObject *result;
-
- if (BTreeItems_seek(self, i) < 0)
- return NULL;
-
- PER_USE_OR_RETURN(self->currentbucket, NULL);
- result = getBucketEntry(self->currentbucket, self->currentoffset,
- self->kind);
- PER_UNUSE(self->currentbucket);
- return result;
- }
-
- /*
- ** BTreeItems_slice
- **
- ** Creates a new BTreeItems structure representing the slice
- ** between the low and high range
- **
- ** Arguments: self The old BTreeItems structure
- ** ilow The start index
- ** ihigh The end index
- **
- ** Returns: BTreeItems item
- */
- static PyObject *
- BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
- {
- Bucket *lowbucket;
- Bucket *highbucket;
- int lowoffset;
- int highoffset;
- Py_ssize_t length = -1; /* len(self), but computed only if needed */
-
- /* Complications:
- * A Python slice never raises IndexError, but BTreeItems_seek does.
- * Python did only part of index normalization before calling this:
- * ilow may be < 0 now, and ihigh may be arbitrarily large. It's
- * our responsibility to clip them.
- * A Python slice is exclusive of the high index, but a BTreeItems
- * struct is inclusive on both ends.
- */
-
- /* First adjust ilow and ihigh to be legit endpoints in the Python
- * sense (ilow inclusive, ihigh exclusive). This block duplicates the
- * logic from Python's list_slice function (slicing for builtin lists).
- */
- if (ilow < 0)
- ilow = 0;
- else
- {
- if (length < 0)
- length = BTreeItems_length(self);
- if (ilow > length)
- ilow = length;
- }
-
- if (ihigh < ilow)
- ihigh = ilow;
- else
- {
- if (length < 0)
- length = BTreeItems_length(self);
- if (ihigh > length)
- ihigh = length;
- }
- assert(0 <= ilow && ilow <= ihigh);
- assert(length < 0 || ihigh <= length);
-
- /* Now adjust for that our struct is inclusive on both ends. This is
- * easy *except* when the slice is empty: there's no good way to spell
- * that in an inclusive-on-both-ends scheme. For example, if the
- * slice is btree.items([:0]), ilow == ihigh == 0 at this point, and if
- * we were to subtract 1 from ihigh that would get interpreted by
- * BTreeItems_seek as meaning the *entire* set of items. Setting ilow==1
- * and ihigh==0 doesn't work either, as BTreeItems_seek raises IndexError
- * if we attempt to seek to ilow==1 when the underlying sequence is empty.
- * It seems simplest to deal with empty slices as a special case here.
- */
- if (ilow == ihigh) /* empty slice */
- {
- lowbucket = highbucket = NULL;
- lowoffset = 1;
- highoffset = 0;
- }
- else
- {
- assert(ilow < ihigh);
- --ihigh; /* exclusive -> inclusive */
-
- if (BTreeItems_seek(self, ilow) < 0)
- return NULL;
- lowbucket = self->currentbucket;
- lowoffset = self->currentoffset;
-
- if (BTreeItems_seek(self, ihigh) < 0)
- return NULL;
-
- highbucket = self->currentbucket;
- highoffset = self->currentoffset;
- }
- return newBTreeItems(self->kind,
- lowbucket, lowoffset, highbucket, highoffset);
- }
-
- static PyObject *
- BTreeItems_subscript(BTreeItems *self, PyObject* subscript)
- {
- Py_ssize_t len = BTreeItems_length_or_nonzero(self, 0);
-
- if (PyIndex_Check(subscript))
- {
- Py_ssize_t i = PyNumber_AsSsize_t(subscript, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return NULL;
- if (i < 0)
- i += len;
- return BTreeItems_item(self, i);
- }
- if (PySlice_Check(subscript))
- {
- Py_ssize_t start, stop, step, slicelength;
-
- #ifdef PY3K
- #define SLICEOBJ(x) (x)
- #else
- #define SLICEOBJ(x) (PySliceObject*)(x)
- #endif
-
- if (PySlice_GetIndicesEx(SLICEOBJ(subscript), len,
- &start, &stop, &step, &slicelength) < 0)
- {
- return NULL;
- }
-
- if (step != 1)
- {
- PyErr_SetString(PyExc_RuntimeError,
- "slices must have step size of 1");
- return NULL;
- }
- return BTreeItems_slice(self, start, stop);
- }
- PyErr_SetString(PyExc_RuntimeError,
- "Unknown index type: must be int or slice");
- return NULL;
- }
-
- /* Py3K doesn't honor sequence slicing, so implement via mapping */
- static PyMappingMethods BTreeItems_as_mapping = {
- (lenfunc)BTreeItems_length, /* mp_length */
- (binaryfunc)BTreeItems_subscript, /* mp_subscript */
- };
-
- static PySequenceMethods BTreeItems_as_sequence =
- {
- (lenfunc) BTreeItems_length, /* sq_length */
- (binaryfunc)0, /* sq_concat */
- (ssizeargfunc)0, /* sq_repeat */
- (ssizeargfunc) BTreeItems_item, /* sq_item */
- #ifndef PY3K
- /* Py3K doesn't honor this slot */
- (ssizessizeargfunc) BTreeItems_slice, /* sq_slice */
- #endif
- };
-
- /* Number Method items (just for nb_nonzero!) */
-
- static int
- BTreeItems_nonzero(BTreeItems *self)
- {
- return BTreeItems_length_or_nonzero(self, 1);
- }
-
- static PyNumberMethods BTreeItems_as_number_for_nonzero = {
- 0, /* nb_add */
- 0, /* nb_subtract */
- 0, /* nb_multiply */
- #ifndef PY3K
- 0, /* nb_divide */
- #endif
- 0, /* nb_remainder */
- 0, /* nb_divmod */
- 0, /* nb_power */
- 0, /* nb_negative */
- 0, /* nb_positive */
- 0, /* nb_absolute */
- (inquiry)BTreeItems_nonzero /* nb_nonzero */
- };
-
- static PyTypeObject BTreeItemsType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- MOD_NAME_PREFIX "BTreeItems", /* tp_name */
- sizeof(BTreeItems), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor) BTreeItems_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* obsolete tp_getattr */
- 0, /* obsolete tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- &BTreeItems_as_number_for_nonzero, /* tp_as_number */
- &BTreeItems_as_sequence, /* tp_as_sequence */
- &BTreeItems_as_mapping, /* tp_as_mapping */
- (hashfunc)0, /* tp_hash */
- (ternaryfunc)0, /* tp_call */
- (reprfunc)0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- /* Space for future expansion */
- 0L,0L,
- "Sequence type used to iterate over BTree items." /* Documentation string */
- };
-
- /* Returns a new BTreeItems object representing the contiguous slice from
- * offset lowoffset in bucket lowbucket through offset highoffset in bucket
- * highbucket, inclusive. Pass lowbucket == NULL for an empty slice.
- * The currentbucket is set to lowbucket, currentoffset ot lowoffset, and
- * pseudoindex to 0. kind is 'k', 'v' or 'i' (see BTreeItems struct docs).
- */
- static PyObject *
- newBTreeItems(char kind,
- Bucket *lowbucket, int lowoffset,
- Bucket *highbucket, int highoffset)
- {
- BTreeItems *self;
-
- UNLESS (self = PyObject_NEW(BTreeItems, &BTreeItemsType))
- return NULL;
- self->kind=kind;
-
- self->first=lowoffset;
- self->last=highoffset;
-
- if (! lowbucket || ! highbucket
- || (lowbucket == highbucket && lowoffset > highoffset))
- {
- self->firstbucket = 0;
- self->lastbucket = 0;
- self->currentbucket = 0;
- }
- else
- {
- Py_INCREF(lowbucket);
- self->firstbucket = lowbucket;
- Py_INCREF(highbucket);
- self->lastbucket = highbucket;
- Py_INCREF(lowbucket);
- self->currentbucket = lowbucket;
- }
-
- self->currentoffset = lowoffset;
- self->pseudoindex = 0;
-
- return OBJECT(self);
- }
-
- static int
- nextBTreeItems(SetIteration *i)
- {
- if (i->position >= 0)
- {
- if (i->position)
- {
- DECREF_KEY(i->key);
- DECREF_VALUE(i->value);
- }
-
- if (BTreeItems_seek(ITEMS(i->set), i->position) >= 0)
- {
- Bucket *currentbucket;
-
- currentbucket = BUCKET(ITEMS(i->set)->currentbucket);
- UNLESS(PER_USE(currentbucket))
- {
- /* Mark iteration terminated, so that finiSetIteration doesn't
- * try to redundantly decref the key and value
- */
- i->position = -1;
- return -1;
- }
-
- COPY_KEY(i->key, currentbucket->keys[ITEMS(i->set)->currentoffset]);
- INCREF_KEY(i->key);
-
- COPY_VALUE(i->value,
- currentbucket->values[ITEMS(i->set)->currentoffset]);
- INCREF_VALUE(i->value);
-
- i->position ++;
-
- PER_UNUSE(currentbucket);
- }
- else
- {
- i->position = -1;
- PyErr_Clear();
- }
- }
- return 0;
- }
-
- static int
- nextTreeSetItems(SetIteration *i)
- {
- if (i->position >= 0)
- {
- if (i->position)
- {
- DECREF_KEY(i->key);
- }
-
- if (BTreeItems_seek(ITEMS(i->set), i->position) >= 0)
- {
- Bucket *currentbucket;
-
- currentbucket = BUCKET(ITEMS(i->set)->currentbucket);
- UNLESS(PER_USE(currentbucket))
- {
- /* Mark iteration terminated, so that finiSetIteration doesn't
- * try to redundantly decref the key and value
- */
- i->position = -1;
- return -1;
- }
-
- COPY_KEY(i->key, currentbucket->keys[ITEMS(i->set)->currentoffset]);
- INCREF_KEY(i->key);
-
- i->position ++;
-
- PER_UNUSE(currentbucket);
- }
- else
- {
- i->position = -1;
- PyErr_Clear();
- }
- }
- return 0;
- }
-
- /* Support for the iteration protocol new in Python 2.2. */
-
- static PyTypeObject BTreeIter_Type;
-
- /* The type of iterator objects, returned by e.g. iter(IIBTree()). */
- typedef struct
- {
- PyObject_HEAD
- /* We use a BTreeItems object because it's convenient and flexible.
- * We abuse it two ways:
- * 1. We set currentbucket to NULL when the iteration is finished.
- * 2. We don't bother keeping pseudoindex in synch.
- */
- BTreeItems *pitems;
- } BTreeIter;
-
- /* Return a new iterator object, to traverse the keys and/or values
- * represented by pitems. pitems must not be NULL. Returns NULL if error.
- */
- static BTreeIter *
- BTreeIter_new(BTreeItems *pitems)
- {
- BTreeIter *result;
-
- assert(pitems != NULL);
- result = PyObject_New(BTreeIter, &BTreeIter_Type);
- if (result)
- {
- Py_INCREF(pitems);
- result->pitems = pitems;
- }
- return result;
- }
-
- /* The iterator's tp_dealloc slot. */
- static void
- BTreeIter_dealloc(BTreeIter *bi)
- {
- Py_DECREF(bi->pitems);
- PyObject_Del(bi);
- }
-
- /* The implementation of the iterator's tp_iternext slot. Returns "the next"
- * item; returns NULL if error; returns NULL without setting an error if the
- * iteration is exhausted (that's the way to terminate the iteration protocol).
- */
- static PyObject *
- BTreeIter_next(BTreeIter *bi, PyObject *args)
- {
- PyObject *result = NULL; /* until proven innocent */
- BTreeItems *items = bi->pitems;
- int i = items->currentoffset;
- Bucket *bucket = items->currentbucket;
-
- if (bucket == NULL) /* iteration termination is sticky */
- return NULL;
-
- PER_USE_OR_RETURN(bucket, NULL);
- if (i >= bucket->len)
- {
- /* We never leave this routine normally with i >= len: somebody
- * else mutated the current bucket.
- */
- PyErr_SetString(PyExc_RuntimeError,
- "the bucket being iterated changed size");
- /* Arrange for that this error is sticky too. */
- items->currentoffset = INT_MAX;
- goto Done;
- }
-
- /* Build the result object, from bucket at offset i. */
- result = getBucketEntry(bucket, i, items->kind);
-
- /* Advance position for next call. */
- if (bucket == items->lastbucket && i >= items->last)
- {
- /* Next call should terminate the iteration. */
- Py_DECREF(items->currentbucket);
- items->currentbucket = NULL;
- }
- else
- {
- ++i;
- if (i >= bucket->len)
- {
- Py_XINCREF(bucket->next);
- items->currentbucket = bucket->next;
- Py_DECREF(bucket);
- i = 0;
- }
- items->currentoffset = i;
- }
-
- Done:
- PER_UNUSE(bucket);
- return result;
- }
-
- static PyObject *
- BTreeIter_getiter(PyObject *it)
- {
- Py_INCREF(it);
- return it;
- }
-
- static PyTypeObject BTreeIter_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- MODULE_NAME MOD_NAME_PREFIX "TreeIterator", /* tp_name */
- sizeof(BTreeIter), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)BTreeIter_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /*PyObject_GenericGetAttr,*/ /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)BTreeIter_getiter, /* tp_iter */
- (iternextfunc)BTreeIter_next, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- };
|