Commit 7b65b4e7 authored by Tres Seaver's avatar Tres Seaver

Merge py3k branch.

parents f70f5c92 bbd693c7
...@@ -6,3 +6,4 @@ nosetests.xml ...@@ -6,3 +6,4 @@ nosetests.xml
coverage.xml coverage.xml
*.egg *.egg
docs/_build docs/_build
__pycache__
...@@ -41,7 +41,8 @@ ...@@ -41,7 +41,8 @@
* a search finger weren't being used at all, but is still quadratic time * a search finger weren't being used at all, but is still quadratic time
* in the number of buckets in the slice. * in the number of buckets in the slice.
*/ */
typedef struct { typedef struct
{
PyObject_HEAD PyObject_HEAD
Bucket *firstbucket; /* First bucket */ Bucket *firstbucket; /* First bucket */
Bucket *currentbucket; /* Current bucket (search finger) */ Bucket *currentbucket; /* Current bucket (search finger) */
...@@ -90,7 +91,8 @@ BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero) ...@@ -90,7 +91,8 @@ BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero)
Py_INCREF(b); Py_INCREF(b);
PER_USE_OR_RETURN(b, -1); PER_USE_OR_RETURN(b, -1);
while ((next = b->next)) { while ((next = b->next))
{
r += b->len; r += b->len;
if (nonzero && r > 0) if (nonzero && r > 0)
/* Short-circuit if all we care about is nonempty */ /* Short-circuit if all we care about is nonempty */
...@@ -141,10 +143,12 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i) ...@@ -141,10 +143,12 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
pseudoindex = self->pseudoindex; pseudoindex = self->pseudoindex;
currentoffset = self->currentoffset; currentoffset = self->currentoffset;
currentbucket = self->currentbucket; currentbucket = self->currentbucket;
if (currentbucket == NULL) goto no_match; if (currentbucket == NULL)
goto no_match;
delta = i - pseudoindex; delta = i - pseudoindex;
while (delta > 0) { /* move right */ while (delta > 0) /* move right */
{
int max; int max;
/* Want to move right delta positions; the most we can move right in /* Want to move right delta positions; the most we can move right in
* this bucket is currentbucket->len - currentoffset - 1 positions. * this bucket is currentbucket->len - currentoffset - 1 positions.
...@@ -153,34 +157,41 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i) ...@@ -153,34 +157,41 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
max = currentbucket->len - currentoffset - 1; max = currentbucket->len - currentoffset - 1;
b = currentbucket->next; b = currentbucket->next;
PER_UNUSE(currentbucket); PER_UNUSE(currentbucket);
if (delta <= max) { if (delta <= max)
{
currentoffset += delta; currentoffset += delta;
pseudoindex += delta; pseudoindex += delta;
if (currentbucket == self->lastbucket if (currentbucket == self->lastbucket
&& currentoffset > self->last) goto no_match; && currentoffset > self->last)
goto no_match;
break; break;
} }
/* Move to start of next bucket. */ /* Move to start of next bucket. */
if (currentbucket == self->lastbucket || b == NULL) goto no_match; if (currentbucket == self->lastbucket || b == NULL)
goto no_match;
currentbucket = b; currentbucket = b;
pseudoindex += max + 1; pseudoindex += max + 1;
delta -= max + 1; delta -= max + 1;
currentoffset = 0; currentoffset = 0;
} }
while (delta < 0) { /* move left */ while (delta < 0) /* move left */
{
int status; int status;
/* Want to move left -delta positions; the most we can move left in /* Want to move left -delta positions; the most we can move left in
* this bucket is currentoffset positions. * this bucket is currentoffset positions.
*/ */
if ((-delta) <= currentoffset) { if ((-delta) <= currentoffset)
{
currentoffset += delta; currentoffset += delta;
pseudoindex += delta; pseudoindex += delta;
if (currentbucket == self->firstbucket if (currentbucket == self->firstbucket
&& currentoffset < self->first) goto no_match; && currentoffset < self->first)
goto no_match;
break; break;
} }
/* Move to end of previous bucket. */ /* Move to end of previous bucket. */
if (currentbucket == self->firstbucket) goto no_match; if (currentbucket == self->firstbucket)
goto no_match;
status = PreviousBucket(&currentbucket, self->firstbucket); status = PreviousBucket(&currentbucket, self->firstbucket);
if (status == 0) if (status == 0)
goto no_match; goto no_match;
...@@ -202,7 +213,8 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i) ...@@ -202,7 +213,8 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
PER_USE_OR_RETURN(currentbucket, -1); PER_USE_OR_RETURN(currentbucket, -1);
error = currentoffset < 0 || currentoffset >= currentbucket->len; error = currentoffset < 0 || currentoffset >= currentbucket->len;
PER_UNUSE(currentbucket); PER_UNUSE(currentbucket);
if (error) { if (error)
{
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
"the bucket being iterated changed size"); "the bucket being iterated changed size");
return -1; return -1;
...@@ -232,8 +244,8 @@ getBucketEntry(Bucket *b, int i, char kind) ...@@ -232,8 +244,8 @@ getBucketEntry(Bucket *b, int i, char kind)
assert(b); assert(b);
assert(0 <= i && i < b->len); assert(0 <= i && i < b->len);
switch (kind) { switch (kind)
{
case 'k': case 'k':
COPY_KEY_TO_OBJECT(result, b->keys[i]); COPY_KEY_TO_OBJECT(result, b->keys[i]);
break; break;
...@@ -242,25 +254,30 @@ getBucketEntry(Bucket *b, int i, char kind) ...@@ -242,25 +254,30 @@ getBucketEntry(Bucket *b, int i, char kind)
COPY_VALUE_TO_OBJECT(result, b->values[i]); COPY_VALUE_TO_OBJECT(result, b->values[i]);
break; break;
case 'i': { case 'i':
{
PyObject *key; PyObject *key;
PyObject *value;; PyObject *value;;
COPY_KEY_TO_OBJECT(key, b->keys[i]); COPY_KEY_TO_OBJECT(key, b->keys[i]);
if (!key) break; if (!key)
break;
COPY_VALUE_TO_OBJECT(value, b->values[i]); COPY_VALUE_TO_OBJECT(value, b->values[i]);
if (!value) { if (!value)
{
Py_DECREF(key); Py_DECREF(key);
break; break;
} }
result = PyTuple_New(2); result = PyTuple_New(2);
if (result) { if (result)
{
PyTuple_SET_ITEM(result, 0, key); PyTuple_SET_ITEM(result, 0, key);
PyTuple_SET_ITEM(result, 1, value); PyTuple_SET_ITEM(result, 1, value);
} }
else { else
{
Py_DECREF(key); Py_DECREF(key);
Py_DECREF(value); Py_DECREF(value);
} }
...@@ -289,7 +306,8 @@ BTreeItems_item(BTreeItems *self, Py_ssize_t i) ...@@ -289,7 +306,8 @@ BTreeItems_item(BTreeItems *self, Py_ssize_t i)
{ {
PyObject *result; PyObject *result;
if (BTreeItems_seek(self, i) < 0) return NULL; if (BTreeItems_seek(self, i) < 0)
return NULL;
PER_USE_OR_RETURN(self->currentbucket, NULL); PER_USE_OR_RETURN(self->currentbucket, NULL);
result = getBucketEntry(self->currentbucket, self->currentoffset, result = getBucketEntry(self->currentbucket, self->currentoffset,
...@@ -334,7 +352,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh) ...@@ -334,7 +352,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
*/ */
if (ilow < 0) if (ilow < 0)
ilow = 0; ilow = 0;
else { else
{
if (length < 0) if (length < 0)
length = BTreeItems_length(self); length = BTreeItems_length(self);
if (ilow > length) if (ilow > length)
...@@ -343,7 +362,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh) ...@@ -343,7 +362,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
if (ihigh < ilow) if (ihigh < ilow)
ihigh = ilow; ihigh = ilow;
else { else
{
if (length < 0) if (length < 0)
length = BTreeItems_length(self); length = BTreeItems_length(self);
if (ihigh > length) if (ihigh > length)
...@@ -362,21 +382,24 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh) ...@@ -362,21 +382,24 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
* if we attempt to seek to ilow==1 when the underlying sequence is empty. * 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. * It seems simplest to deal with empty slices as a special case here.
*/ */
if (ilow == ihigh) { if (ilow == ihigh) /* empty slice */
/* empty slice */ {
lowbucket = highbucket = NULL; lowbucket = highbucket = NULL;
lowoffset = 1; lowoffset = 1;
highoffset = 0; highoffset = 0;
} }
else { else
{
assert(ilow < ihigh); assert(ilow < ihigh);
--ihigh; /* exclusive -> inclusive */ --ihigh; /* exclusive -> inclusive */
if (BTreeItems_seek(self, ilow) < 0) return NULL; if (BTreeItems_seek(self, ilow) < 0)
return NULL;
lowbucket = self->currentbucket; lowbucket = self->currentbucket;
lowoffset = self->currentoffset; lowoffset = self->currentoffset;
if (BTreeItems_seek(self, ihigh) < 0) return NULL; if (BTreeItems_seek(self, ihigh) < 0)
return NULL;
highbucket = self->currentbucket; highbucket = self->currentbucket;
highoffset = self->currentoffset; highoffset = self->currentoffset;
...@@ -385,12 +408,65 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh) ...@@ -385,12 +408,65 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
lowbucket, lowoffset, highbucket, highoffset); lowbucket, lowoffset, highbucket, highoffset);
} }
static PySequenceMethods BTreeItems_as_sequence = { static PyObject *
(lenfunc) BTreeItems_length, BTreeItems_subscript(BTreeItems *self, PyObject* subscript)
(binaryfunc)0, {
(ssizeargfunc)0, Py_ssize_t len = BTreeItems_length_or_nonzero(self, 0);
(ssizeargfunc) BTreeItems_item,
(ssizessizeargfunc) BTreeItems_slice, 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!) */ /* Number Method items (just for nb_nonzero!) */
...@@ -402,31 +478,41 @@ BTreeItems_nonzero(BTreeItems *self) ...@@ -402,31 +478,41 @@ BTreeItems_nonzero(BTreeItems *self)
} }
static PyNumberMethods BTreeItems_as_number_for_nonzero = { static PyNumberMethods BTreeItems_as_number_for_nonzero = {
0,0,0,0,0,0,0,0,0,0, 0, /* nb_add */
(inquiry)BTreeItems_nonzero}; 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 = { static PyTypeObject BTreeItemsType = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /*ob_size*/ MOD_NAME_PREFIX "BTreeItems", /* tp_name */
MOD_NAME_PREFIX "BTreeItems", /*tp_name*/ sizeof(BTreeItems), /* tp_basicsize */
sizeof(BTreeItems), /*tp_basicsize*/ 0, /* tp_itemsize */
0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor) BTreeItems_dealloc, /*tp_dealloc*/ (destructor) BTreeItems_dealloc, /* tp_dealloc */
(printfunc)0, /*tp_print*/ 0, /* tp_print */
(getattrfunc)0, /*obsolete tp_getattr*/ 0, /* obsolete tp_getattr */
(setattrfunc)0, /*obsolete tp_setattr*/ 0, /* obsolete tp_setattr */
(cmpfunc)0, /*tp_compare*/ 0, /* tp_compare */
(reprfunc)0, /*tp_repr*/ 0, /* tp_repr */
&BTreeItems_as_number_for_nonzero, /*tp_as_number*/ &BTreeItems_as_number_for_nonzero, /* tp_as_number */
&BTreeItems_as_sequence, /*tp_as_sequence*/ &BTreeItems_as_sequence, /* tp_as_sequence */
0, /*tp_as_mapping*/ &BTreeItems_as_mapping, /* tp_as_mapping */
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /* tp_hash */
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /* tp_call */
(reprfunc)0, /*tp_str*/ (reprfunc)0, /* tp_str */
0, /*tp_getattro*/ 0, /* tp_getattro */
0, /*tp_setattro*/ 0, /* tp_setattro */
/* Space for future expansion */ /* Space for future expansion */
0L,0L, 0L,0L,
"Sequence type used to iterate over BTree items." /* Documentation string */ "Sequence type used to iterate over BTree items." /* Documentation string */
...@@ -445,7 +531,8 @@ newBTreeItems(char kind, ...@@ -445,7 +531,8 @@ newBTreeItems(char kind,
{ {
BTreeItems *self; BTreeItems *self;
UNLESS (self = PyObject_NEW(BTreeItems, &BTreeItemsType)) return NULL; UNLESS (self = PyObject_NEW(BTreeItems, &BTreeItemsType))
return NULL;
self->kind=kind; self->kind=kind;
self->first=lowoffset; self->first=lowoffset;
...@@ -564,7 +651,8 @@ nextTreeSetItems(SetIteration *i) ...@@ -564,7 +651,8 @@ nextTreeSetItems(SetIteration *i)
static PyTypeObject BTreeIter_Type; static PyTypeObject BTreeIter_Type;
/* The type of iterator objects, returned by e.g. iter(IIBTree()). */ /* The type of iterator objects, returned by e.g. iter(IIBTree()). */
typedef struct { typedef struct
{
PyObject_HEAD PyObject_HEAD
/* We use a BTreeItems object because it's convenient and flexible. /* We use a BTreeItems object because it's convenient and flexible.
* We abuse it two ways: * We abuse it two ways:
...@@ -584,7 +672,8 @@ BTreeIter_new(BTreeItems *pitems) ...@@ -584,7 +672,8 @@ BTreeIter_new(BTreeItems *pitems)
assert(pitems != NULL); assert(pitems != NULL);
result = PyObject_New(BTreeIter, &BTreeIter_Type); result = PyObject_New(BTreeIter, &BTreeIter_Type);
if (result) { if (result)
{
Py_INCREF(pitems); Py_INCREF(pitems);
result->pitems = pitems; result->pitems = pitems;
} }
...@@ -615,7 +704,8 @@ BTreeIter_next(BTreeIter *bi, PyObject *args) ...@@ -615,7 +704,8 @@ BTreeIter_next(BTreeIter *bi, PyObject *args)
return NULL; return NULL;
PER_USE_OR_RETURN(bucket, NULL); PER_USE_OR_RETURN(bucket, NULL);
if (i >= bucket->len) { if (i >= bucket->len)
{
/* We never leave this routine normally with i >= len: somebody /* We never leave this routine normally with i >= len: somebody
* else mutated the current bucket. * else mutated the current bucket.
*/ */
...@@ -630,14 +720,17 @@ BTreeIter_next(BTreeIter *bi, PyObject *args) ...@@ -630,14 +720,17 @@ BTreeIter_next(BTreeIter *bi, PyObject *args)
result = getBucketEntry(bucket, i, items->kind); result = getBucketEntry(bucket, i, items->kind);
/* Advance position for next call. */ /* Advance position for next call. */
if (bucket == items->lastbucket && i >= items->last) { if (bucket == items->lastbucket && i >= items->last)
{
/* Next call should terminate the iteration. */ /* Next call should terminate the iteration. */
Py_DECREF(items->currentbucket); Py_DECREF(items->currentbucket);
items->currentbucket = NULL; items->currentbucket = NULL;
} }
else { else
{
++i; ++i;
if (i >= bucket->len) { if (i >= bucket->len)
{
Py_XINCREF(bucket->next); Py_XINCREF(bucket->next);
items->currentbucket = bucket->next; items->currentbucket = bucket->next;
Py_DECREF(bucket); Py_DECREF(bucket);
...@@ -659,8 +752,7 @@ BTreeIter_getiter(PyObject *it) ...@@ -659,8 +752,7 @@ BTreeIter_getiter(PyObject *it)
} }
static PyTypeObject BTreeIter_Type = { static PyTypeObject BTreeIter_Type = {
PyObject_HEAD_INIT(NULL) PyVarObject_HEAD_INIT(NULL, 0)
0, /* ob_size */
MOD_NAME_PREFIX "-iterator", /* tp_name */ MOD_NAME_PREFIX "-iterator", /* tp_name */
sizeof(BTreeIter), /* tp_basicsize */ sizeof(BTreeIter), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "Python.h" #include "Python.h"
/* include structmember.h for offsetof */ /* include structmember.h for offsetof */
#include "structmember.h" #include "structmember.h"
#include "bytesobject.h"
#ifdef PERSISTENT #ifdef PERSISTENT
#include "persistent/cPersistence.h" #include "persistent/cPersistence.h"
...@@ -27,7 +28,7 @@ ...@@ -27,7 +28,7 @@
#define PER_ACCESSED(O) 1 #define PER_ACCESSED(O) 1
#endif #endif
#include "py24compat.h" #include "_compat.h"
/* So sue me. This pair gets used all over the place, so much so that it /* So sue me. This pair gets used all over the place, so much so that it
* interferes with understanding non-persistence parts of algorithms. * interferes with understanding non-persistence parts of algorithms.
...@@ -65,7 +66,7 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;} ...@@ -65,7 +66,7 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define MAX_BTREE_SIZE(B) DEFAULT_MAX_BTREE_SIZE #define MAX_BTREE_SIZE(B) DEFAULT_MAX_BTREE_SIZE
#define MAX_BUCKET_SIZE(B) DEFAULT_MAX_BUCKET_SIZE #define MAX_BUCKET_SIZE(B) DEFAULT_MAX_BUCKET_SIZE
#define SameType_Check(O1, O2) ((O1)->ob_type==(O2)->ob_type) #define SameType_Check(O1, O2) (Py_TYPE((O1))==Py_TYPE((O2)))
#define ASSERT(C, S, R) if (! (C)) { \ #define ASSERT(C, S, R) if (! (C)) { \
PyErr_SetString(PyExc_AssertionError, (S)); return (R); } PyErr_SetString(PyExc_AssertionError, (S)); return (R); }
...@@ -81,7 +82,7 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;} ...@@ -81,7 +82,7 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
static int static int
longlong_check(PyObject *ob) longlong_check(PyObject *ob)
{ {
if (PyInt_Check(ob)) if (INT_CHECK(ob))
return 1; return 1;
if (PyLong_Check(ob)) { if (PyLong_Check(ob)) {
...@@ -101,10 +102,52 @@ longlong_as_object(PY_LONG_LONG val) ...@@ -101,10 +102,52 @@ longlong_as_object(PY_LONG_LONG val)
static PY_LONG_LONG maxint = 0; static PY_LONG_LONG maxint = 0;
if (maxint == 0) if (maxint == 0)
maxint = PyInt_GetMax(); maxint = INT_GETMAX();
if ((val > maxint) || (val < (-maxint-1))) if ((val > maxint) || (val < (-maxint-1)))
return PyLong_FromLongLong(val); return PyLong_FromLongLong(val);
return PyInt_FromLong((long)val); return INT_FROM_LONG((long)val);
}
#endif
#ifdef NEED_LONG_LONG_KEYS
static int
longlong_convert(PyObject *ob, PY_LONG_LONG *value)
{
#ifndef PY3K
if (PyInt_Check(ob))
{
(*value) = (PY_LONG_LONG)PyInt_AS_LONG(ob);
return 1;
}
#endif
if (!PyLong_Check(ob))
{
PyErr_SetString(PyExc_TypeError, "expected integer key");
return 0;
}
else
{
PY_LONG_LONG val;
#if PY_VERSION_HEX < 0x02070000
/* check magnitude */
val = PyLong_AsLongLong(ob);
if (val == -1 && PyErr_Occurred())
goto overflow;
#else
int overflow;
val = PyLong_AsLongLongAndOverflow(ob, &overflow);
if (overflow)
goto overflow;
#endif
(*value) = val;
return 1;
}
overflow:
PyErr_SetString(PyExc_ValueError, "long integer out of range");
return 0;
} }
#endif #endif
...@@ -291,7 +334,7 @@ IndexError(int i) ...@@ -291,7 +334,7 @@ IndexError(int i)
{ {
PyObject *v; PyObject *v;
v = PyInt_FromLong(i); v = INT_FROM_LONG(i);
if (!v) { if (!v) {
v = Py_None; v = Py_None;
Py_INCREF(v); Py_INCREF(v);
...@@ -451,7 +494,11 @@ BTREEITEMSTEMPLATE_C ...@@ -451,7 +494,11 @@ BTREEITEMSTEMPLATE_C
int int
init_persist_type(PyTypeObject *type) init_persist_type(PyTypeObject *type)
{ {
#ifdef PY3K
((PyObject*)type)->ob_type = &PyType_Type;
#else
type->ob_type = &PyType_Type; type->ob_type = &PyType_Type;
#endif
type->tp_base = cPersistenceCAPI->pertype; type->tp_base = cPersistenceCAPI->pertype;
if (PyType_Ready(type) < 0) if (PyType_Ready(type) < 0)
...@@ -460,120 +507,167 @@ init_persist_type(PyTypeObject *type) ...@@ -460,120 +507,167 @@ init_persist_type(PyTypeObject *type)
return 1; return 1;
} }
void #ifdef PY3K
INITMODULE (void) static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"_" MOD_NAME_PREFIX "BTree", /* m_name */
BTree_module_documentation, /* m_doc */
-1, /* m_size */
module_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
static PyObject*
module_init(void)
{ {
PyObject *m, *d, *c; PyObject *module, *mod_dict, *interfaces, *conflicterr;
#ifdef KEY_TYPE_IS_PYOBJECT #ifdef KEY_TYPE_IS_PYOBJECT
object_ = PyTuple_GetItem(Py_None->ob_type->tp_bases, 0); object_ = PyTuple_GetItem(Py_TYPE(Py_None)->tp_bases, 0);
if (object_ == NULL) if (object_ == NULL)
return; return NULL;
#endif #endif
sort_str = PyString_InternFromString("sort"); sort_str = INTERN("sort");
if (!sort_str) if (!sort_str)
return; return NULL;
reverse_str = PyString_InternFromString("reverse"); reverse_str = INTERN("reverse");
if (!reverse_str) if (!reverse_str)
return; return NULL;
__setstate___str = PyString_InternFromString("__setstate__"); __setstate___str = INTERN("__setstate__");
if (!__setstate___str) if (!__setstate___str)
return; return NULL;
_bucket_type_str = PyString_InternFromString("_bucket_type"); _bucket_type_str = INTERN("_bucket_type");
if (!_bucket_type_str) if (!_bucket_type_str)
return; return NULL;
/* Grab the ConflictError class */ /* Grab the ConflictError class */
m = PyImport_ImportModule("BTrees.Interfaces"); interfaces = PyImport_ImportModule("BTrees.Interfaces");
if (m != NULL) { if (interfaces != NULL)
c = PyObject_GetAttrString(m, "BTreesConflictError"); {
if (c != NULL) conflicterr = PyObject_GetAttrString(interfaces, "BTreesConflictError");
ConflictError = c; if (conflicterr != NULL)
Py_DECREF(m); ConflictError = conflicterr;
Py_DECREF(interfaces);
} }
if (ConflictError == NULL) { if (ConflictError == NULL)
{
Py_INCREF(PyExc_ValueError); Py_INCREF(PyExc_ValueError);
ConflictError=PyExc_ValueError; ConflictError=PyExc_ValueError;
} }
/* Initialize the PyPersist_C_API and the type objects. */ /* Initialize the PyPersist_C_API and the type objects. */
cPersistenceCAPI = PyCObject_Import("persistent.cPersistence", "CAPI"); #ifdef PY3K
cPersistenceCAPI = (cPersistenceCAPIstruct *)PyCapsule_Import(
"persistent.cPersistence.CAPI", 0);
#else
cPersistenceCAPI = (cPersistenceCAPIstruct *)PyCObject_Import(
"persistent.cPersistence", "CAPI");
#endif
if (cPersistenceCAPI == NULL) if (cPersistenceCAPI == NULL)
return; return NULL;
BTreeItemsType.ob_type = &PyType_Type; #ifdef PY3K
BTreeIter_Type.ob_type = &PyType_Type; #define _SET_TYPE(typ) ((PyObject*)(&typ))->ob_type = &PyType_Type
#else
#define _SET_TYPE(typ) (typ).ob_type = &PyType_Type
#endif
_SET_TYPE(BTreeItemsType);
_SET_TYPE(BTreeIter_Type);
BTreeIter_Type.tp_getattro = PyObject_GenericGetAttr; BTreeIter_Type.tp_getattro = PyObject_GenericGetAttr;
BucketType.tp_new = PyType_GenericNew; BucketType.tp_new = PyType_GenericNew;
SetType.tp_new = PyType_GenericNew; SetType.tp_new = PyType_GenericNew;
BTreeType.tp_new = PyType_GenericNew; BTreeType.tp_new = PyType_GenericNew;
TreeSetType.tp_new = PyType_GenericNew; TreeSetType.tp_new = PyType_GenericNew;
if (!init_persist_type(&BucketType)) if (!init_persist_type(&BucketType))
return; return NULL;
if (!init_persist_type(&BTreeType)) if (!init_persist_type(&BTreeType))
return; return NULL;
if (!init_persist_type(&SetType)) if (!init_persist_type(&SetType))
return; return NULL;
if (!init_persist_type(&TreeSetType)) if (!init_persist_type(&TreeSetType))
return; return NULL;
if (PyDict_SetItem(BTreeType.tp_dict, _bucket_type_str, if (PyDict_SetItem(BTreeType.tp_dict, _bucket_type_str,
(PyObject *)&BucketType) < 0) { (PyObject *)&BucketType) < 0)
{
fprintf(stderr, "btree failed\n"); fprintf(stderr, "btree failed\n");
return; return NULL;
} }
if (PyDict_SetItem(TreeSetType.tp_dict, _bucket_type_str, if (PyDict_SetItem(TreeSetType.tp_dict, _bucket_type_str,
(PyObject *)&SetType) < 0) { (PyObject *)&SetType) < 0)
{
fprintf(stderr, "bucket failed\n"); fprintf(stderr, "bucket failed\n");
return; return NULL;
} }
/* Create the module and add the functions */ /* Create the module and add the functions */
m = Py_InitModule4("_" MOD_NAME_PREFIX "BTree", #ifdef PY3K
module = PyModule_Create(&moduledef);
#else
module = Py_InitModule4("_" MOD_NAME_PREFIX "BTree",
module_methods, BTree_module_documentation, module_methods, BTree_module_documentation,
(PyObject *)NULL, PYTHON_API_VERSION); (PyObject *)NULL, PYTHON_API_VERSION);
#endif
/* Add some symbolic constants to the module */ /* Add some symbolic constants to the module */
d = PyModule_GetDict(m); mod_dict = PyModule_GetDict(module);
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Bucket", if (PyDict_SetItemString(mod_dict, MOD_NAME_PREFIX "Bucket",
(PyObject *)&BucketType) < 0) (PyObject *)&BucketType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "BTree", if (PyDict_SetItemString(mod_dict, MOD_NAME_PREFIX "BTree",
(PyObject *)&BTreeType) < 0) (PyObject *)&BTreeType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Set", if (PyDict_SetItemString(mod_dict, MOD_NAME_PREFIX "Set",
(PyObject *)&SetType) < 0) (PyObject *)&SetType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "TreeSet", if (PyDict_SetItemString(mod_dict, MOD_NAME_PREFIX "TreeSet",
(PyObject *)&TreeSetType) < 0) (PyObject *)&TreeSetType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "TreeIterator", if (PyDict_SetItemString(mod_dict, MOD_NAME_PREFIX "TreeIterator",
(PyObject *)&BTreeIter_Type) < 0) (PyObject *)&BTreeIter_Type) < 0)
return; return NULL;
/* We also want to be able to access these constants without the prefix /* We also want to be able to access these constants without the prefix
* so that code can more easily exchange modules (particularly the integer * so that code can more easily exchange modules (particularly the integer
* and long modules, but also others). The TreeIterator is only internal, * and long modules, but also others). The TreeIterator is only internal,
* so we don't bother to expose that. * so we don't bother to expose that.
*/ */
if (PyDict_SetItemString(d, "Bucket", if (PyDict_SetItemString(mod_dict, "Bucket",
(PyObject *)&BucketType) < 0) (PyObject *)&BucketType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, "BTree", if (PyDict_SetItemString(mod_dict, "BTree",
(PyObject *)&BTreeType) < 0) (PyObject *)&BTreeType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, "Set", if (PyDict_SetItemString(mod_dict, "Set",
(PyObject *)&SetType) < 0) (PyObject *)&SetType) < 0)
return; return NULL;
if (PyDict_SetItemString(d, "TreeSet", if (PyDict_SetItemString(mod_dict, "TreeSet",
(PyObject *)&TreeSetType) < 0) (PyObject *)&TreeSetType) < 0)
return; return NULL;
#if defined(ZODB_64BIT_INTS) && defined(NEED_LONG_LONG_SUPPORT) #if defined(ZODB_64BIT_INTS) && defined(NEED_LONG_LONG_SUPPORT)
if (PyDict_SetItemString(d, "using64bits", Py_True) < 0) if (PyDict_SetItemString(mod_dict, "using64bits", Py_True) < 0)
return; return NULL;
#else #else
if (PyDict_SetItemString(d, "using64bits", Py_False) < 0) if (PyDict_SetItemString(mod_dict, "using64bits", Py_False) < 0)
return; return NULL;
#endif #endif
return module;
} }
#ifdef PY3K
PyMODINIT_FUNC INITMODULE(void)
{
return module_init();
}
#else
PyMODINIT_FUNC INITMODULE(void)
{
module_init();
}
#endif
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE FOR A PARTICULAR PURPOSE
****************************************************************************/ ****************************************************************************/
#include "_compat.h"
#define BTREETEMPLATE_C "$Id$\n" #define BTREETEMPLATE_C "$Id$\n"
...@@ -42,8 +43,8 @@ BTree_check_inner(BTree *self, Bucket *nextbucket) ...@@ -42,8 +43,8 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
PER_USE_OR_RETURN(self, -1); PER_USE_OR_RETURN(self, -1);
CHECK(self->len >= 0, "BTree len < 0"); CHECK(self->len >= 0, "BTree len < 0");
CHECK(self->len <= self->size, "BTree len > size"); CHECK(self->len <= self->size, "BTree len > size");
if (self->len == 0) { if (self->len == 0) /* Empty BTree. */
/* Empty BTree. */ {
CHECK(self->firstbucket == NULL, CHECK(self->firstbucket == NULL,
"Empty BTree has non-NULL firstbucket"); "Empty BTree has non-NULL firstbucket");
result = 0; result = 0;
...@@ -59,58 +60,67 @@ BTree_check_inner(BTree *self, Bucket *nextbucket) ...@@ -59,58 +60,67 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
* on self's pointers being intact. * on self's pointers being intact.
*/ */
#ifdef PERSISTENT #ifdef PERSISTENT
CHECK(self->firstbucket->ob_refcnt >= 1, CHECK(Py_REFCNT(self->firstbucket) >= 1,
"Non-empty BTree firstbucket has refcount < 1"); "Non-empty BTree firstbucket has refcount < 1");
#else #else
CHECK(self->firstbucket->ob_refcnt >= 2, CHECK(Py_REFCNT(self->firstbucket) >= 2,
"Non-empty BTree firstbucket has refcount < 2"); "Non-empty BTree firstbucket has refcount < 2");
#endif #endif
for (i = 0; i < self->len; ++i) { for (i = 0; i < self->len; ++i)
{
CHECK(self->data[i].child != NULL, "BTree has NULL child"); CHECK(self->data[i].child != NULL, "BTree has NULL child");
} }
if (SameType_Check(self, self->data[0].child)) { if (SameType_Check(self, self->data[0].child))
{
/* Our children are also BTrees. */ /* Our children are also BTrees. */
child = self->data[0].child; child = self->data[0].child;
UNLESS (PER_USE(child)) goto Done; UNLESS (PER_USE(child))
goto Done;
activated_child = child; activated_child = child;
CHECK(self->firstbucket == BTREE(child)->firstbucket, CHECK(self->firstbucket == BTREE(child)->firstbucket,
"BTree has firstbucket different than " "BTree has firstbucket different than "
"its first child's firstbucket"); "its first child's firstbucket");
PER_ALLOW_DEACTIVATION(child); PER_ALLOW_DEACTIVATION(child);
activated_child = NULL; activated_child = NULL;
for (i = 0; i < self->len; ++i) { for (i = 0; i < self->len; ++i)
{
child = self->data[i].child; child = self->data[i].child;
CHECK(SameType_Check(self, child), CHECK(SameType_Check(self, child),
"BTree children have different types"); "BTree children have different types");
if (i == self->len - 1) if (i == self->len - 1)
bucketafter = nextbucket; bucketafter = nextbucket;
else { else
{
BTree *child2 = BTREE(self->data[i+1].child); BTree *child2 = BTREE(self->data[i+1].child);
UNLESS (PER_USE(child2)) goto Done; UNLESS (PER_USE(child2))
goto Done;
bucketafter = child2->firstbucket; bucketafter = child2->firstbucket;
PER_ALLOW_DEACTIVATION(child2); PER_ALLOW_DEACTIVATION(child2);
} }
if (BTree_check_inner(BTREE(child), bucketafter) < 0) goto Done; if (BTree_check_inner(BTREE(child), bucketafter) < 0)
goto Done;
} }
} }
else { else /* Our children are buckets. */
/* Our children are buckets. */ {
CHECK(self->firstbucket == BUCKET(self->data[0].child), CHECK(self->firstbucket == BUCKET(self->data[0].child),
"Bottom-level BTree node has inconsistent firstbucket belief"); "Bottom-level BTree node has inconsistent firstbucket belief");
for (i = 0; i < self->len; ++i) { for (i = 0; i < self->len; ++i)
{
child = self->data[i].child; child = self->data[i].child;
UNLESS (PER_USE(child)) goto Done; UNLESS (PER_USE(child))
goto Done;
activated_child = child; activated_child = child;
CHECK(!SameType_Check(self, child), CHECK(!SameType_Check(self, child),
"BTree children have different types"); "BTree children have different types");
CHECK(child->len >= 1, "Bucket length < 1"); /* no empty buckets! */ CHECK(child->len >= 1, "Bucket length < 1");/* no empty buckets! */
CHECK(child->len <= child->size, "Bucket len > size"); CHECK(child->len <= child->size, "Bucket len > size");
#ifdef PERSISTENT #ifdef PERSISTENT
CHECK(child->ob_refcnt >= 1, "Bucket has refcount < 1"); CHECK(Py_REFCNT(child) >= 1, "Bucket has refcount < 1");
#else #else
CHECK(child->ob_refcnt >= 2, "Bucket has refcount < 2"); CHECK(Py_REFCNT(child) >= 2, "Bucket has refcount < 2");
#endif #endif
if (i == self->len - 1) if (i == self->len - 1)
bucketafter = nextbucket; bucketafter = nextbucket;
...@@ -125,13 +135,15 @@ BTree_check_inner(BTree *self, Bucket *nextbucket) ...@@ -125,13 +135,15 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
result = 0; result = 0;
goto Done; goto Done;
Error: Error:
PyErr_SetString(PyExc_AssertionError, errormsg); PyErr_SetString(PyExc_AssertionError, errormsg);
result = -1; result = -1;
Done:
Done:
/* No point updating access time -- this isn't a "real" use. */ /* No point updating access time -- this isn't a "real" use. */
PER_ALLOW_DEACTIVATION(self); PER_ALLOW_DEACTIVATION(self);
if (activated_child) { if (activated_child)
{
PER_ALLOW_DEACTIVATION(activated_child); PER_ALLOW_DEACTIVATION(activated_child);
} }
return result; return result;
...@@ -150,7 +162,8 @@ BTree_check(BTree *self) ...@@ -150,7 +162,8 @@ BTree_check(BTree *self)
PyObject *result = NULL; PyObject *result = NULL;
int i = BTree_check_inner(self, NULL); int i = BTree_check_inner(self, NULL);
if (i >= 0) { if (i >= 0)
{
result = Py_None; result = Py_None;
Py_INCREF(result); Py_INCREF(result);
} }
...@@ -187,34 +200,39 @@ _BTree_get(BTree *self, PyObject *keyarg, int has_key) ...@@ -187,34 +200,39 @@ _BTree_get(BTree *self, PyObject *keyarg, int has_key)
UNLESS (copied) return NULL; UNLESS (copied) return NULL;
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
if (self->len == 0) { if (self->len == 0)
{
/* empty BTree */ /* empty BTree */
if (has_key) if (has_key)
result = PyInt_FromLong(0); result = INT_FROM_LONG(0);
else else
PyErr_SetObject(PyExc_KeyError, keyarg); PyErr_SetObject(PyExc_KeyError, keyarg);
} }
else { else
for (;;) { {
for (;;)
{
int i; int i;
Sized *child; Sized *child;
BTREE_SEARCH(i, self, key, goto Done); BTREE_SEARCH(i, self, key, goto Done);
child = self->data[i].child; child = self->data[i].child;
has_key += has_key != 0; /* bump depth counter, maybe */ has_key += has_key != 0; /* bump depth counter, maybe */
if (SameType_Check(self, child)) { if (SameType_Check(self, child))
{
PER_UNUSE(self); PER_UNUSE(self);
self = BTREE(child); self = BTREE(child);
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
} }
else { else
{
result = _bucket_get(BUCKET(child), keyarg, has_key); result = _bucket_get(BUCKET(child), keyarg, has_key);
break; break;
} }
} }
} }
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return result; return result;
} }
...@@ -236,7 +254,7 @@ BTree_newBucket(BTree *self) ...@@ -236,7 +254,7 @@ BTree_newBucket(BTree *self)
Sized *result; Sized *result;
/* _bucket_type_str defined in BTreeModuleTemplate.c */ /* _bucket_type_str defined in BTreeModuleTemplate.c */
factory = PyObject_GetAttr((PyObject *)self->ob_type, _bucket_type_str); factory = PyObject_GetAttr((PyObject *)Py_TYPE(self), _bucket_type_str);
if (factory == NULL) if (factory == NULL)
return NULL; return NULL;
/* TODO: Should we check that the factory actually returns something /* TODO: Should we check that the factory actually returns something
...@@ -282,7 +300,8 @@ BTree_split(BTree *self, int index, BTree *next) ...@@ -282,7 +300,8 @@ BTree_split(BTree *self, int index, BTree *next)
/* Set next's firstbucket. self->firstbucket is still correct. */ /* Set next's firstbucket. self->firstbucket is still correct. */
child = next->data[0].child; child = next->data[0].child;
if (SameType_Check(self, child)) { if (SameType_Check(self, child))
{
PER_USE_OR_RETURN(child, -1); PER_USE_OR_RETURN(child, -1);
next->firstbucket = BTREE(child)->firstbucket; next->firstbucket = BTREE(child)->firstbucket;
PER_UNUSE(child); PER_UNUSE(child);
...@@ -318,8 +337,9 @@ BTree_split_root(BTree *self, int noval) ...@@ -318,8 +337,9 @@ BTree_split_root(BTree *self, int noval)
BTreeItem *d; BTreeItem *d;
/* Create a child BTree, and a new data vector for self. */ /* Create a child BTree, and a new data vector for self. */
child = BTREE(PyObject_CallObject(OBJECT(self->ob_type), NULL)); child = BTREE(PyObject_CallObject(OBJECT(Py_TYPE(self)), NULL));
if (!child) return -1; if (!child)
return -1;
d = BTree_Malloc(sizeof(BTreeItem) * 2); d = BTree_Malloc(sizeof(BTreeItem) * 2);
if (!d) { if (!d) {
...@@ -368,15 +388,18 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -368,15 +388,18 @@ BTree_grow(BTree *self, int index, int noval)
Sized *v, *e = 0; Sized *v, *e = 0;
BTreeItem *d; BTreeItem *d;
if (self->len == self->size) { if (self->len == self->size)
if (self->size) { {
if (self->size)
{
d = BTree_Realloc(self->data, sizeof(BTreeItem) * self->size * 2); d = BTree_Realloc(self->data, sizeof(BTreeItem) * self->size * 2);
if (d == NULL) if (d == NULL)
return -1; return -1;
self->data = d; self->data = d;
self->size *= 2; self->size *= 2;
} }
else { else
{
d = BTree_Malloc(sizeof(BTreeItem) * 2); d = BTree_Malloc(sizeof(BTreeItem) * 2);
if (d == NULL) if (d == NULL)
return -1; return -1;
...@@ -385,15 +408,17 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -385,15 +408,17 @@ BTree_grow(BTree *self, int index, int noval)
} }
} }
if (self->len) { if (self->len)
{
d = self->data + index; d = self->data + index;
v = d->child; v = d->child;
/* Create a new object of the same type as the target value */ /* Create a new object of the same type as the target value */
e = (Sized *)PyObject_CallObject((PyObject *)v->ob_type, NULL); e = (Sized *)PyObject_CallObject((PyObject *)Py_TYPE(v), NULL);
if (e == NULL) if (e == NULL)
return -1; return -1;
UNLESS(PER_USE(v)) { UNLESS(PER_USE(v))
{
Py_DECREF(e); Py_DECREF(e);
return -1; return -1;
} }
...@@ -405,7 +430,8 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -405,7 +430,8 @@ BTree_grow(BTree *self, int index, int noval)
i = bucket_split((Bucket *)v, -1, (Bucket *)e); i = bucket_split((Bucket *)v, -1, (Bucket *)e);
PER_ALLOW_DEACTIVATION(v); PER_ALLOW_DEACTIVATION(v);
if (i < 0) { if (i < 0)
{
Py_DECREF(e); Py_DECREF(e);
assert(PyErr_Occurred()); assert(PyErr_Occurred());
return -1; return -1;
...@@ -416,7 +442,8 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -416,7 +442,8 @@ BTree_grow(BTree *self, int index, int noval)
if (self->len > index) /* Shift up the old values one array slot */ if (self->len > index) /* Shift up the old values one array slot */
memmove(d+1, d, sizeof(BTreeItem)*(self->len-index)); memmove(d+1, d, sizeof(BTreeItem)*(self->len-index));
if (SameType_Check(self, v)) { if (SameType_Check(self, v))
{
COPY_KEY(d->key, BTREE(e)->data->key); COPY_KEY(d->key, BTREE(e)->data->key);
/* We take the unused reference from e, so there's no /* We take the unused reference from e, so there's no
...@@ -424,7 +451,8 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -424,7 +451,8 @@ BTree_grow(BTree *self, int index, int noval)
*/ */
/* INCREF_KEY(self->data[1].key); */ /* INCREF_KEY(self->data[1].key); */
} }
else { else
{
COPY_KEY(d->key, BUCKET(e)->keys[0]); COPY_KEY(d->key, BUCKET(e)->keys[0]);
INCREF_KEY(d->key); INCREF_KEY(d->key);
} }
...@@ -434,7 +462,8 @@ BTree_grow(BTree *self, int index, int noval) ...@@ -434,7 +462,8 @@ BTree_grow(BTree *self, int index, int noval)
if (self->len >= MAX_BTREE_SIZE(self) * 2) /* the root is huge */ if (self->len >= MAX_BTREE_SIZE(self) * 2) /* the root is huge */
return BTree_split_root(self, noval); return BTree_split_root(self, noval);
} }
else { else
{
/* The BTree is empty. Create an empty bucket. See CAUTION in /* The BTree is empty. Create an empty bucket. See CAUTION in
* the comments preceding. * the comments preceding.
*/ */
...@@ -468,19 +497,22 @@ BTree_lastBucket(BTree *self) ...@@ -468,19 +497,22 @@ BTree_lastBucket(BTree *self)
Sized *pchild; Sized *pchild;
Bucket *result; Bucket *result;
UNLESS (self->data && self->len) { UNLESS (self->data && self->len)
{
IndexError(-1); /* is this the best action to take? */ IndexError(-1); /* is this the best action to take? */
return NULL; return NULL;
} }
pchild = self->data[self->len - 1].child; pchild = self->data[self->len - 1].child;
if (SameType_Check(self, pchild)) { if (SameType_Check(self, pchild))
{
self = BTREE(pchild); self = BTREE(pchild);
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
result = BTree_lastBucket(self); result = BTree_lastBucket(self);
PER_UNUSE(self); PER_UNUSE(self);
} }
else { else
{
Py_INCREF(pchild); Py_INCREF(pchild);
result = BUCKET(pchild); result = BUCKET(pchild);
} }
...@@ -492,7 +524,8 @@ BTree_deleteNextBucket(BTree *self) ...@@ -492,7 +524,8 @@ BTree_deleteNextBucket(BTree *self)
{ {
Bucket *b; Bucket *b;
UNLESS (PER_USE(self)) return -1; UNLESS (PER_USE(self))
return -1;
b = BTree_lastBucket(self); b = BTree_lastBucket(self);
if (b == NULL) if (b == NULL)
...@@ -505,7 +538,7 @@ BTree_deleteNextBucket(BTree *self) ...@@ -505,7 +538,7 @@ BTree_deleteNextBucket(BTree *self)
return 0; return 0;
err: err:
Py_XDECREF(b); Py_XDECREF(b);
PER_ALLOW_DEACTIVATION(self); PER_ALLOW_DEACTIVATION(self);
return -1; return -1;
...@@ -538,7 +571,8 @@ _BTree_clear(BTree *self) ...@@ -538,7 +571,8 @@ _BTree_clear(BTree *self)
{ {
const int len = self->len; const int len = self->len;
if (self->firstbucket) { if (self->firstbucket)
{
/* Obscure: The first bucket is pointed to at least by /* Obscure: The first bucket is pointed to at least by
* self->firstbucket and data[0].child of whichever BTree node it's * self->firstbucket and data[0].child of whichever BTree node it's
* a child of. However, if persistence is enabled then the latter * a child of. However, if persistence is enabled then the latter
...@@ -546,23 +580,26 @@ _BTree_clear(BTree *self) ...@@ -546,23 +580,26 @@ _BTree_clear(BTree *self)
* count": we can only rely on self's pointers being intact. * count": we can only rely on self's pointers being intact.
*/ */
#ifdef PERSISTENT #ifdef PERSISTENT
ASSERT(self->firstbucket->ob_refcnt > 0, ASSERT(Py_REFCNT(self->firstbucket) > 0,
"Invalid firstbucket pointer", -1); "Invalid firstbucket pointer", -1);
#else #else
ASSERT(self->firstbucket->ob_refcnt > 1, ASSERT(Py_REFCNT(self->firstbucket) > 1,
"Invalid firstbucket pointer", -1); "Invalid firstbucket pointer", -1);
#endif #endif
Py_DECREF(self->firstbucket); Py_DECREF(self->firstbucket);
self->firstbucket = NULL; self->firstbucket = NULL;
} }
if (self->data) { if (self->data)
{
int i; int i;
if (len > 0) { /* 0 is special because key 0 is trash */ if (len > 0) /* 0 is special because key 0 is trash */
{
Py_DECREF(self->data[0].child); Py_DECREF(self->data[0].child);
} }
for (i = 1; i < len; i++) { for (i = 1; i < len; i++)
{
#ifdef KEY_TYPE_IS_PYOBJECT #ifdef KEY_TYPE_IS_PYOBJECT
DECREF_KEY(self->data[i].key); DECREF_KEY(self->data[i].key);
#endif #endif
...@@ -617,18 +654,22 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -617,18 +654,22 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
int copied = 1; int copied = 1;
COPY_KEY_FROM_ARG(key, keyarg, copied); COPY_KEY_FROM_ARG(key, keyarg, copied);
if (!copied) return -1; if (!copied)
return -1;
PER_USE_OR_RETURN(self, -1); PER_USE_OR_RETURN(self, -1);
self_was_empty = self->len == 0; self_was_empty = self->len == 0;
if (self_was_empty) { if (self_was_empty)
{
/* We're empty. Make room. */ /* We're empty. Make room. */
if (value) { if (value)
{
if (BTree_grow(self, 0, noval) < 0) if (BTree_grow(self, 0, noval) < 0)
goto Error; goto Error;
} }
else { else
{
/* Can't delete a key from an empty BTree. */ /* Can't delete a key from an empty BTree. */
PyErr_SetObject(PyExc_KeyError, keyarg); PyErr_SetObject(PyExc_KeyError, keyarg);
goto Error; goto Error;
...@@ -645,7 +686,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -645,7 +686,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
if (SameType_Check(self, d->child)) if (SameType_Check(self, d->child))
status = _BTree_set(BTREE(d->child), keyarg, value, unique, noval); status = _BTree_set(BTREE(d->child), keyarg, value, unique, noval);
else { else
{
int bucket_changed = 0; int bucket_changed = 0;
status = _bucket_set(BUCKET(d->child), keyarg, status = _bucket_set(BUCKET(d->child), keyarg,
value, unique, noval, &bucket_changed); value, unique, noval, &bucket_changed);
...@@ -664,19 +706,23 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -664,19 +706,23 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
} }
#endif #endif
} }
if (status == 0) goto Done; if (status == 0)
if (status < 0) goto Error; goto Done;
if (status < 0)
goto Error;
assert(status == 1 || status == 2); assert(status == 1 || status == 2);
/* The child changed size. Get its new size. Note that since the tree /* The child changed size. Get its new size. Note that since the tree
* rooted at the child changed size, so did the tree rooted at self: * rooted at the child changed size, so did the tree rooted at self:
* our status must be >= 1 too. * our status must be >= 1 too.
*/ */
UNLESS(PER_USE(d->child)) goto Error; UNLESS(PER_USE(d->child))
goto Error;
childlength = d->child->len; childlength = d->child->len;
PER_UNUSE(d->child); PER_UNUSE(d->child);
if (value) { if (value)
{
/* A bucket got bigger -- if it's "too big", split it. */ /* A bucket got bigger -- if it's "too big", split it. */
int toobig; int toobig;
...@@ -687,7 +733,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -687,7 +733,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
toobig = childlength > MAX_BUCKET_SIZE(d->child); toobig = childlength > MAX_BUCKET_SIZE(d->child);
if (toobig) { if (toobig) {
if (BTree_grow(self, min, noval) < 0) goto Error; if (BTree_grow(self, min, noval) < 0)
goto Error;
changed = 1; /* BTree_grow mutated self */ changed = 1; /* BTree_grow mutated self */
} }
goto Done; /* and status still == 1 */ goto Done; /* and status still == 1 */
...@@ -706,45 +753,53 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -706,45 +753,53 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
*/ */
int _cmp = 1; int _cmp = 1;
TEST_KEY_SET_OR(_cmp, key, d->key) goto Error; TEST_KEY_SET_OR(_cmp, key, d->key) goto Error;
if (_cmp == 0) if (_cmp == 0) /* Need to replace key with first key from child */
{ /* Need to replace key with first key from child */ {
Bucket *bucket; Bucket *bucket;
if (SameType_Check(self, d->child)) if (SameType_Check(self, d->child))
{ {
UNLESS(PER_USE(d->child)) goto Error; UNLESS(PER_USE(d->child))
goto Error;
bucket = BTREE(d->child)->firstbucket; bucket = BTREE(d->child)->firstbucket;
PER_UNUSE(d->child); PER_UNUSE(d->child);
} }
else else
bucket = BUCKET(d->child); bucket = BUCKET(d->child);
UNLESS(PER_USE(bucket)) goto Error; UNLESS(PER_USE(bucket))
goto Error;
DECREF_KEY(d->key); DECREF_KEY(d->key);
COPY_KEY(d->key, bucket->keys[0]); COPY_KEY(d->key, bucket->keys[0]);
INCREF_KEY(d->key); INCREF_KEY(d->key);
PER_UNUSE(bucket); PER_UNUSE(bucket);
if (PER_CHANGED(self) < 0) goto Error; if (PER_CHANGED(self) < 0)
goto Error;
} }
} }
if (status == 2) { if (status == 2)
{
/* The child must be a BTree because bucket.set never returns 2 */ /* The child must be a BTree because bucket.set never returns 2 */
/* Two problems to solve: May have to adjust our own firstbucket, /* Two problems to solve: May have to adjust our own firstbucket,
* and the bucket that went away needs to get unlinked. * and the bucket that went away needs to get unlinked.
*/ */
if (min) { if (min)
{
/* This wasn't our firstbucket, so no need to adjust ours (note /* This wasn't our firstbucket, so no need to adjust ours (note
* that it can't be the firstbucket of any node above us either). * that it can't be the firstbucket of any node above us either).
* Tell "the tree to the left" to do the unlinking. * Tell "the tree to the left" to do the unlinking.
*/ */
if (BTree_deleteNextBucket(BTREE(d[-1].child)) < 0) goto Error; if (BTree_deleteNextBucket(BTREE(d[-1].child)) < 0)
goto Error;
status = 1; /* we solved the child's firstbucket problem */ status = 1; /* we solved the child's firstbucket problem */
} }
else { else
{
/* This was our firstbucket. Update to new firstbucket value. */ /* This was our firstbucket. Update to new firstbucket value. */
Bucket *nextbucket; Bucket *nextbucket;
UNLESS(PER_USE(d->child)) goto Error; UNLESS(PER_USE(d->child))
goto Error;
nextbucket = BTREE(d->child)->firstbucket; nextbucket = BTREE(d->child)->firstbucket;
PER_UNUSE(d->child); PER_UNUSE(d->child);
...@@ -764,30 +819,36 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -764,30 +819,36 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
* us to do with the firstbucket problems the child gave us, and since the * us to do with the firstbucket problems the child gave us, and since the
* child isn't empty don't create any new firstbucket problems of our own. * child isn't empty don't create any new firstbucket problems of our own.
*/ */
if (childlength) goto Done; if (childlength)
goto Done;
/* The child became empty: we need to remove it from self->data. /* The child became empty: we need to remove it from self->data.
* But first, if we're a bottom-level node, we've got more bucket-fiddling * But first, if we're a bottom-level node, we've got more bucket-fiddling
* to set up. * to set up.
*/ */
if (! SameType_Check(self, d->child)) { if (! SameType_Check(self, d->child))
{
/* We're about to delete a bucket, so need to adjust bucket pointers. */ /* We're about to delete a bucket, so need to adjust bucket pointers. */
if (min) { if (min)
{
/* It's not our first bucket, so we can tell the previous /* It's not our first bucket, so we can tell the previous
* bucket to adjust its reference to it. It can't be anyone * bucket to adjust its reference to it. It can't be anyone
* else's first bucket either, so the caller needn't do anything. * else's first bucket either, so the caller needn't do anything.
*/ */
if (Bucket_deleteNextBucket(BUCKET(d[-1].child)) < 0) goto Error; if (Bucket_deleteNextBucket(BUCKET(d[-1].child)) < 0)
goto Error;
/* status should be 1, and already is: if it were 2, the /* status should be 1, and already is: if it were 2, the
* block above would have set it to 1 in its min != 0 branch. * block above would have set it to 1 in its min != 0 branch.
*/ */
assert(status == 1); assert(status == 1);
} }
else { else
{
Bucket *nextbucket; Bucket *nextbucket;
/* It's our first bucket. We can't unlink it directly. */ /* It's our first bucket. We can't unlink it directly. */
/* 'changed' will be set true by the deletion code following. */ /* 'changed' will be set true by the deletion code following. */
UNLESS(PER_USE(d->child)) goto Error; UNLESS(PER_USE(d->child))
goto Error;
nextbucket = BUCKET(d->child)->next; nextbucket = BUCKET(d->child)->next;
PER_UNUSE(d->child); PER_UNUSE(d->child);
...@@ -802,10 +863,12 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -802,10 +863,12 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
/* Remove the child from self->data. */ /* Remove the child from self->data. */
Py_DECREF(d->child); Py_DECREF(d->child);
#ifdef KEY_TYPE_IS_PYOBJECT #ifdef KEY_TYPE_IS_PYOBJECT
if (min) { if (min)
{
DECREF_KEY(d->key); DECREF_KEY(d->key);
} }
else if (self->len > 1) { else if (self->len > 1)
{
/* We're deleting the first child of a BTree with more than one /* We're deleting the first child of a BTree with more than one
* child. The key at d+1 is about to be shifted into slot 0, * child. The key at d+1 is about to be shifted into slot 0,
* and hence never to be referenced again (the key in slot 0 is * and hence never to be referenced again (the key in slot 0 is
...@@ -822,18 +885,21 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value, ...@@ -822,18 +885,21 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
memmove(d, d+1, (self->len - min) * sizeof(BTreeItem)); memmove(d, d+1, (self->len - min) * sizeof(BTreeItem));
changed = 1; changed = 1;
Done: Done:
#ifdef PERSISTENT #ifdef PERSISTENT
if (changed) { if (changed)
if (PER_CHANGED(self) < 0) goto Error; {
if (PER_CHANGED(self) < 0)
goto Error;
} }
#endif #endif
PER_UNUSE(self); PER_UNUSE(self);
return status; return status;
Error: Error:
assert(PyErr_Occurred()); assert(PyErr_Occurred());
if (self_was_empty) { if (self_was_empty)
{
/* BTree_grow may have left the BTree in an invalid state. Make /* BTree_grow may have left the BTree in an invalid state. Make
* sure the tree is a legitimate empty tree. * sure the tree is a legitimate empty tree.
*/ */
...@@ -870,32 +936,38 @@ BTree__p_deactivate(BTree *self, PyObject *args, PyObject *keywords) ...@@ -870,32 +936,38 @@ BTree__p_deactivate(BTree *self, PyObject *args, PyObject *keywords)
int ghostify = 1; int ghostify = 1;
PyObject *force = NULL; PyObject *force = NULL;
if (args && PyTuple_GET_SIZE(args) > 0) { if (args && PyTuple_GET_SIZE(args) > 0)
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_deactivate takes not positional arguments"); "_p_deactivate takes not positional arguments");
return NULL; return NULL;
} }
if (keywords) { if (keywords)
{
int size = PyDict_Size(keywords); int size = PyDict_Size(keywords);
force = PyDict_GetItemString(keywords, "force"); force = PyDict_GetItemString(keywords, "force");
if (force) if (force)
size--; size--;
if (size) { if (size)
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_deactivate only accepts keyword arg force"); "_p_deactivate only accepts keyword arg force");
return NULL; return NULL;
} }
} }
if (self->jar && self->oid) { if (self->jar && self->oid)
{
ghostify = self->state == cPersistent_UPTODATE_STATE; ghostify = self->state == cPersistent_UPTODATE_STATE;
if (!ghostify && force) { if (!ghostify && force)
{
if (PyObject_IsTrue(force)) if (PyObject_IsTrue(force))
ghostify = 1; ghostify = 1;
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;
} }
if (ghostify) { if (ghostify)
{
if (_BTree_clear(self) < 0) if (_BTree_clear(self) < 0)
return NULL; return NULL;
PER_GHOSTIFY(self); PER_GHOSTIFY(self);
...@@ -925,7 +997,7 @@ BTree_clear(BTree *self) ...@@ -925,7 +997,7 @@ BTree_clear(BTree *self)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
return NULL; return NULL;
} }
...@@ -964,19 +1036,22 @@ BTree_getstate(BTree *self) ...@@ -964,19 +1036,22 @@ BTree_getstate(BTree *self)
PyObject *o; PyObject *o;
int i, l; int i, l;
UNLESS (PER_USE(self)) return NULL; UNLESS (PER_USE(self))
return NULL;
if (self->len) { if (self->len)
{
r = PyTuple_New(self->len * 2 - 1); r = PyTuple_New(self->len * 2 - 1);
if (r == NULL) if (r == NULL)
goto err; goto err;
if (self->len == 1 if (self->len == 1
&& self->data->child->ob_type != self->ob_type && Py_TYPE(self->data->child) != Py_TYPE(self)
#ifdef PERSISTENT #ifdef PERSISTENT
&& BUCKET(self->data->child)->oid == NULL && BUCKET(self->data->child)->oid == NULL
#endif #endif
) { )
{
/* We have just one bucket. Save its data directly. */ /* We have just one bucket. Save its data directly. */
o = bucket_getstate((Bucket *)self->data->child); o = bucket_getstate((Bucket *)self->data->child);
if (o == NULL) if (o == NULL)
...@@ -984,9 +1059,12 @@ BTree_getstate(BTree *self) ...@@ -984,9 +1059,12 @@ BTree_getstate(BTree *self)
PyTuple_SET_ITEM(r, 0, o); PyTuple_SET_ITEM(r, 0, o);
ASSIGN(r, Py_BuildValue("(O)", r)); ASSIGN(r, Py_BuildValue("(O)", r));
} }
else { else
for (i=0, l=0; i < self->len; i++) { {
if (i) { for (i=0, l=0; i < self->len; i++)
{
if (i)
{
COPY_KEY_TO_OBJECT(o, self->data[i].key); COPY_KEY_TO_OBJECT(o, self->data[i].key);
PyTuple_SET_ITEM(r, l, o); PyTuple_SET_ITEM(r, l, o);
l++; l++;
...@@ -1000,7 +1078,8 @@ BTree_getstate(BTree *self) ...@@ -1000,7 +1078,8 @@ BTree_getstate(BTree *self)
} }
} }
else { else
{
r = Py_None; r = Py_None;
Py_INCREF(r); Py_INCREF(r);
} }
...@@ -1009,7 +1088,7 @@ BTree_getstate(BTree *self) ...@@ -1009,7 +1088,7 @@ BTree_getstate(BTree *self)
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
return NULL; return NULL;
...@@ -1038,7 +1117,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval) ...@@ -1038,7 +1117,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
if (!PyArg_ParseTuple(state, "O|O:__setstate__", &items, &firstbucket)) if (!PyArg_ParseTuple(state, "O|O:__setstate__", &items, &firstbucket))
return -1; return -1;
if (!PyTuple_Check(items)) { if (!PyTuple_Check(items))
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"tuple required for first state element"); "tuple required for first state element");
return -1; return -1;
...@@ -1057,9 +1137,11 @@ _BTree_setstate(BTree *self, PyObject *state, int noval) ...@@ -1057,9 +1137,11 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
return -1; return -1;
self->size = len; self->size = len;
for (i = 0, d = self->data, l = 0; i < len; i++, d++) { for (i = 0, d = self->data, l = 0; i < len; i++, d++)
{
PyObject *v; PyObject *v;
if (i) { /* skip the first key slot */ if (i)
{ /* skip the first key slot */
COPY_KEY_FROM_ARG(d->key, PyTuple_GET_ITEM(items, l), copied); COPY_KEY_FROM_ARG(d->key, PyTuple_GET_ITEM(items, l), copied);
l++; l++;
if (!copied) if (!copied)
...@@ -1067,22 +1149,26 @@ _BTree_setstate(BTree *self, PyObject *state, int noval) ...@@ -1067,22 +1149,26 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
INCREF_KEY(d->key); INCREF_KEY(d->key);
} }
v = PyTuple_GET_ITEM(items, l); v = PyTuple_GET_ITEM(items, l);
if (PyTuple_Check(v)) { if (PyTuple_Check(v))
{
/* Handle the special case in __getstate__() for a BTree /* Handle the special case in __getstate__() for a BTree
with a single bucket. */ with a single bucket. */
d->child = BTree_newBucket(self); d->child = BTree_newBucket(self);
if (!d->child) if (!d->child)
return -1; return -1;
if (noval) { if (noval)
{
if (_set_setstate(BUCKET(d->child), v) < 0) if (_set_setstate(BUCKET(d->child), v) < 0)
return -1; return -1;
} }
else { else
{
if (_bucket_setstate(BUCKET(d->child), v) < 0) if (_bucket_setstate(BUCKET(d->child), v) < 0)
return -1; return -1;
} }
} }
else { else
{
d->child = (Sized *)v; d->child = (Sized *)v;
Py_INCREF(v); Py_INCREF(v);
} }
...@@ -1093,7 +1179,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval) ...@@ -1093,7 +1179,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
firstbucket = (PyObject *)self->data->child; firstbucket = (PyObject *)self->data->child;
if (!PyObject_IsInstance(firstbucket, (PyObject *) if (!PyObject_IsInstance(firstbucket, (PyObject *)
(noval ? &SetType : &BucketType))) { (noval ? &SetType : &BucketType)))
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"No firstbucket in non-empty BTree"); "No firstbucket in non-empty BTree");
return -1; return -1;
...@@ -1104,7 +1191,7 @@ _BTree_setstate(BTree *self, PyObject *state, int noval) ...@@ -1104,7 +1191,7 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
/* firstbucket is also the child of some BTree node, but that node may /* firstbucket is also the child of some BTree node, but that node may
* be a ghost if persistence is enabled. * be a ghost if persistence is enabled.
*/ */
assert(self->firstbucket->ob_refcnt > 1); assert(Py_REFCNT(self->firstbucket) > 1);
#endif #endif
self->len = len; self->len = len;
...@@ -1149,27 +1236,31 @@ get_bucket_state(PyObject *t) ...@@ -1149,27 +1236,31 @@ get_bucket_state(PyObject *t)
{ {
if (t == Py_None) if (t == Py_None)
return Py_None; /* an empty BTree */ return Py_None; /* an empty BTree */
if (! PyTuple_Check(t)) { if (! PyTuple_Check(t))
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_resolveConflict: expected tuple or None for state"); "_p_resolveConflict: expected tuple or None for state");
return NULL; return NULL;
} }
if (PyTuple_GET_SIZE(t) == 2) { if (PyTuple_GET_SIZE(t) == 2)
{
/* A non-degenerate BTree. */ /* A non-degenerate BTree. */
return merge_error(-1, -1, -1, 11); return merge_error(-1, -1, -1, 11);
} }
/* We're in the one-bucket case. */ /* We're in the one-bucket case. */
if (PyTuple_GET_SIZE(t) != 1) { if (PyTuple_GET_SIZE(t) != 1)
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_resolveConflict: expected 1- or 2-tuple for state"); "_p_resolveConflict: expected 1- or 2-tuple for state");
return NULL; return NULL;
} }
t = PyTuple_GET_ITEM(t, 0); t = PyTuple_GET_ITEM(t, 0);
if (! PyTuple_Check(t) || PyTuple_GET_SIZE(t) != 1) { if (! PyTuple_Check(t) || PyTuple_GET_SIZE(t) != 1)
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_resolveConflict: expected 1-tuple containing " "_p_resolveConflict: expected 1-tuple containing "
"bucket state"); "bucket state");
...@@ -1177,7 +1268,8 @@ get_bucket_state(PyObject *t) ...@@ -1177,7 +1268,8 @@ get_bucket_state(PyObject *t)
} }
t = PyTuple_GET_ITEM(t, 0); t = PyTuple_GET_ITEM(t, 0);
if (! PyTuple_Check(t)) { if (! PyTuple_Check(t))
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_resolveConflict: expected tuple for bucket state"); "_p_resolveConflict: expected tuple for bucket state");
return NULL; return NULL;
...@@ -1279,7 +1371,8 @@ BTree__p_resolveConflict(BTree *self, PyObject *args) ...@@ -1279,7 +1371,8 @@ BTree__p_resolveConflict(BTree *self, PyObject *args)
*/ */
static int static int
BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal, BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
Bucket **bucket, int *offset) { Bucket **bucket, int *offset)
{
Sized *deepest_smaller = NULL; /* last possibility to move left */ Sized *deepest_smaller = NULL; /* last possibility to move left */
int deepest_smaller_is_btree = 0; /* Boolean; if false, it's a bucket */ int deepest_smaller_is_btree = 0; /* Boolean; if false, it's a bucket */
Bucket *pbucket; Bucket *pbucket;
...@@ -1290,34 +1383,41 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -1290,34 +1383,41 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
int copied = 1; int copied = 1;
COPY_KEY_FROM_ARG(key, keyarg, copied); COPY_KEY_FROM_ARG(key, keyarg, copied);
UNLESS (copied) return -1; UNLESS (copied)
return -1;
/* We don't need to: PER_USE_OR_RETURN(self, -1); /* We don't need to: PER_USE_OR_RETURN(self, -1);
because the caller does. */ because the caller does. */
UNLESS (self->data && self->len) return 0; UNLESS (self->data && self->len)
return 0;
/* Search downward until hitting a bucket, stored in pbucket. */ /* Search downward until hitting a bucket, stored in pbucket. */
for (;;) { for (;;)
{
Sized *pchild; Sized *pchild;
int pchild_is_btree; int pchild_is_btree;
BTREE_SEARCH(i, self, key, goto Done); BTREE_SEARCH(i, self, key, goto Done);
pchild = self->data[i].child; pchild = self->data[i].child;
pchild_is_btree = SameType_Check(self, pchild); pchild_is_btree = SameType_Check(self, pchild);
if (i) { if (i)
{
deepest_smaller = self->data[i-1].child; deepest_smaller = self->data[i-1].child;
deepest_smaller_is_btree = pchild_is_btree; deepest_smaller_is_btree = pchild_is_btree;
} }
if (pchild_is_btree) { if (pchild_is_btree)
if (self_got_rebound) { {
if (self_got_rebound)
{
PER_UNUSE(self); PER_UNUSE(self);
} }
self = BTREE(pchild); self = BTREE(pchild);
self_got_rebound = 1; self_got_rebound = 1;
PER_USE_OR_RETURN(self, -1); PER_USE_OR_RETURN(self, -1);
} }
else { else
{
pbucket = BUCKET(pchild); pbucket = BUCKET(pchild);
break; break;
} }
...@@ -1327,14 +1427,16 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -1327,14 +1427,16 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
i = Bucket_findRangeEnd(pbucket, keyarg, low, exclude_equal, offset); i = Bucket_findRangeEnd(pbucket, keyarg, low, exclude_equal, offset);
if (i < 0) if (i < 0)
goto Done; goto Done;
if (i > 0) { if (i > 0)
{
Py_INCREF(pbucket); Py_INCREF(pbucket);
*bucket = pbucket; *bucket = pbucket;
result = 1; result = 1;
goto Done; goto Done;
} }
/* This may be one of the two difficult cases detailed in the comments. */ /* This may be one of the two difficult cases detailed in the comments. */
if (low) { if (low)
{
Bucket *next; Bucket *next;
UNLESS(PER_USE(pbucket)) goto Done; UNLESS(PER_USE(pbucket)) goto Done;
...@@ -1350,19 +1452,25 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -1350,19 +1452,25 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
PER_UNUSE(pbucket); PER_UNUSE(pbucket);
} }
/* High-end search: if it's possible to go left, do so. */ /* High-end search: if it's possible to go left, do so. */
else if (deepest_smaller) { else if (deepest_smaller)
if (deepest_smaller_is_btree) { {
UNLESS(PER_USE(deepest_smaller)) goto Done; if (deepest_smaller_is_btree)
{
UNLESS(PER_USE(deepest_smaller))
goto Done;
/* We own the reference this returns. */ /* We own the reference this returns. */
pbucket = BTree_lastBucket(BTREE(deepest_smaller)); pbucket = BTree_lastBucket(BTREE(deepest_smaller));
PER_UNUSE(deepest_smaller); PER_UNUSE(deepest_smaller);
if (pbucket == NULL) goto Done; /* error */ if (pbucket == NULL)
goto Done; /* error */
} }
else { else
{
pbucket = BUCKET(deepest_smaller); pbucket = BUCKET(deepest_smaller);
Py_INCREF(pbucket); Py_INCREF(pbucket);
} }
UNLESS(PER_USE(pbucket)) goto Done; UNLESS(PER_USE(pbucket))
goto Done;
result = 1; result = 1;
*bucket = pbucket; /* transfer ownership to caller */ *bucket = pbucket; /* transfer ownership to caller */
*offset = pbucket->len - 1; *offset = pbucket->len - 1;
...@@ -1371,8 +1479,9 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -1371,8 +1479,9 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
else else
result = 0; /* simply not found */ result = 0; /* simply not found */
Done: Done:
if (self_got_rebound) { if (self_got_rebound)
{
PER_UNUSE(self); PER_UNUSE(self);
} }
return result; return result;
...@@ -1386,11 +1495,14 @@ BTree_maxminKey(BTree *self, PyObject *args, int min) ...@@ -1386,11 +1495,14 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
int offset, rc; int offset, rc;
int empty_tree = 1; int empty_tree = 1;
UNLESS (PyArg_ParseTuple(args, "|O", &key)) return NULL; UNLESS (PyArg_ParseTuple(args, "|O", &key))
return NULL;
UNLESS (PER_USE(self)) return NULL; UNLESS (PER_USE(self))
return NULL;
UNLESS (self->data && self->len) goto empty; UNLESS (self->data && self->len)
goto empty;
/* Find the range */ /* Find the range */
...@@ -1398,7 +1510,8 @@ BTree_maxminKey(BTree *self, PyObject *args, int min) ...@@ -1398,7 +1510,8 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
{ {
if ((rc = BTree_findRangeEnd(self, key, min, 0, &bucket, &offset)) <= 0) if ((rc = BTree_findRangeEnd(self, key, min, 0, &bucket, &offset)) <= 0)
{ {
if (rc < 0) goto err; if (rc < 0)
goto err;
empty_tree = 0; empty_tree = 0;
goto empty; goto empty;
} }
...@@ -1436,11 +1549,11 @@ BTree_maxminKey(BTree *self, PyObject *args, int min) ...@@ -1436,11 +1549,11 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
return key; return key;
empty: empty:
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
empty_tree ? "empty tree" : empty_tree ? "empty tree" :
"no key satisfies the conditions"); "no key satisfies the conditions");
err: err:
PER_UNUSE(self); PER_UNUSE(self);
if (bucket) if (bucket)
{ {
...@@ -1483,7 +1596,8 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type) ...@@ -1483,7 +1596,8 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
int highoffset; int highoffset;
PyObject *result; PyObject *result;
if (args) { if (args)
{
if (! PyArg_ParseTupleAndKeywords(args, kw, "|OOii", search_keywords, if (! PyArg_ParseTupleAndKeywords(args, kw, "|OOii", search_keywords,
&min, &min,
&max, &max,
...@@ -1492,33 +1606,43 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type) ...@@ -1492,33 +1606,43 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
return NULL; return NULL;
} }
UNLESS (PER_USE(self)) return NULL; UNLESS (PER_USE(self))
return NULL;
UNLESS (self->data && self->len) goto empty; UNLESS (self->data && self->len)
goto empty;
/* Find the low range */ /* Find the low range */
if (min != Py_None) { if (min != Py_None)
{
if ((rc = BTree_findRangeEnd(self, min, 1, excludemin, if ((rc = BTree_findRangeEnd(self, min, 1, excludemin,
&lowbucket, &lowoffset)) <= 0) { &lowbucket, &lowoffset)) <= 0)
if (rc < 0) goto err; {
if (rc < 0)
goto err;
goto empty; goto empty;
} }
} }
else { else
{
lowbucket = self->firstbucket; lowbucket = self->firstbucket;
lowoffset = 0; lowoffset = 0;
if (excludemin) { if (excludemin)
{
int bucketlen; int bucketlen;
UNLESS (PER_USE(lowbucket)) goto err; UNLESS (PER_USE(lowbucket))
goto err;
bucketlen = lowbucket->len; bucketlen = lowbucket->len;
PER_UNUSE(lowbucket); PER_UNUSE(lowbucket);
if (bucketlen > 1) if (bucketlen > 1)
lowoffset = 1; lowoffset = 1;
else if (self->len < 2) else if (self->len < 2)
goto empty; goto empty;
else { /* move to first item in next bucket */ else
{ /* move to first item in next bucket */
Bucket *next; Bucket *next;
UNLESS (PER_USE(lowbucket)) goto err; UNLESS (PER_USE(lowbucket))
goto err;
next = lowbucket->next; next = lowbucket->next;
PER_UNUSE(lowbucket); PER_UNUSE(lowbucket);
assert(next != NULL); assert(next != NULL);
...@@ -1531,39 +1655,48 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type) ...@@ -1531,39 +1655,48 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
} }
/* Find the high range */ /* Find the high range */
if (max != Py_None) { if (max != Py_None)
{
if ((rc = BTree_findRangeEnd(self, max, 0, excludemax, if ((rc = BTree_findRangeEnd(self, max, 0, excludemax,
&highbucket, &highoffset)) <= 0) { &highbucket, &highoffset)) <= 0)
{
Py_DECREF(lowbucket); Py_DECREF(lowbucket);
if (rc < 0) goto err; if (rc < 0)
goto err;
goto empty; goto empty;
} }
} }
else { else
{
int bucketlen; int bucketlen;
highbucket = BTree_lastBucket(self); highbucket = BTree_lastBucket(self);
assert(highbucket != NULL); /* we know self isn't empty */ assert(highbucket != NULL); /* we know self isn't empty */
UNLESS (PER_USE(highbucket)) goto err_and_decref_buckets; UNLESS (PER_USE(highbucket))
goto err_and_decref_buckets;
bucketlen = highbucket->len; bucketlen = highbucket->len;
PER_UNUSE(highbucket); PER_UNUSE(highbucket);
highoffset = bucketlen - 1; highoffset = bucketlen - 1;
if (excludemax) { if (excludemax)
{
if (highoffset > 0) if (highoffset > 0)
--highoffset; --highoffset;
else if (self->len < 2) else if (self->len < 2)
goto empty_and_decref_buckets; goto empty_and_decref_buckets;
else { /* move to last item of preceding bucket */ else /* move to last item of preceding bucket */
{
int status; int status;
assert(highbucket != self->firstbucket); assert(highbucket != self->firstbucket);
Py_DECREF(highbucket); Py_DECREF(highbucket);
status = PreviousBucket(&highbucket, self->firstbucket); status = PreviousBucket(&highbucket, self->firstbucket);
if (status < 0) { if (status < 0)
{
Py_DECREF(lowbucket); Py_DECREF(lowbucket);
goto err; goto err;
} }
assert(status > 0); assert(status > 0);
Py_INCREF(highbucket); Py_INCREF(highbucket);
UNLESS (PER_USE(highbucket)) goto err_and_decref_buckets; UNLESS (PER_USE(highbucket))
goto err_and_decref_buckets;
highoffset = highbucket->len - 1; highoffset = highbucket->len - 1;
PER_UNUSE(highbucket); PER_UNUSE(highbucket);
} }
...@@ -1585,22 +1718,27 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type) ...@@ -1585,22 +1718,27 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
* empty range. * empty range.
*/ */
if (min != Py_None && max != Py_None && /* both args user-supplied */ if (min != Py_None && max != Py_None && /* both args user-supplied */
lowbucket != highbucket) /* and different buckets */ { lowbucket != highbucket) /* and different buckets */
{
KEY_TYPE first; KEY_TYPE first;
KEY_TYPE last; KEY_TYPE last;
int cmp; int cmp;
/* Have to check the hard way: see how the endpoints compare. */ /* Have to check the hard way: see how the endpoints compare. */
UNLESS (PER_USE(lowbucket)) goto err_and_decref_buckets; UNLESS (PER_USE(lowbucket))
goto err_and_decref_buckets;
COPY_KEY(first, lowbucket->keys[lowoffset]); COPY_KEY(first, lowbucket->keys[lowoffset]);
PER_UNUSE(lowbucket); PER_UNUSE(lowbucket);
UNLESS (PER_USE(highbucket)) goto err_and_decref_buckets; UNLESS (PER_USE(highbucket))
goto err_and_decref_buckets;
COPY_KEY(last, highbucket->keys[highoffset]); COPY_KEY(last, highbucket->keys[highoffset]);
PER_UNUSE(highbucket); PER_UNUSE(highbucket);
TEST_KEY_SET_OR(cmp, first, last) goto err_and_decref_buckets; TEST_KEY_SET_OR(cmp, first, last)
if (cmp > 0) goto empty_and_decref_buckets; goto err_and_decref_buckets;
if (cmp > 0)
goto empty_and_decref_buckets;
} }
PER_UNUSE(self); PER_UNUSE(self);
...@@ -1610,19 +1748,19 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type) ...@@ -1610,19 +1748,19 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
Py_DECREF(highbucket); Py_DECREF(highbucket);
return result; return result;
err_and_decref_buckets: err_and_decref_buckets:
Py_DECREF(lowbucket); Py_DECREF(lowbucket);
Py_DECREF(highbucket); Py_DECREF(highbucket);
err: err:
PER_UNUSE(self); PER_UNUSE(self);
return NULL; return NULL;
empty_and_decref_buckets: empty_and_decref_buckets:
Py_DECREF(lowbucket); Py_DECREF(lowbucket);
Py_DECREF(highbucket); Py_DECREF(highbucket);
empty: empty:
PER_UNUSE(self); PER_UNUSE(self);
return newBTreeItems(type, 0, 0, 0, 0); return newBTreeItems(type, 0, 0, 0, 0);
} }
...@@ -1663,57 +1801,71 @@ BTree_byValue(BTree *self, PyObject *omin) ...@@ -1663,57 +1801,71 @@ BTree_byValue(BTree *self, PyObject *omin)
int copied=1; int copied=1;
SetIteration it = {0, 0, 1}; SetIteration it = {0, 0, 1};
UNLESS (PER_USE(self)) return NULL; UNLESS (PER_USE(self))
return NULL;
COPY_VALUE_FROM_ARG(min, omin, copied); COPY_VALUE_FROM_ARG(min, omin, copied);
UNLESS(copied) return NULL; UNLESS(copied)
return NULL;
UNLESS (r=PyList_New(0)) goto err; UNLESS (r=PyList_New(0))
goto err;
it.set=BTree_rangeSearch(self, NULL, NULL, 'i'); it.set=BTree_rangeSearch(self, NULL, NULL, 'i');
UNLESS(it.set) goto err; UNLESS(it.set)
goto err;
if (nextBTreeItems(&it) < 0) goto err; if (nextBTreeItems(&it) < 0)
goto err;
while (it.position >= 0) while (it.position >= 0)
{ {
if (TEST_VALUE(it.value, min) >= 0) if (TEST_VALUE(it.value, min) >= 0)
{ {
UNLESS (item = PyTuple_New(2)) goto err; UNLESS (item = PyTuple_New(2))
goto err;
COPY_KEY_TO_OBJECT(o, it.key); COPY_KEY_TO_OBJECT(o, it.key);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 1, o); PyTuple_SET_ITEM(item, 1, o);
COPY_VALUE(v, it.value); COPY_VALUE(v, it.value);
NORMALIZE_VALUE(v, min); NORMALIZE_VALUE(v, min);
COPY_VALUE_TO_OBJECT(o, v); COPY_VALUE_TO_OBJECT(o, v);
DECREF_VALUE(v); DECREF_VALUE(v);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 0, o); PyTuple_SET_ITEM(item, 0, o);
if (PyList_Append(r, item) < 0) goto err; if (PyList_Append(r, item) < 0)
goto err;
Py_DECREF(item); Py_DECREF(item);
item = 0; item = 0;
} }
if (nextBTreeItems(&it) < 0) goto err; if (nextBTreeItems(&it) < 0)
goto err;
} }
item=PyObject_GetAttr(r,sort_str); item=PyObject_GetAttr(r,sort_str);
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_CallObject(item, NULL)); ASSIGN(item, PyObject_CallObject(item, NULL));
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_GetAttr(r, reverse_str)); ASSIGN(item, PyObject_GetAttr(r, reverse_str));
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_CallObject(item, NULL)); ASSIGN(item, PyObject_CallObject(item, NULL));
UNLESS (item) goto err; UNLESS (item)
goto err;
Py_DECREF(item); Py_DECREF(item);
finiSetIteration(&it); finiSetIteration(&it);
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
finiSetIteration(&it); finiSetIteration(&it);
...@@ -1729,9 +1881,12 @@ BTree_getm(BTree *self, PyObject *args) ...@@ -1729,9 +1881,12 @@ BTree_getm(BTree *self, PyObject *args)
{ {
PyObject *key, *d=Py_None, *r; PyObject *key, *d=Py_None, *r;
UNLESS (PyArg_ParseTuple(args, "O|O", &key, &d)) return NULL; UNLESS (PyArg_ParseTuple(args, "O|O", &key, &d))
if ((r=_BTree_get(self, key, 0))) return r; return NULL;
UNLESS (PyErr_ExceptionMatches(PyExc_KeyError)) return NULL; if ((r=_BTree_get(self, key, 0)))
return r;
UNLESS (PyErr_ExceptionMatches(PyExc_KeyError))
return NULL;
PyErr_Clear(); PyErr_Clear();
Py_INCREF(d); Py_INCREF(d);
return d; return d;
...@@ -1787,9 +1942,11 @@ BTree_pop(BTree *self, PyObject *args) ...@@ -1787,9 +1942,11 @@ BTree_pop(BTree *self, PyObject *args)
return NULL; return NULL;
value = _BTree_get(self, key, 0); value = _BTree_get(self, key, 0);
if (value != NULL) { if (value != NULL)
{
/* Delete key and associated value. */ /* Delete key and associated value. */
if (_BTree_set(self, key, NULL, 0, 0) < 0) { if (_BTree_set(self, key, NULL, 0, 0) < 0)
{
Py_DECREF(value); Py_DECREF(value);
return NULL;; return NULL;;
} }
...@@ -1802,7 +1959,8 @@ BTree_pop(BTree *self, PyObject *args) ...@@ -1802,7 +1959,8 @@ BTree_pop(BTree *self, PyObject *args)
if (! PyErr_ExceptionMatches(PyExc_KeyError)) if (! PyErr_ExceptionMatches(PyExc_KeyError))
return NULL; return NULL;
if (failobj != NULL) { if (failobj != NULL)
{
/* Clear the KeyError and return the explicit default. */ /* Clear the KeyError and return the explicit default. */
PyErr_Clear(); PyErr_Clear();
Py_INCREF(failobj); Py_INCREF(failobj);
...@@ -1831,8 +1989,9 @@ BTree_contains(BTree *self, PyObject *key) ...@@ -1831,8 +1989,9 @@ BTree_contains(BTree *self, PyObject *key)
PyObject *asobj = _BTree_get(self, key, 1); PyObject *asobj = _BTree_get(self, key, 1);
int result = -1; int result = -1;
if (asobj != NULL) { if (asobj != NULL)
result = PyInt_AsLong(asobj) ? 1 : 0; {
result = INT_AS_LONG(asobj) ? 1 : 0;
Py_DECREF(asobj); Py_DECREF(asobj);
} }
return result; return result;
...@@ -1844,10 +2003,12 @@ BTree_addUnique(BTree *self, PyObject *args) ...@@ -1844,10 +2003,12 @@ BTree_addUnique(BTree *self, PyObject *args)
int grew; int grew;
PyObject *key, *v; PyObject *key, *v;
UNLESS (PyArg_ParseTuple(args, "OO", &key, &v)) return NULL; UNLESS (PyArg_ParseTuple(args, "OO", &key, &v))
return NULL;
if ((grew=_BTree_set(self, key, v, 1, 0)) < 0) return NULL; if ((grew=_BTree_set(self, key, v, 1, 0)) < 0)
return PyInt_FromLong(grew); return NULL;
return INT_FROM_LONG(grew);
} }
/**************************************************************************/ /**************************************************************************/
...@@ -1865,7 +2026,8 @@ buildBTreeIter(BTree *self, PyObject *args, PyObject *kw, char kind) ...@@ -1865,7 +2026,8 @@ buildBTreeIter(BTree *self, PyObject *args, PyObject *kw, char kind)
BTreeIter *result = NULL; BTreeIter *result = NULL;
BTreeItems *items = (BTreeItems *)BTree_rangeSearch(self, args, kw, kind); BTreeItems *items = (BTreeItems *)BTree_rangeSearch(self, args, kw, kind);
if (items) { if (items)
{
result = BTreeIter_new(items); result = BTreeIter_new(items);
Py_DECREF(items); Py_DECREF(items);
} }
...@@ -1912,7 +2074,7 @@ BTree_iteritems(BTree *self, PyObject *args, PyObject *kw) ...@@ -1912,7 +2074,7 @@ BTree_iteritems(BTree *self, PyObject *args, PyObject *kw)
*/ */
static struct PyMemberDef BTree_members[] = { static struct PyMemberDef BTree_members[] = {
{"_firstbucket", T_OBJECT, offsetof(BTree, firstbucket), RO}, {"_firstbucket", T_OBJECT, offsetof(BTree, firstbucket), READONLY},
{NULL} {NULL}
}; };
...@@ -1929,18 +2091,18 @@ static struct PyMethodDef BTree_methods[] = { ...@@ -1929,18 +2091,18 @@ static struct PyMethodDef BTree_methods[] = {
"has_key(key)\n\n" "has_key(key)\n\n"
"Return true if the BTree contains the given key."}, "Return true if the BTree contains the given key."},
{"keys", (PyCFunction) BTree_keys, METH_KEYWORDS, {"keys", (PyCFunction) BTree_keys, METH_VARARGS | METH_KEYWORDS,
"keys([min, max]) -> list of keys\n\n" "keys([min, max]) -> list of keys\n\n"
"Returns the keys of the BTree. If min and max are supplied, only\n" "Returns the keys of the BTree. If min and max are supplied, only\n"
"keys greater than min and less than max are returned."}, "keys greater than min and less than max are returned."},
{"values", (PyCFunction) BTree_values, METH_KEYWORDS, {"values", (PyCFunction) BTree_values, METH_VARARGS | METH_KEYWORDS,
"values([min, max]) -> list of values\n\n" "values([min, max]) -> list of values\n\n"
"Returns the values of the BTree. If min and max are supplied, only\n" "Returns the values of the BTree. If min and max are supplied, only\n"
"values corresponding to keys greater than min and less than max are\n" "values corresponding to keys greater than min and less than max are\n"
"returned."}, "returned."},
{"items", (PyCFunction) BTree_items, METH_KEYWORDS, {"items", (PyCFunction) BTree_items, METH_VARARGS | METH_KEYWORDS,
"items([min, max]) -> -- list of key, value pairs\n\n" "items([min, max]) -> -- list of key, value pairs\n\n"
"Returns the items of the BTree. If min and max are supplied, only\n" "Returns the items of the BTree. If min and max are supplied, only\n"
"items with keys greater than min and less than max are returned."}, "items with keys greater than min and less than max are returned."},
...@@ -1986,24 +2148,26 @@ static struct PyMethodDef BTree_methods[] = { ...@@ -1986,24 +2148,26 @@ static struct PyMethodDef BTree_methods[] = {
{"update", (PyCFunction) Mapping_update, METH_O, {"update", (PyCFunction) Mapping_update, METH_O,
"update(collection)\n\n Add the items from the given collection."}, "update(collection)\n\n Add the items from the given collection."},
{"iterkeys", (PyCFunction) BTree_iterkeys, METH_KEYWORDS, {"iterkeys", (PyCFunction) BTree_iterkeys, METH_VARARGS | METH_KEYWORDS,
"B.iterkeys([min[,max]]) -> an iterator over the keys of B"}, "B.iterkeys([min[,max]]) -> an iterator over the keys of B"},
{"itervalues", (PyCFunction) BTree_itervalues, METH_KEYWORDS, {"itervalues", (PyCFunction) BTree_itervalues, METH_VARARGS | METH_KEYWORDS,
"B.itervalues([min[,max]]) -> an iterator over the values of B"}, "B.itervalues([min[,max]]) -> an iterator over the values of B"},
{"iteritems", (PyCFunction) BTree_iteritems, METH_KEYWORDS, {"iteritems", (PyCFunction) BTree_iteritems, METH_VARARGS | METH_KEYWORDS,
"B.iteritems([min[,max]]) -> an iterator over the (key, value) items of B"}, "B.iteritems([min[,max]]) -> an iterator over the (key, value) "
"items of B"},
{"_check", (PyCFunction) BTree_check, METH_NOARGS, {"_check", (PyCFunction) BTree_check, METH_NOARGS,
"Perform sanity check on BTree, and raise exception if flawed."}, "Perform sanity check on BTree, and raise exception if flawed."},
#ifdef PERSISTENT #ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) BTree__p_resolveConflict, {"_p_resolveConflict",
METH_VARARGS, (PyCFunction) BTree__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"}, "_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) BTree__p_deactivate, METH_KEYWORDS, {"_p_deactivate",
(PyCFunction) BTree__p_deactivate, METH_VARARGS | METH_KEYWORDS,
"_p_deactivate()\n\nReinitialize from a newly created copy."}, "_p_deactivate()\n\nReinitialize from a newly created copy."},
#endif #endif
{NULL, NULL} {NULL, NULL}
...@@ -2044,8 +2208,8 @@ BTree_traverse(BTree *self, visitproc visit, void *arg) ...@@ -2044,8 +2208,8 @@ BTree_traverse(BTree *self, visitproc visit, void *arg)
goto Done; \ goto Done; \
} }
if (self->ob_type == &BTreeType) if (Py_TYPE(self) == &BTreeType)
assert(self->ob_type->tp_dictoffset == 0); assert(Py_TYPE(self)->tp_dictoffset == 0);
/* Call our base type's traverse function. Because BTrees are /* Call our base type's traverse function. Because BTrees are
* subclasses of Peristent, there must be one. * subclasses of Peristent, there must be one.
...@@ -2076,7 +2240,7 @@ BTree_traverse(BTree *self, visitproc visit, void *arg) ...@@ -2076,7 +2240,7 @@ BTree_traverse(BTree *self, visitproc visit, void *arg)
VISIT(self->firstbucket); VISIT(self->firstbucket);
Done: Done:
return err; return err;
#undef VISIT #undef VISIT
...@@ -2119,7 +2283,8 @@ BTree_length_or_nonzero(BTree *self, int nonzero) ...@@ -2119,7 +2283,8 @@ BTree_length_or_nonzero(BTree *self, int nonzero)
return b != NULL; return b != NULL;
result = 0; result = 0;
while (b) { while (b)
{
PER_USE_OR_RETURN(b, -1); PER_USE_OR_RETURN(b, -1);
result += b->len; result += b->len;
next = b->next; next = b->next;
...@@ -2136,9 +2301,9 @@ BTree_length(BTree *self) ...@@ -2136,9 +2301,9 @@ BTree_length(BTree *self)
} }
static PyMappingMethods BTree_as_mapping = { static PyMappingMethods BTree_as_mapping = {
(lenfunc)BTree_length, /*mp_length*/ (lenfunc)BTree_length, /* mp_length */
(binaryfunc)BTree_get, /*mp_subscript*/ (binaryfunc)BTree_get, /* mp_subscript */
(objobjargproc)BTree_setitem, /*mp_ass_subscript*/ (objobjargproc)BTree_setitem, /* mp_ass_subscript */
}; };
static PySequenceMethods BTree_as_sequence = { static PySequenceMethods BTree_as_sequence = {
...@@ -2161,13 +2326,24 @@ BTree_nonzero(BTree *self) ...@@ -2161,13 +2326,24 @@ BTree_nonzero(BTree *self)
} }
static PyNumberMethods BTree_as_number_for_nonzero = { static PyNumberMethods BTree_as_number_for_nonzero = {
0,0,0,0,0,0,0,0,0,0, 0, /* nb_add */
(inquiry)BTree_nonzero}; 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)BTree_nonzero /* nb_nonzero */
};
static PyTypeObject BTreeType = { static PyTypeObject BTreeType = {
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ PyVarObject_HEAD_INIT(NULL, 0)
0, /* ob_size */ MODULE_NAME MOD_NAME_PREFIX "BTree", /* tp_name */
MODULE_NAME MOD_NAME_PREFIX "BTree",/* tp_name */
sizeof(BTree), /* tp_basicsize */ sizeof(BTree), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
(destructor)BTree_dealloc, /* tp_dealloc */ (destructor)BTree_dealloc, /* tp_dealloc */
...@@ -2185,7 +2361,8 @@ static PyTypeObject BTreeType = { ...@@ -2185,7 +2361,8 @@ static PyTypeObject BTreeType = {
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)BTree_traverse, /* tp_traverse */ (traverseproc)BTree_traverse, /* tp_traverse */
......
...@@ -87,19 +87,20 @@ _bucket_get(Bucket *self, PyObject *keyarg, int has_key) ...@@ -87,19 +87,20 @@ _bucket_get(Bucket *self, PyObject *keyarg, int has_key)
BUCKET_SEARCH(i, cmp, self, key, goto Done); BUCKET_SEARCH(i, cmp, self, key, goto Done);
if (has_key) if (has_key)
r = PyInt_FromLong(cmp ? 0 : has_key); r = INT_FROM_LONG(cmp ? 0 : has_key);
else { else
if (cmp == 0) { {
if (cmp == 0)
{
COPY_VALUE_TO_OBJECT(r, self->values[i]); COPY_VALUE_TO_OBJECT(r, self->values[i]);
} }
else else
PyErr_SetObject(PyExc_KeyError, keyarg); PyErr_SetObject(PyExc_KeyError, keyarg);
} }
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
} }
static PyObject * static PyObject *
...@@ -129,7 +130,8 @@ Bucket_grow(Bucket *self, int newsize, int noval) ...@@ -129,7 +130,8 @@ Bucket_grow(Bucket *self, int newsize, int noval)
KEY_TYPE *keys; KEY_TYPE *keys;
VALUE_TYPE *values; VALUE_TYPE *values;
if (self->size) { if (self->size)
{
if (newsize < 0) if (newsize < 0)
newsize = self->size * 2; newsize = self->size * 2;
if (newsize < 0) /* int overflow */ if (newsize < 0) /* int overflow */
...@@ -137,9 +139,11 @@ Bucket_grow(Bucket *self, int newsize, int noval) ...@@ -137,9 +139,11 @@ Bucket_grow(Bucket *self, int newsize, int noval)
UNLESS (keys = BTree_Realloc(self->keys, sizeof(KEY_TYPE) * newsize)) UNLESS (keys = BTree_Realloc(self->keys, sizeof(KEY_TYPE) * newsize))
return -1; return -1;
UNLESS (noval) { UNLESS (noval)
{
values = BTree_Realloc(self->values, sizeof(VALUE_TYPE) * newsize); values = BTree_Realloc(self->values, sizeof(VALUE_TYPE) * newsize);
if (values == NULL) { if (values == NULL)
{
free(keys); free(keys);
return -1; return -1;
} }
...@@ -147,14 +151,17 @@ Bucket_grow(Bucket *self, int newsize, int noval) ...@@ -147,14 +151,17 @@ Bucket_grow(Bucket *self, int newsize, int noval)
} }
self->keys = keys; self->keys = keys;
} }
else { else
{
if (newsize < 0) if (newsize < 0)
newsize = MIN_BUCKET_ALLOC; newsize = MIN_BUCKET_ALLOC;
UNLESS (self->keys = BTree_Malloc(sizeof(KEY_TYPE) * newsize)) UNLESS (self->keys = BTree_Malloc(sizeof(KEY_TYPE) * newsize))
return -1; return -1;
UNLESS (noval) { UNLESS (noval)
{
self->values = BTree_Malloc(sizeof(VALUE_TYPE) * newsize); self->values = BTree_Malloc(sizeof(VALUE_TYPE) * newsize);
if (self->values == NULL) { if (self->values == NULL)
{
free(self->keys); free(self->keys);
self->keys = NULL; self->keys = NULL;
return -1; return -1;
...@@ -164,7 +171,7 @@ Bucket_grow(Bucket *self, int newsize, int noval) ...@@ -164,7 +171,7 @@ Bucket_grow(Bucket *self, int newsize, int noval)
self->size = newsize; self->size = newsize;
return 0; return 0;
Overflow: Overflow:
PyErr_NoMemory(); PyErr_NoMemory();
return -1; return -1;
} }
...@@ -222,7 +229,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n, ...@@ -222,7 +229,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
/* Make room. */ /* Make room. */
newlen = self->len + n; newlen = self->len + n;
if (newlen > self->size) { if (newlen > self->size)
{
int newsize = newlen; int newsize = newlen;
if (overallocate) /* boost by 25% -- pretty arbitrary */ if (overallocate) /* boost by 25% -- pretty arbitrary */
newsize += newsize >> 2; newsize += newsize >> 2;
...@@ -233,7 +241,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n, ...@@ -233,7 +241,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
/* Copy stuff. */ /* Copy stuff. */
memcpy(self->keys + self->len, from->keys + i, n * sizeof(KEY_TYPE)); memcpy(self->keys + self->len, from->keys + i, n * sizeof(KEY_TYPE));
if (copyValues) { if (copyValues)
{
assert(self->values); assert(self->values);
assert(from->values); assert(from->values);
memcpy(self->values + self->len, from->values + i, memcpy(self->values + self->len, from->values + i,
...@@ -246,16 +255,19 @@ bucket_append(Bucket *self, Bucket *from, int i, int n, ...@@ -246,16 +255,19 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
{ {
int j; int j;
PyObject **p = from->keys + i; PyObject **p = from->keys + i;
for (j = 0; j < n; ++j, ++p) { for (j = 0; j < n; ++j, ++p)
{
Py_INCREF(*p); Py_INCREF(*p);
} }
} }
#endif #endif
#ifdef VALUE_TYPE_IS_PYOBJECT #ifdef VALUE_TYPE_IS_PYOBJECT
if (copyValues) { if (copyValues)
{
int j; int j;
PyObject **p = from->values + i; PyObject **p = from->values + i;
for (j = 0; j < n; ++j, ++p) { for (j = 0; j < n; ++j, ++p)
{
Py_INCREF(*p); Py_INCREF(*p);
} }
} }
...@@ -309,28 +321,33 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -309,28 +321,33 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
int copied = 1; int copied = 1;
COPY_KEY_FROM_ARG(key, keyarg, copied); COPY_KEY_FROM_ARG(key, keyarg, copied);
UNLESS(copied) return -1; UNLESS(copied)
return -1;
/* Copy the value early (if needed), so that in case of error a /* Copy the value early (if needed), so that in case of error a
* pile of bucket mutations don't need to be undone. * pile of bucket mutations don't need to be undone.
*/ */
if (v && !noval) { if (v && !noval) {
COPY_VALUE_FROM_ARG(value, v, copied); COPY_VALUE_FROM_ARG(value, v, copied);
UNLESS(copied) return -1; UNLESS(copied)
return -1;
} }
UNLESS (PER_USE(self)) return -1; UNLESS (PER_USE(self))
return -1;
BUCKET_SEARCH(i, cmp, self, key, goto Done); BUCKET_SEARCH(i, cmp, self, key, goto Done);
if (cmp == 0) { if (cmp == 0)
{
/* The key exists, at index i. */ /* The key exists, at index i. */
if (v)
if (v) { {
/* The key exists at index i, and there's a new value. /* The key exists at index i, and there's a new value.
* If unique, we're not supposed to replace it. If noval, or this * If unique, we're not supposed to replace it. If noval, or this
* is a set bucket (self->values is NULL), there's nothing to do. * is a set bucket (self->values is NULL), there's nothing to do.
*/ */
if (unique || noval || self->values == NULL) { if (unique || noval || self->values == NULL)
{
result = 0; result = 0;
goto Done; goto Done;
} }
...@@ -338,7 +355,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -338,7 +355,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
/* The key exists at index i, and we need to replace the value. */ /* The key exists at index i, and we need to replace the value. */
#ifdef VALUE_SAME #ifdef VALUE_SAME
/* short-circuit if no change */ /* short-circuit if no change */
if (VALUE_SAME(self->values[i], value)) { if (VALUE_SAME(self->values[i], value))
{
result = 0; result = 0;
goto Done; goto Done;
} }
...@@ -360,18 +378,21 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -360,18 +378,21 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
memmove(self->keys + i, self->keys + i+1, memmove(self->keys + i, self->keys + i+1,
sizeof(KEY_TYPE)*(self->len - i)); sizeof(KEY_TYPE)*(self->len - i));
if (self->values) { if (self->values)
{
DECREF_VALUE(self->values[i]); DECREF_VALUE(self->values[i]);
if (i < self->len) if (i < self->len)
memmove(self->values + i, self->values + i+1, memmove(self->values + i, self->values + i+1,
sizeof(VALUE_TYPE)*(self->len - i)); sizeof(VALUE_TYPE)*(self->len - i));
} }
if (! self->len) { if (! self->len)
{
self->size = 0; self->size = 0;
free(self->keys); free(self->keys);
self->keys = NULL; self->keys = NULL;
if (self->values) { if (self->values)
{
free(self->values); free(self->values);
self->values = NULL; self->values = NULL;
} }
...@@ -385,7 +406,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -385,7 +406,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
} }
/* The key doesn't exist, and belongs at index i. */ /* The key doesn't exist, and belongs at index i. */
if (!v) { if (!v)
{
/* Can't delete a non-existent key. */ /* Can't delete a non-existent key. */
PyErr_SetObject(PyExc_KeyError, keyarg); PyErr_SetObject(PyExc_KeyError, keyarg);
goto Done; goto Done;
...@@ -395,10 +417,12 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -395,10 +417,12 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
if (self->len == self->size && Bucket_grow(self, -1, noval) < 0) if (self->len == self->size && Bucket_grow(self, -1, noval) < 0)
goto Done; goto Done;
if (self->len > i) { if (self->len > i)
{
memmove(self->keys + i + 1, self->keys + i, memmove(self->keys + i + 1, self->keys + i,
sizeof(KEY_TYPE) * (self->len - i)); sizeof(KEY_TYPE) * (self->len - i));
if (self->values) { if (self->values)
{
memmove(self->values + i + 1, self->values + i, memmove(self->values + i + 1, self->values + i,
sizeof(VALUE_TYPE) * (self->len - i)); sizeof(VALUE_TYPE) * (self->len - i));
} }
...@@ -407,7 +431,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -407,7 +431,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
COPY_KEY(self->keys[i], key); COPY_KEY(self->keys[i], key);
INCREF_KEY(self->keys[i]); INCREF_KEY(self->keys[i]);
if (! noval) { if (! noval)
{
COPY_VALUE(self->values[i], value); COPY_VALUE(self->values[i], value);
INCREF_VALUE(self->values[i]); INCREF_VALUE(self->values[i]);
} }
...@@ -418,7 +443,7 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, ...@@ -418,7 +443,7 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
if (PER_CHANGED(self) >= 0) if (PER_CHANGED(self) >= 0)
result = 1; result = 1;
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return result; return result;
} }
...@@ -461,8 +486,15 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -461,8 +486,15 @@ update_from_seq(PyObject *map, PyObject *seq)
* returns true for a PeristentMapping or PersistentDict, and we * returns true for a PeristentMapping or PersistentDict, and we
* want to use items() in those cases too. * want to use items() in those cases too.
*/ */
#ifdef PY3K
#define ITERITEMS "items"
#else
#define ITERITEMS "iteritems"
#endif
if (!PySequence_Check(seq) || /* or it "looks like a dict" */ if (!PySequence_Check(seq) || /* or it "looks like a dict" */
PyObject_HasAttrString(seq, "iteritems")) { PyObject_HasAttrString(seq, ITERITEMS))
#undef ITERITEMS
{
PyObject *items; PyObject *items;
items = PyObject_GetAttrString(seq, "items"); items = PyObject_GetAttrString(seq, "items");
if (items == NULL) if (items == NULL)
...@@ -478,15 +510,18 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -478,15 +510,18 @@ update_from_seq(PyObject *map, PyObject *seq)
iter = PyObject_GetIter(seq); iter = PyObject_GetIter(seq);
if (iter == NULL) if (iter == NULL)
goto err; goto err;
while (1) { while (1)
{
o = PyIter_Next(iter); o = PyIter_Next(iter);
if (o == NULL) { if (o == NULL)
{
if (PyErr_Occurred()) if (PyErr_Occurred())
goto err; goto err;
else else
break; break;
} }
if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != 2) { if (!PyTuple_Check(o) || PyTuple_GET_SIZE(o) != 2)
{
Py_DECREF(o); Py_DECREF(o);
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"Sequence must contain 2-item tuples"); "Sequence must contain 2-item tuples");
...@@ -494,7 +529,8 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -494,7 +529,8 @@ update_from_seq(PyObject *map, PyObject *seq)
} }
k = PyTuple_GET_ITEM(o, 0); k = PyTuple_GET_ITEM(o, 0);
v = PyTuple_GET_ITEM(o, 1); v = PyTuple_GET_ITEM(o, 1);
if (PyObject_SetItem(map, k, v) < 0) { if (PyObject_SetItem(map, k, v) < 0)
{
Py_DECREF(o); Py_DECREF(o);
goto err; goto err;
} }
...@@ -502,7 +538,7 @@ update_from_seq(PyObject *map, PyObject *seq) ...@@ -502,7 +538,7 @@ update_from_seq(PyObject *map, PyObject *seq)
} }
err = 0; err = 0;
err: err:
Py_DECREF(iter); Py_DECREF(iter);
Py_DECREF(seq); Py_DECREF(seq);
return err; return err;
...@@ -585,12 +621,14 @@ Bucket_deleteNextBucket(Bucket *self) ...@@ -585,12 +621,14 @@ Bucket_deleteNextBucket(Bucket *self)
PER_USE_OR_RETURN(self, -1); PER_USE_OR_RETURN(self, -1);
successor = self->next; successor = self->next;
if (successor) { if (successor)
{
Bucket *next; Bucket *next;
/* Before: self -> successor -> next /* Before: self -> successor -> next
* After: self --------------> next * After: self --------------> next
*/ */
UNLESS (PER_USE(successor)) goto Done; UNLESS (PER_USE(successor))
goto Done;
next = successor->next; next = successor->next;
PER_UNUSE(successor); PER_UNUSE(successor);
...@@ -602,7 +640,7 @@ Bucket_deleteNextBucket(Bucket *self) ...@@ -602,7 +640,7 @@ Bucket_deleteNextBucket(Bucket *self)
} }
result = 0; result = 0;
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return result; return result;
} }
...@@ -653,14 +691,17 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -653,14 +691,17 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal,
int copied = 1; int copied = 1;
COPY_KEY_FROM_ARG(key, keyarg, copied); COPY_KEY_FROM_ARG(key, keyarg, copied);
UNLESS (copied) return -1; UNLESS (copied)
return -1;
UNLESS (PER_USE(self)) return -1; UNLESS (PER_USE(self))
return -1;
BUCKET_SEARCH(i, cmp, self, key, goto Done); BUCKET_SEARCH(i, cmp, self, key, goto Done);
if (cmp == 0) { if (cmp == 0) {
/* exact match at index i */ /* exact match at index i */
if (exclude_equal) { if (exclude_equal)
{
/* but we don't want an exact match */ /* but we don't want an exact match */
if (low) if (low)
++i; ++i;
...@@ -679,7 +720,7 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal, ...@@ -679,7 +720,7 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal,
if (result) if (result)
*offset = i; *offset = i;
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return result; return result;
} }
...@@ -691,31 +732,36 @@ Bucket_maxminKey(Bucket *self, PyObject *args, int min) ...@@ -691,31 +732,36 @@ Bucket_maxminKey(Bucket *self, PyObject *args, int min)
int rc, offset = 0; int rc, offset = 0;
int empty_bucket = 1; int empty_bucket = 1;
if (args && ! PyArg_ParseTuple(args, "|O", &key)) return NULL; if (args && ! PyArg_ParseTuple(args, "|O", &key))
return NULL;
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
UNLESS (self->len) goto empty; UNLESS (self->len)
goto empty;
/* Find the low range */ /* Find the low range */
if (key) if (key)
{ {
if ((rc = Bucket_findRangeEnd(self, key, min, 0, &offset)) <= 0) if ((rc = Bucket_findRangeEnd(self, key, min, 0, &offset)) <= 0)
{ {
if (rc < 0) return NULL; if (rc < 0)
return NULL;
empty_bucket = 0; empty_bucket = 0;
goto empty; goto empty;
} }
} }
else if (min) offset = 0; else if (min)
else offset = self->len -1; offset = 0;
else
offset = self->len -1;
COPY_KEY_TO_OBJECT(key, self->keys[offset]); COPY_KEY_TO_OBJECT(key, self->keys[offset]);
PER_UNUSE(self); PER_UNUSE(self);
return key; return key;
empty: empty:
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
empty_bucket ? "empty bucket" : empty_bucket ? "empty bucket" :
"no key satisfies the conditions"); "no key satisfies the conditions");
...@@ -745,7 +791,8 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw, ...@@ -745,7 +791,8 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
int excludemax = 0; int excludemax = 0;
int rc; int rc;
if (args) { if (args)
{
if (! PyArg_ParseTupleAndKeywords(args, kw, "|OOii", search_keywords, if (! PyArg_ParseTupleAndKeywords(args, kw, "|OOii", search_keywords,
&min, &min,
&max, &max,
...@@ -754,19 +801,23 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw, ...@@ -754,19 +801,23 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
return -1; return -1;
} }
UNLESS (self->len) goto empty; UNLESS (self->len)
goto empty;
/* Find the low range */ /* Find the low range */
if (min != Py_None) { if (min != Py_None)
{
rc = Bucket_findRangeEnd(self, min, 1, excludemin, low); rc = Bucket_findRangeEnd(self, min, 1, excludemin, low);
if (rc < 0) if (rc < 0)
return -1; return -1;
if (rc == 0) if (rc == 0)
goto empty; goto empty;
} }
else { else
{
*low = 0; *low = 0;
if (excludemin) { if (excludemin)
{
if (self->len < 2) if (self->len < 2)
goto empty; goto empty;
++*low; ++*low;
...@@ -774,16 +825,19 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw, ...@@ -774,16 +825,19 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
} }
/* Find the high range */ /* Find the high range */
if (max != Py_None) { if (max != Py_None)
{
rc = Bucket_findRangeEnd(self, max, 0, excludemax, high); rc = Bucket_findRangeEnd(self, max, 0, excludemax, high);
if (rc < 0) if (rc < 0)
return -1; return -1;
if (rc == 0) if (rc == 0)
goto empty; goto empty;
} }
else { else
{
*high = self->len - 1; *high = self->len - 1;
if (excludemax) { if (excludemax)
{
if (self->len < 2) if (self->len < 2)
goto empty; goto empty;
--*high; --*high;
...@@ -794,7 +848,7 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw, ...@@ -794,7 +848,7 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
if (*low <= *high) if (*low <= *high)
return 0; return 0;
empty: empty:
*low = 0; *low = 0;
*high = -1; *high = -1;
return 0; return 0;
...@@ -825,7 +879,8 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw) ...@@ -825,7 +879,8 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw)
if (r == NULL) if (r == NULL)
goto err; goto err;
for (i=low; i <= high; i++) { for (i=low; i <= high; i++)
{
COPY_KEY_TO_OBJECT(key, self->keys[i]); COPY_KEY_TO_OBJECT(key, self->keys[i]);
if (PyList_SetItem(r, i-low , key) < 0) if (PyList_SetItem(r, i-low , key) < 0)
goto err; goto err;
...@@ -834,7 +889,7 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw) ...@@ -834,7 +889,7 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw)
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
return NULL; return NULL;
...@@ -858,21 +913,25 @@ bucket_values(Bucket *self, PyObject *args, PyObject *kw) ...@@ -858,21 +913,25 @@ bucket_values(Bucket *self, PyObject *args, PyObject *kw)
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
if (Bucket_rangeSearch(self, args, kw, &low, &high) < 0) goto err; if (Bucket_rangeSearch(self, args, kw, &low, &high) < 0)
goto err;
UNLESS (r=PyList_New(high-low+1)) goto err; UNLESS (r=PyList_New(high-low+1))
goto err;
for (i=low; i <= high; i++) for (i=low; i <= high; i++)
{ {
COPY_VALUE_TO_OBJECT(v, self->values[i]); COPY_VALUE_TO_OBJECT(v, self->values[i]);
UNLESS (v) goto err; UNLESS (v)
if (PyList_SetItem(r, i-low, v) < 0) goto err; goto err;
if (PyList_SetItem(r, i-low, v) < 0)
goto err;
} }
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
return NULL; return NULL;
...@@ -896,23 +955,29 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw) ...@@ -896,23 +955,29 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw)
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
if (Bucket_rangeSearch(self, args, kw, &low, &high) < 0) goto err; if (Bucket_rangeSearch(self, args, kw, &low, &high) < 0)
goto err;
UNLESS (r=PyList_New(high-low+1)) goto err; UNLESS (r=PyList_New(high-low+1))
goto err;
for (i=low; i <= high; i++) for (i=low; i <= high; i++)
{ {
UNLESS (item = PyTuple_New(2)) goto err; UNLESS (item = PyTuple_New(2))
goto err;
COPY_KEY_TO_OBJECT(o, self->keys[i]); COPY_KEY_TO_OBJECT(o, self->keys[i]);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 0, o); PyTuple_SET_ITEM(item, 0, o);
COPY_VALUE_TO_OBJECT(o, self->values[i]); COPY_VALUE_TO_OBJECT(o, self->values[i]);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 1, o); PyTuple_SET_ITEM(item, 1, o);
if (PyList_SetItem(r, i-low, item) < 0) goto err; if (PyList_SetItem(r, i-low, item) < 0)
goto err;
item = 0; item = 0;
} }
...@@ -920,7 +985,7 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw) ...@@ -920,7 +985,7 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw)
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
Py_XDECREF(item); Py_XDECREF(item);
...@@ -938,51 +1003,62 @@ bucket_byValue(Bucket *self, PyObject *omin) ...@@ -938,51 +1003,62 @@ bucket_byValue(Bucket *self, PyObject *omin)
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
COPY_VALUE_FROM_ARG(min, omin, copied); COPY_VALUE_FROM_ARG(min, omin, copied);
UNLESS(copied) return NULL; UNLESS(copied)
return NULL;
for (i=0, l=0; i < self->len; i++) for (i=0, l=0; i < self->len; i++)
if (TEST_VALUE(self->values[i], min) >= 0) if (TEST_VALUE(self->values[i], min) >= 0)
l++; l++;
UNLESS (r=PyList_New(l)) goto err; UNLESS (r=PyList_New(l))
goto err;
for (i=0, l=0; i < self->len; i++) for (i=0, l=0; i < self->len; i++)
{ {
if (TEST_VALUE(self->values[i], min) < 0) continue; if (TEST_VALUE(self->values[i], min) < 0)
continue;
UNLESS (item = PyTuple_New(2)) goto err; UNLESS (item = PyTuple_New(2))
goto err;
COPY_KEY_TO_OBJECT(o, self->keys[i]); COPY_KEY_TO_OBJECT(o, self->keys[i]);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 1, o); PyTuple_SET_ITEM(item, 1, o);
COPY_VALUE(v, self->values[i]); COPY_VALUE(v, self->values[i]);
NORMALIZE_VALUE(v, min); NORMALIZE_VALUE(v, min);
COPY_VALUE_TO_OBJECT(o, v); COPY_VALUE_TO_OBJECT(o, v);
DECREF_VALUE(v); DECREF_VALUE(v);
UNLESS (o) goto err; UNLESS (o)
goto err;
PyTuple_SET_ITEM(item, 0, o); PyTuple_SET_ITEM(item, 0, o);
if (PyList_SetItem(r, l, item) < 0) goto err; if (PyList_SetItem(r, l, item) < 0)
goto err;
l++; l++;
item = 0; item = 0;
} }
item=PyObject_GetAttr(r,sort_str); item=PyObject_GetAttr(r,sort_str);
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_CallObject(item, NULL)); ASSIGN(item, PyObject_CallObject(item, NULL));
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_GetAttr(r, reverse_str)); ASSIGN(item, PyObject_GetAttr(r, reverse_str));
UNLESS (item) goto err; UNLESS (item)
goto err;
ASSIGN(item, PyObject_CallObject(item, NULL)); ASSIGN(item, PyObject_CallObject(item, NULL));
UNLESS (item) goto err; UNLESS (item)
goto err;
Py_DECREF(item); Py_DECREF(item);
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(r); Py_XDECREF(r);
Py_XDECREF(item); Py_XDECREF(item);
...@@ -999,7 +1075,8 @@ _bucket_clear(Bucket *self) ...@@ -999,7 +1075,8 @@ _bucket_clear(Bucket *self)
*/ */
self->len = self->size = 0; self->len = self->size = 0;
if (self->next) { if (self->next)
{
Py_DECREF(self->next); Py_DECREF(self->next);
self->next = NULL; self->next = NULL;
} }
...@@ -1008,7 +1085,8 @@ _bucket_clear(Bucket *self) ...@@ -1008,7 +1085,8 @@ _bucket_clear(Bucket *self)
when neither key nor value is an object, i.e. II. */ when neither key nor value is an object, i.e. II. */
(void)len; (void)len;
if (self->keys) { if (self->keys)
{
#ifdef KEY_TYPE_IS_PYOBJECT #ifdef KEY_TYPE_IS_PYOBJECT
int i; int i;
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
...@@ -1018,7 +1096,8 @@ _bucket_clear(Bucket *self) ...@@ -1018,7 +1096,8 @@ _bucket_clear(Bucket *self)
self->keys = NULL; self->keys = NULL;
} }
if (self->values) { if (self->values)
{
#ifdef VALUE_TYPE_IS_PYOBJECT #ifdef VALUE_TYPE_IS_PYOBJECT
int i; int i;
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
...@@ -1037,12 +1116,14 @@ bucket__p_deactivate(Bucket *self, PyObject *args, PyObject *keywords) ...@@ -1037,12 +1116,14 @@ bucket__p_deactivate(Bucket *self, PyObject *args, PyObject *keywords)
int ghostify = 1; int ghostify = 1;
PyObject *force = NULL; PyObject *force = NULL;
if (args && PyTuple_GET_SIZE(args) > 0) { if (args && PyTuple_GET_SIZE(args) > 0)
{
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"_p_deactivate takes no positional arguments"); "_p_deactivate takes no positional arguments");
return NULL; return NULL;
} }
if (keywords) { if (keywords)
{
int size = PyDict_Size(keywords); int size = PyDict_Size(keywords);
force = PyDict_GetItemString(keywords, "force"); force = PyDict_GetItemString(keywords, "force");
if (force) if (force)
...@@ -1054,7 +1135,8 @@ bucket__p_deactivate(Bucket *self, PyObject *args, PyObject *keywords) ...@@ -1054,7 +1135,8 @@ bucket__p_deactivate(Bucket *self, PyObject *args, PyObject *keywords)
} }
} }
if (self->jar && self->oid) { if (self->jar && self->oid)
{
ghostify = self->state == cPersistent_UPTODATE_STATE; ghostify = self->state == cPersistent_UPTODATE_STATE;
if (!ghostify && force) { if (!ghostify && force) {
if (PyObject_IsTrue(force)) if (PyObject_IsTrue(force))
...@@ -1078,7 +1160,8 @@ bucket_clear(Bucket *self, PyObject *args) ...@@ -1078,7 +1160,8 @@ bucket_clear(Bucket *self, PyObject *args)
{ {
PER_USE_OR_RETURN(self, NULL); PER_USE_OR_RETURN(self, NULL);
if (self->len) { if (self->len)
{
if (_bucket_clear(self) < 0) if (_bucket_clear(self) < 0)
return NULL; return NULL;
if (PER_CHANGED(self) < 0) if (PER_CHANGED(self) < 0)
...@@ -1088,7 +1171,7 @@ bucket_clear(Bucket *self, PyObject *args) ...@@ -1088,7 +1171,7 @@ bucket_clear(Bucket *self, PyObject *args)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
return NULL; return NULL;
} }
...@@ -1126,7 +1209,8 @@ bucket_getstate(Bucket *self) ...@@ -1126,7 +1209,8 @@ bucket_getstate(Bucket *self)
len = self->len; len = self->len;
if (self->values) { /* Bucket */ if (self->values) /* Bucket */
{
items = PyTuple_New(len * 2); items = PyTuple_New(len * 2);
if (items == NULL) if (items == NULL)
goto err; goto err;
...@@ -1143,7 +1227,9 @@ bucket_getstate(Bucket *self) ...@@ -1143,7 +1227,9 @@ bucket_getstate(Bucket *self)
PyTuple_SET_ITEM(items, l, o); PyTuple_SET_ITEM(items, l, o);
l++; l++;
} }
} else { /* Set */ }
else /* Set */
{
items = PyTuple_New(len); items = PyTuple_New(len);
if (items == NULL) if (items == NULL)
goto err; goto err;
...@@ -1164,7 +1250,7 @@ bucket_getstate(Bucket *self) ...@@ -1164,7 +1250,7 @@ bucket_getstate(Bucket *self)
PER_UNUSE(self); PER_UNUSE(self);
return state; return state;
err: err:
PER_UNUSE(self); PER_UNUSE(self);
Py_XDECREF(items); Py_XDECREF(items);
return NULL; return NULL;
...@@ -1355,7 +1441,7 @@ bucket_contains(Bucket *self, PyObject *key) ...@@ -1355,7 +1441,7 @@ bucket_contains(Bucket *self, PyObject *key)
int result = -1; int result = -1;
if (asobj != NULL) { if (asobj != NULL) {
result = PyInt_AsLong(asobj) ? 1 : 0; result = INT_AS_LONG(asobj) ? 1 : 0;
Py_DECREF(asobj); Py_DECREF(asobj);
} }
return result; return result;
...@@ -1404,12 +1490,13 @@ buildBucketIter(Bucket *self, PyObject *args, PyObject *kw, char kind) ...@@ -1404,12 +1490,13 @@ buildBucketIter(Bucket *self, PyObject *args, PyObject *kw, char kind)
items = (BTreeItems *)newBTreeItems(kind, self, lowoffset, items = (BTreeItems *)newBTreeItems(kind, self, lowoffset,
self, highoffset); self, highoffset);
if (items == NULL) goto Done; if (items == NULL)
goto Done;
result = BTreeIter_new(items); /* win or lose, we're done */ result = BTreeIter_new(items); /* win or lose, we're done */
Py_DECREF(items); Py_DECREF(items);
Done: Done:
PER_UNUSE(self); PER_UNUSE(self);
return (PyObject *)result; return (PyObject *)result;
} }
...@@ -1487,7 +1574,7 @@ _bucket__p_resolveConflict(PyObject *ob_type, PyObject *s[3]) ...@@ -1487,7 +1574,7 @@ _bucket__p_resolveConflict(PyObject *ob_type, PyObject *s[3])
else else
result = bucket_merge(b[0], b[1], b[2]); result = bucket_merge(b[0], b[1], b[2]);
Done: Done:
Py_XDECREF(meth); Py_XDECREF(meth);
Py_XDECREF(a); Py_XDECREF(a);
Py_XDECREF(b[0]); Py_XDECREF(b[0]);
...@@ -1505,7 +1592,7 @@ bucket__p_resolveConflict(Bucket *self, PyObject *args) ...@@ -1505,7 +1592,7 @@ bucket__p_resolveConflict(Bucket *self, PyObject *args)
if (!PyArg_ParseTuple(args, "OOO", &s[0], &s[1], &s[2])) if (!PyArg_ParseTuple(args, "OOO", &s[0], &s[1], &s[2]))
return NULL; return NULL;
return _bucket__p_resolveConflict((PyObject *)self->ob_type, s); return _bucket__p_resolveConflict((PyObject *)Py_TYPE(self), s);
} }
#endif #endif
...@@ -1529,7 +1616,7 @@ static struct PyMethodDef Bucket_methods[] = { ...@@ -1529,7 +1616,7 @@ static struct PyMethodDef Bucket_methods[] = {
{"__setstate__", (PyCFunction) bucket_setstate, METH_O, {"__setstate__", (PyCFunction) bucket_setstate, METH_O,
"__setstate__() -- Set the state of the object"}, "__setstate__() -- Set the state of the object"},
{"keys", (PyCFunction) bucket_keys, METH_KEYWORDS, {"keys", (PyCFunction) bucket_keys, METH_VARARGS | METH_KEYWORDS,
"keys([min, max]) -- Return the keys"}, "keys([min, max]) -- Return the keys"},
{"has_key", (PyCFunction) bucket_has_key, METH_O, {"has_key", (PyCFunction) bucket_has_key, METH_O,
...@@ -1549,10 +1636,10 @@ static struct PyMethodDef Bucket_methods[] = { ...@@ -1549,10 +1636,10 @@ static struct PyMethodDef Bucket_methods[] = {
"minKey([key]) -- Find the minimum key\n\n" "minKey([key]) -- Find the minimum key\n\n"
"If an argument is given, find the minimum >= the argument"}, "If an argument is given, find the minimum >= the argument"},
{"values", (PyCFunction) bucket_values, METH_KEYWORDS, {"values", (PyCFunction) bucket_values, METH_VARARGS | METH_KEYWORDS,
"values([min, max]) -- Return the values"}, "values([min, max]) -- Return the values"},
{"items", (PyCFunction) bucket_items, METH_KEYWORDS, {"items", (PyCFunction) bucket_items, METH_VARARGS | METH_KEYWORDS,
"items([min, max])) -- Return the items"}, "items([min, max])) -- Return the items"},
{"byValue", (PyCFunction) bucket_byValue, METH_O, {"byValue", (PyCFunction) bucket_byValue, METH_O,
...@@ -1573,25 +1660,28 @@ static struct PyMethodDef Bucket_methods[] = { ...@@ -1573,25 +1660,28 @@ static struct PyMethodDef Bucket_methods[] = {
"If key is not found, d is returned if given, otherwise KeyError\n" "If key is not found, d is returned if given, otherwise KeyError\n"
"is raised."}, "is raised."},
{"iterkeys", (PyCFunction) Bucket_iterkeys, METH_KEYWORDS, {"iterkeys", (PyCFunction) Bucket_iterkeys, METH_VARARGS | METH_KEYWORDS,
"B.iterkeys([min[,max]]) -> an iterator over the keys of B"}, "B.iterkeys([min[,max]]) -> an iterator over the keys of B"},
{"itervalues", (PyCFunction) Bucket_itervalues, METH_KEYWORDS, {"itervalues",
(PyCFunction) Bucket_itervalues, METH_VARARGS | METH_KEYWORDS,
"B.itervalues([min[,max]]) -> an iterator over the values of B"}, "B.itervalues([min[,max]]) -> an iterator over the values of B"},
{"iteritems", (PyCFunction) Bucket_iteritems, METH_KEYWORDS, {"iteritems", (PyCFunction) Bucket_iteritems, METH_VARARGS | METH_KEYWORDS,
"B.iteritems([min[,max]]) -> an iterator over the (key, value) items of B"}, "B.iteritems([min[,max]]) -> an iterator over the (key, value) "
"items of B"},
#ifdef EXTRA_BUCKET_METHODS #ifdef EXTRA_BUCKET_METHODS
EXTRA_BUCKET_METHODS EXTRA_BUCKET_METHODS
#endif #endif
#ifdef PERSISTENT #ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) bucket__p_resolveConflict, {"_p_resolveConflict",
METH_VARARGS, (PyCFunction) bucket__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"}, "_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) bucket__p_deactivate, METH_KEYWORDS, {"_p_deactivate",
(PyCFunction) bucket__p_deactivate, METH_VARARGS | METH_KEYWORDS,
"_p_deactivate() -- Reinitialize from a newly created copy"}, "_p_deactivate() -- Reinitialize from a newly created copy"},
#endif #endif
{NULL, NULL} {NULL, NULL}
...@@ -1648,8 +1738,10 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg) ...@@ -1648,8 +1738,10 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg)
goto Done; goto Done;
len = self->len; len = self->len;
(void)i; /* if neither keys nor values are PyObject*, "i" is otherwise /* if neither keys nor values are PyObject*, "i" is otherwise
unreferenced and we get a nuisance compiler wng */ unreferenced and we get a nuisance compiler wng */
(void)i;
(void)len;
#ifdef KEY_TYPE_IS_PYOBJECT #ifdef KEY_TYPE_IS_PYOBJECT
/* Keys are Python objects so need to be traversed. */ /* Keys are Python objects so need to be traversed. */
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
...@@ -1667,7 +1759,7 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg) ...@@ -1667,7 +1759,7 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg)
VISIT(self->next); VISIT(self->next);
Done: Done:
return err; return err;
#undef VISIT #undef VISIT
...@@ -1686,7 +1778,8 @@ static int ...@@ -1686,7 +1778,8 @@ static int
Bucket_length( Bucket *self) Bucket_length( Bucket *self)
{ {
int r; int r;
UNLESS (PER_USE(self)) return -1; UNLESS (PER_USE(self))
return -1;
r = self->len; r = self->len;
PER_UNUSE(self); PER_UNUSE(self);
return r; return r;
...@@ -1715,47 +1808,74 @@ static PyObject * ...@@ -1715,47 +1808,74 @@ static PyObject *
bucket_repr(Bucket *self) bucket_repr(Bucket *self)
{ {
PyObject *i, *r; PyObject *i, *r;
#ifdef PY3K
PyObject *rb;
#endif
char repr[10000]; char repr[10000];
int rv; int rv;
i = bucket_items(self, NULL, NULL); i = bucket_items(self, NULL, NULL);
if (!i) if (!i)
{
return NULL; return NULL;
}
r = PyObject_Repr(i); r = PyObject_Repr(i);
Py_DECREF(i); Py_DECREF(i);
if (!r) { if (!r)
{
return NULL; return NULL;
} }
#ifdef PY3K
rb = PyUnicode_AsLatin1String(r);
rv = PyOS_snprintf(repr, sizeof(repr),
"%s(%s)", Py_TYPE(self)->tp_name,
PyBytes_AsString(rb));
Py_DECREF(rb);
#else
rv = PyOS_snprintf(repr, sizeof(repr), rv = PyOS_snprintf(repr, sizeof(repr),
"%s(%s)", self->ob_type->tp_name, "%s(%s)", Py_TYPE(self)->tp_name,
PyString_AS_STRING(r)); PyBytes_AS_STRING(r));
if (rv > 0 && rv < sizeof(repr)) { #endif
if (rv > 0 && rv < sizeof(repr))
{
Py_DECREF(r); Py_DECREF(r);
return PyString_FromStringAndSize(repr, strlen(repr)); #ifdef PY3K
return PyUnicode_DecodeLatin1(repr, sizeof(repr), "surrogateescape");
#else
return PyBytes_FromStringAndSize(repr, sizeof(repr));
#endif
} }
else { else
{
/* The static buffer wasn't big enough */ /* The static buffer wasn't big enough */
int size; int size;
PyObject *s; PyObject *s;
#ifdef PY3K
PyObject *result;
#endif
/* 3 for the parens and the null byte */ /* 3 for the parens and the null byte */
size = strlen(self->ob_type->tp_name) + PyString_GET_SIZE(r) + 3; size = strlen(Py_TYPE(self)->tp_name) + PyBytes_GET_SIZE(r) + 3;
s = PyString_FromStringAndSize(NULL, size); s = PyBytes_FromStringAndSize(NULL, size);
if (!s) { if (!s) {
Py_DECREF(r); Py_DECREF(r);
return r; return r;
} }
PyOS_snprintf(PyString_AS_STRING(s), size, PyOS_snprintf(PyBytes_AS_STRING(s), size,
"%s(%s)", self->ob_type->tp_name, PyString_AS_STRING(r)); "%s(%s)", Py_TYPE(self)->tp_name, PyBytes_AS_STRING(r));
Py_DECREF(r); Py_DECREF(r);
#ifdef PY3K
result = PyUnicode_FromEncodedObject(s, "latin1", "surrogateescape");
Py_DECREF(s);
return result;
#else
return s; return s;
#endif
} }
} }
static PyTypeObject BucketType = { static PyTypeObject BucketType = {
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ PyVarObject_HEAD_INIT(NULL, 0)
0, /* ob_size */ MODULE_NAME MOD_NAME_PREFIX "Bucket", /* tp_name */
MODULE_NAME MOD_NAME_PREFIX "Bucket",/* tp_name */
sizeof(Bucket), /* tp_basicsize */ sizeof(Bucket), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
(destructor)bucket_dealloc, /* tp_dealloc */ (destructor)bucket_dealloc, /* tp_dealloc */
...@@ -1773,7 +1893,8 @@ static PyTypeObject BucketType = { ...@@ -1773,7 +1893,8 @@ static PyTypeObject BucketType = {
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)bucket_traverse, /* tp_traverse */ (traverseproc)bucket_traverse, /* tp_traverse */
...@@ -1800,7 +1921,8 @@ nextBucket(SetIteration *i) ...@@ -1800,7 +1921,8 @@ nextBucket(SetIteration *i)
{ {
if (i->position >= 0) if (i->position >= 0)
{ {
UNLESS(PER_USE(BUCKET(i->set))) return -1; UNLESS(PER_USE(BUCKET(i->set)))
return -1;
if (i->position) if (i->position)
{ {
...@@ -1825,6 +1947,5 @@ nextBucket(SetIteration *i) ...@@ -1825,6 +1947,5 @@ nextBucket(SetIteration *i)
PER_ALLOW_DEACTIVATION(BUCKET(i->set)); PER_ALLOW_DEACTIVATION(BUCKET(i->set));
} }
return 0; return 0;
} }
...@@ -99,17 +99,8 @@ weightedUnionPy = _set_operation(_weightedUnion, IFSetPy) ...@@ -99,17 +99,8 @@ weightedUnionPy = _set_operation(_weightedUnion, IFSetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, IFSetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, IFSetPy)
try: try:
from _IFBTree import IFBucket from ._IFBTree import IFBucket
from _IFBTree import IFSet except ImportError: #pragma NO COVER w/ C extensions
from _IFBTree import IFBTree
from _IFBTree import IFTreeSet
from _IFBTree import difference
from _IFBTree import union
from _IFBTree import intersection
from _IFBTree import multiunion
from _OIBTree import weightedUnion
from _OIBTree import weightedIntersection
except ImportError: #pragma NO COVER
IFBucket = IFBucketPy IFBucket = IFBucketPy
IFSet = IFSetPy IFSet = IFSetPy
IFBTree = IFBTreePy IFBTree = IFBTreePy
...@@ -120,6 +111,16 @@ except ImportError: #pragma NO COVER ...@@ -120,6 +111,16 @@ except ImportError: #pragma NO COVER
multiunion = multiunionPy multiunion = multiunionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._IFBTree import IFSet
from ._IFBTree import IFBTree
from ._IFBTree import IFTreeSet
from ._IFBTree import difference
from ._IFBTree import union
from ._IFBTree import intersection
from ._IFBTree import multiunion
from ._IFBTree import weightedUnion
from ._IFBTree import weightedIntersection
Bucket = IFBucket Bucket = IFBucket
Set = IFSet Set = IFSet
......
...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, IISetPy) ...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, IISetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, IISetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, IISetPy)
try: try:
from _IIBTree import IIBucket from ._IIBTree import IIBucket
from _IIBTree import IISet except ImportError: #pragma NO COVER w/ C extensions
from _IIBTree import IIBTree
from _IIBTree import IITreeSet
from _IIBTree import difference
from _IIBTree import union
from _IIBTree import intersection
from _IIBTree import multiunion
from _IIBTree import weightedUnion
from _IIBTree import weightedIntersection
except ImportError: #pragma NO COVER
IIBucket = IIBucketPy IIBucket = IIBucketPy
IISet = IISetPy IISet = IISetPy
IIBTree = IIBTreePy IIBTree = IIBTreePy
...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER ...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER
multiunion = multiunionPy multiunion = multiunionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._IIBTree import IISet
from ._IIBTree import IIBTree
from ._IIBTree import IITreeSet
from ._IIBTree import difference
from ._IIBTree import union
from ._IIBTree import intersection
from ._IIBTree import multiunion
from ._IIBTree import weightedUnion
from ._IIBTree import weightedIntersection
Bucket = IIBucket Bucket = IIBucket
Set = IISet Set = IISet
......
...@@ -83,15 +83,8 @@ intersectionPy = _set_operation(_intersection, IOSetPy) ...@@ -83,15 +83,8 @@ intersectionPy = _set_operation(_intersection, IOSetPy)
multiunionPy = _set_operation(_multiunion, IOSetPy) multiunionPy = _set_operation(_multiunion, IOSetPy)
try: try:
from _IOBTree import IOBucket from ._IOBTree import IOBucket
from _IOBTree import IOSet except ImportError: #pragma NO COVER w/ C extensions
from _IOBTree import IOBTree
from _IOBTree import IOTreeSet
from _IOBTree import difference
from _IOBTree import union
from _IOBTree import intersection
from _IOBTree import multiunion
except ImportError: #pragma NO COVER
IOBucket = IOBucketPy IOBucket = IOBucketPy
IOSet = IOSetPy IOSet = IOSetPy
IOBTree = IOBTreePy IOBTree = IOBTreePy
...@@ -100,6 +93,14 @@ except ImportError: #pragma NO COVER ...@@ -100,6 +93,14 @@ except ImportError: #pragma NO COVER
union = unionPy union = unionPy
intersection = intersectionPy intersection = intersectionPy
multiunion = multiunionPy multiunion = multiunionPy
else: #pragma NO COVER w/o C extensions
from ._IOBTree import IOSet
from ._IOBTree import IOBTree
from ._IOBTree import IOTreeSet
from ._IOBTree import difference
from ._IOBTree import union
from ._IOBTree import intersection
from ._IOBTree import multiunion
Bucket = IOBucket Bucket = IOBucket
Set = IOSet Set = IOSet
......
...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, LFSetPy) ...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, LFSetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, LFSetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, LFSetPy)
try: try:
from _LFBTree import LFBucket from ._LFBTree import LFBucket
from _LFBTree import LFSet except ImportError: #pragma NO COVER w/ C extensions
from _LFBTree import LFBTree
from _LFBTree import LFTreeSet
from _LFBTree import difference
from _LFBTree import union
from _LFBTree import intersection
from _LFBTree import multiunion
from _OIBTree import weightedUnion
from _OIBTree import weightedIntersection
except ImportError: #pragma NO COVER
LFBucket = LFBucketPy LFBucket = LFBucketPy
LFSet = LFSetPy LFSet = LFSetPy
LFBTree = LFBTreePy LFBTree = LFBTreePy
...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER ...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER
multiunion = multiunionPy multiunion = multiunionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._LFBTree import LFSet
from ._LFBTree import LFBTree
from ._LFBTree import LFTreeSet
from ._LFBTree import difference
from ._LFBTree import union
from ._LFBTree import intersection
from ._LFBTree import multiunion
from ._LFBTree import weightedUnion
from ._LFBTree import weightedIntersection
Bucket = LFBucket Bucket = LFBucket
Set = LFSet Set = LFSet
......
...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, LLSetPy) ...@@ -100,17 +100,8 @@ weightedUnionPy = _set_operation(_weightedUnion, LLSetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, LLSetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, LLSetPy)
try: try:
from _LLBTree import LLBucket from ._LLBTree import LLBucket
from _LLBTree import LLSet except ImportError: #pragma NO COVER w/ C extensions
from _LLBTree import LLBTree
from _LLBTree import LLTreeSet
from _LLBTree import difference
from _LLBTree import union
from _LLBTree import intersection
from _LLBTree import multiunion
from _LLBTree import weightedUnion
from _LLBTree import weightedIntersection
except ImportError: #pragma NO COVER
LLBucket = LLBucketPy LLBucket = LLBucketPy
LLSet = LLSetPy LLSet = LLSetPy
LLBTree = LLBTreePy LLBTree = LLBTreePy
...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER ...@@ -121,6 +112,16 @@ except ImportError: #pragma NO COVER
multiunion = multiunionPy multiunion = multiunionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._LLBTree import LLSet
from ._LLBTree import LLBTree
from ._LLBTree import LLTreeSet
from ._LLBTree import difference
from ._LLBTree import union
from ._LLBTree import intersection
from ._LLBTree import multiunion
from ._LLBTree import weightedUnion
from ._LLBTree import weightedIntersection
Bucket = LLBucket Bucket = LLBucket
Set = LLSet Set = LLSet
......
...@@ -83,15 +83,8 @@ intersectionPy = _set_operation(_intersection, LOSetPy) ...@@ -83,15 +83,8 @@ intersectionPy = _set_operation(_intersection, LOSetPy)
multiunionPy = _set_operation(_multiunion, LOSetPy) multiunionPy = _set_operation(_multiunion, LOSetPy)
try: try:
from _LOBTree import LOBucket from ._LOBTree import LOBucket
from _LOBTree import LOSet except ImportError: #pragma NO COVER w/ C extensions
from _LOBTree import LOBTree
from _LOBTree import LOTreeSet
from _LOBTree import difference
from _LOBTree import union
from _LOBTree import intersection
from _LOBTree import multiunion
except ImportError: #pragma NO COVER
LOBucket = LOBucketPy LOBucket = LOBucketPy
LOSet = LOSetPy LOSet = LOSetPy
LOBTree = LOBTreePy LOBTree = LOBTreePy
...@@ -100,6 +93,14 @@ except ImportError: #pragma NO COVER ...@@ -100,6 +93,14 @@ except ImportError: #pragma NO COVER
union = unionPy union = unionPy
intersection = intersectionPy intersection = intersectionPy
multiunion = multiunionPy multiunion = multiunionPy
else: #pragma NO COVER w/o C extensions
from ._LOBTree import LOSet
from ._LOBTree import LOBTree
from ._LOBTree import LOTreeSet
from ._LOBTree import difference
from ._LOBTree import union
from ._LOBTree import intersection
from ._LOBTree import multiunion
Bucket = LOBucket Bucket = LOBucket
Set = LOSet Set = LOSet
......
...@@ -97,16 +97,8 @@ weightedUnionPy = _set_operation(_weightedUnion, OISetPy) ...@@ -97,16 +97,8 @@ weightedUnionPy = _set_operation(_weightedUnion, OISetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, OISetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, OISetPy)
try: try:
from _OIBTree import OIBucket from ._OIBTree import OIBucket
from _OIBTree import OISet except ImportError: #pragma NO COVER w/ C extensions
from _OIBTree import OIBTree
from _OIBTree import OITreeSet
from _OIBTree import difference
from _OIBTree import union
from _OIBTree import intersection
from _OIBTree import weightedUnion
from _OIBTree import weightedIntersection
except ImportError: #pragma NO COVER
OIBucket = OIBucketPy OIBucket = OIBucketPy
OISet = OISetPy OISet = OISetPy
OIBTree = OIBTreePy OIBTree = OIBTreePy
...@@ -116,6 +108,15 @@ except ImportError: #pragma NO COVER ...@@ -116,6 +108,15 @@ except ImportError: #pragma NO COVER
intersection = intersectionPy intersection = intersectionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._OIBTree import OISet
from ._OIBTree import OIBTree
from ._OIBTree import OITreeSet
from ._OIBTree import difference
from ._OIBTree import union
from ._OIBTree import intersection
from ._OIBTree import weightedUnion
from ._OIBTree import weightedIntersection
Bucket = OIBucket Bucket = OIBucket
......
...@@ -98,16 +98,8 @@ weightedUnionPy = _set_operation(_weightedUnion, OLSetPy) ...@@ -98,16 +98,8 @@ weightedUnionPy = _set_operation(_weightedUnion, OLSetPy)
weightedIntersectionPy = _set_operation(_weightedIntersection, OLSetPy) weightedIntersectionPy = _set_operation(_weightedIntersection, OLSetPy)
try: try:
from _OLBTree import OLBucket from ._OLBTree import OLBucket
from _OLBTree import OLSet except ImportError: #pragma NO COVER w/ C extensions
from _OLBTree import OLBTree
from _OLBTree import OLTreeSet
from _OLBTree import difference
from _OLBTree import union
from _OLBTree import intersection
from _OLBTree import weightedUnion
from _OLBTree import weightedIntersection
except ImportError: #pragma NO COVER
OLBucket = OLBucketPy OLBucket = OLBucketPy
OLSet = OLSetPy OLSet = OLSetPy
OLBTree = OLBTreePy OLBTree = OLBTreePy
...@@ -117,6 +109,15 @@ except ImportError: #pragma NO COVER ...@@ -117,6 +109,15 @@ except ImportError: #pragma NO COVER
intersection = intersectionPy intersection = intersectionPy
weightedUnion = weightedUnionPy weightedUnion = weightedUnionPy
weightedIntersection = weightedIntersectionPy weightedIntersection = weightedIntersectionPy
else: #pragma NO COVER w/o C extensions
from ._OLBTree import OLSet
from ._OLBTree import OLBTree
from ._OLBTree import OLTreeSet
from ._OLBTree import difference
from ._OLBTree import union
from ._OLBTree import intersection
from ._OLBTree import weightedUnion
from ._OLBTree import weightedIntersection
Bucket = OLBucket Bucket = OLBucket
Set = OLSet Set = OLSet
......
...@@ -78,14 +78,8 @@ unionPy = _set_operation(_union, OOSetPy) ...@@ -78,14 +78,8 @@ unionPy = _set_operation(_union, OOSetPy)
intersectionPy = _set_operation(_intersection, OOSetPy) intersectionPy = _set_operation(_intersection, OOSetPy)
try: try:
from _OOBTree import OOBucket from ._OOBTree import OOBucket
from _OOBTree import OOSet except ImportError as e: #pragma NO COVER w/ C extensions
from _OOBTree import OOBTree
from _OOBTree import OOTreeSet
from _OOBTree import difference
from _OOBTree import union
from _OOBTree import intersection
except ImportError: #pragma NO COVER
OOBucket = OOBucketPy OOBucket = OOBucketPy
OOSet = OOSetPy OOSet = OOSetPy
OOBTree = OOBTreePy OOBTree = OOBTreePy
...@@ -93,6 +87,13 @@ except ImportError: #pragma NO COVER ...@@ -93,6 +87,13 @@ except ImportError: #pragma NO COVER
difference = differencePy difference = differencePy
union = unionPy union = unionPy
intersection = intersectionPy intersection = intersectionPy
else: #pragma NO COVER w/o C extensions
from ._OOBTree import OOSet
from ._OOBTree import OOBTree
from ._OOBTree import OOTreeSet
from ._OOBTree import difference
from ._OOBTree import union
from ._OOBTree import intersection
Bucket = OOBucket Bucket = OOBucket
Set = OOSet Set = OOSet
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE FOR A PARTICULAR PURPOSE
****************************************************************************/ ****************************************************************************/
#include "_compat.h"
#define SETTEMPLATE_C "$Id$\n" #define SETTEMPLATE_C "$Id$\n"
...@@ -20,9 +21,11 @@ Set_insert(Bucket *self, PyObject *args) ...@@ -20,9 +21,11 @@ Set_insert(Bucket *self, PyObject *args)
PyObject *key; PyObject *key;
int i; int i;
UNLESS (PyArg_ParseTuple(args, "O", &key)) return NULL; UNLESS (PyArg_ParseTuple(args, "O", &key))
if ( (i=_bucket_set(self, key, Py_None, 1, 1, 0)) < 0) return NULL; return NULL;
return PyInt_FromLong(i); if ( (i=_bucket_set(self, key, Py_None, 1, 1, 0)) < 0)
return NULL;
return INT_FROM_LONG(i);
} }
/* _Set_update and _TreeSet_update are identical except for the /* _Set_update and _TreeSet_update are identical except for the
...@@ -55,7 +58,7 @@ _Set_update(Bucket *self, PyObject *seq) ...@@ -55,7 +58,7 @@ _Set_update(Bucket *self, PyObject *seq)
n += ind; n += ind;
} }
err: err:
Py_DECREF(iter); Py_DECREF(iter);
if (ind < 0) if (ind < 0)
return -1; return -1;
...@@ -77,7 +80,7 @@ Set_update(Bucket *self, PyObject *args) ...@@ -77,7 +80,7 @@ Set_update(Bucket *self, PyObject *args)
return NULL; return NULL;
} }
return PyInt_FromLong(n); return INT_FROM_LONG(n);
} }
static PyObject * static PyObject *
...@@ -85,8 +88,10 @@ Set_remove(Bucket *self, PyObject *args) ...@@ -85,8 +88,10 @@ Set_remove(Bucket *self, PyObject *args)
{ {
PyObject *key; PyObject *key;
UNLESS (PyArg_ParseTuple(args, "O", &key)) return NULL; UNLESS (PyArg_ParseTuple(args, "O", &key))
if (_bucket_set(self, key, NULL, 0, 1, 0) < 0) return NULL; return NULL;
if (_bucket_set(self, key, NULL, 0, 1, 0) < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
...@@ -109,7 +114,8 @@ _set_setstate(Bucket *self, PyObject *args) ...@@ -109,7 +114,8 @@ _set_setstate(Bucket *self, PyObject *args)
return -1; return -1;
} }
if ((l=PyTuple_Size(items)) < 0) return -1; if ((l=PyTuple_Size(items)) < 0)
return -1;
for (i=self->len; --i >= 0; ) for (i=self->len; --i >= 0; )
{ {
...@@ -125,7 +131,8 @@ _set_setstate(Bucket *self, PyObject *args) ...@@ -125,7 +131,8 @@ _set_setstate(Bucket *self, PyObject *args)
if (l > self->size) if (l > self->size)
{ {
UNLESS (keys=BTree_Realloc(self->keys, sizeof(KEY_TYPE)*l)) return -1; UNLESS (keys=BTree_Realloc(self->keys, sizeof(KEY_TYPE)*l))
return -1;
self->keys=keys; self->keys=keys;
self->size=l; self->size=l;
} }
...@@ -134,7 +141,8 @@ _set_setstate(Bucket *self, PyObject *args) ...@@ -134,7 +141,8 @@ _set_setstate(Bucket *self, PyObject *args)
{ {
k=PyTuple_GET_ITEM(items, i); k=PyTuple_GET_ITEM(items, i);
COPY_KEY_FROM_ARG(self->keys[i], k, copied); COPY_KEY_FROM_ARG(self->keys[i], k, copied);
UNLESS (copied) return -1; UNLESS (copied)
return -1;
INCREF_KEY(self->keys[i]); INCREF_KEY(self->keys[i]);
} }
...@@ -154,13 +162,15 @@ set_setstate(Bucket *self, PyObject *args) ...@@ -154,13 +162,15 @@ set_setstate(Bucket *self, PyObject *args)
{ {
int r; int r;
UNLESS (PyArg_ParseTuple(args, "O", &args)) return NULL; UNLESS (PyArg_ParseTuple(args, "O", &args))
return NULL;
PER_PREVENT_DEACTIVATION(self); PER_PREVENT_DEACTIVATION(self);
r=_set_setstate(self, args); r=_set_setstate(self, args);
PER_UNUSE(self); PER_UNUSE(self);
if (r < 0) return NULL; if (r < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -172,7 +182,7 @@ static struct PyMethodDef Set_methods[] = { ...@@ -172,7 +182,7 @@ static struct PyMethodDef Set_methods[] = {
{"__setstate__", (PyCFunction) set_setstate, METH_VARARGS, {"__setstate__", (PyCFunction) set_setstate, METH_VARARGS,
"__setstate__() -- Set the state of the object"}, "__setstate__() -- Set the state of the object"},
{"keys", (PyCFunction) bucket_keys, METH_KEYWORDS, {"keys", (PyCFunction) bucket_keys, METH_VARARGS | METH_KEYWORDS,
"keys() -- Return the keys"}, "keys() -- Return the keys"},
{"has_key", (PyCFunction) bucket_has_key, METH_O, {"has_key", (PyCFunction) bucket_has_key, METH_O,
...@@ -190,10 +200,12 @@ static struct PyMethodDef Set_methods[] = { ...@@ -190,10 +200,12 @@ static struct PyMethodDef Set_methods[] = {
"If an argument is given, find the minimum >= the argument"}, "If an argument is given, find the minimum >= the argument"},
#ifdef PERSISTENT #ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) bucket__p_resolveConflict, METH_VARARGS, {"_p_resolveConflict",
(PyCFunction) bucket__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"}, "_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) bucket__p_deactivate, METH_KEYWORDS, {"_p_deactivate",
(PyCFunction) bucket__p_deactivate, METH_VARARGS | METH_KEYWORDS,
"_p_deactivate() -- Reinitialize from a newly created copy"}, "_p_deactivate() -- Reinitialize from a newly created copy"},
#endif #endif
...@@ -235,12 +247,14 @@ set_repr(Bucket *self) ...@@ -235,12 +247,14 @@ set_repr(Bucket *self)
PyObject *r, *t; PyObject *r, *t;
if (!format) if (!format)
format = PyString_FromString(MOD_NAME_PREFIX "Set(%s)"); format = TEXT_FROM_STRING(MOD_NAME_PREFIX "Set(%s)");
UNLESS (t = PyTuple_New(1)) return NULL; UNLESS (t = PyTuple_New(1))
UNLESS (r = bucket_keys(self, NULL, NULL)) goto err; return NULL;
UNLESS (r = bucket_keys(self, NULL, NULL))
goto err;
PyTuple_SET_ITEM(t, 0, r); PyTuple_SET_ITEM(t, 0, r);
r = t; r = t;
ASSIGN(r, PyString_Format(format, r)); ASSIGN(r, TEXT_FORMAT(format, r));
return r; return r;
err: err:
Py_DECREF(t); Py_DECREF(t);
...@@ -291,8 +305,7 @@ static PySequenceMethods set_as_sequence = { ...@@ -291,8 +305,7 @@ static PySequenceMethods set_as_sequence = {
}; };
static PyTypeObject SetType = { static PyTypeObject SetType = {
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ PyVarObject_HEAD_INIT(NULL, 0) /* PyPersist_Type */
0, /* ob_size */
MODULE_NAME MOD_NAME_PREFIX "Set", /* tp_name */ MODULE_NAME MOD_NAME_PREFIX "Set", /* tp_name */
sizeof(Bucket), /* tp_basicsize */ sizeof(Bucket), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
...@@ -311,7 +324,8 @@ static PyTypeObject SetType = { ...@@ -311,7 +324,8 @@ static PyTypeObject SetType = {
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)bucket_traverse, /* tp_traverse */ (traverseproc)bucket_traverse, /* tp_traverse */
...@@ -339,7 +353,8 @@ nextSet(SetIteration *i) ...@@ -339,7 +353,8 @@ nextSet(SetIteration *i)
if (i->position >= 0) if (i->position >= 0)
{ {
UNLESS(PER_USE(BUCKET(i->set))) return -1; UNLESS(PER_USE(BUCKET(i->set)))
return -1;
if (i->position) if (i->position)
{ {
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE FOR A PARTICULAR PURPOSE
****************************************************************************/ ****************************************************************************/
#include "_compat.h"
#define TREESETTEMPLATE_C "$Id$\n" #define TREESETTEMPLATE_C "$Id$\n"
...@@ -25,7 +26,7 @@ TreeSet_insert(BTree *self, PyObject *args) ...@@ -25,7 +26,7 @@ TreeSet_insert(BTree *self, PyObject *args)
i = _BTree_set(self, key, Py_None, 1, 1); i = _BTree_set(self, key, Py_None, 1, 1);
if (i < 0) if (i < 0)
return NULL; return NULL;
return PyInt_FromLong(i); return INT_FROM_LONG(i);
} }
/* _Set_update and _TreeSet_update are identical except for the /* _Set_update and _TreeSet_update are identical except for the
...@@ -42,9 +43,11 @@ _TreeSet_update(BTree *self, PyObject *seq) ...@@ -42,9 +43,11 @@ _TreeSet_update(BTree *self, PyObject *seq)
if (iter == NULL) if (iter == NULL)
return -1; return -1;
while (1) { while (1)
{
v = PyIter_Next(iter); v = PyIter_Next(iter);
if (v == NULL) { if (v == NULL)
{
if (PyErr_Occurred()) if (PyErr_Occurred())
goto err; goto err;
else else
...@@ -58,7 +61,7 @@ _TreeSet_update(BTree *self, PyObject *seq) ...@@ -58,7 +61,7 @@ _TreeSet_update(BTree *self, PyObject *seq)
n += ind; n += ind;
} }
err: err:
Py_DECREF(iter); Py_DECREF(iter);
if (ind < 0) if (ind < 0)
return -1; return -1;
...@@ -74,13 +77,14 @@ TreeSet_update(BTree *self, PyObject *args) ...@@ -74,13 +77,14 @@ TreeSet_update(BTree *self, PyObject *args)
if (!PyArg_ParseTuple(args, "|O:update", &seq)) if (!PyArg_ParseTuple(args, "|O:update", &seq))
return NULL; return NULL;
if (seq) { if (seq)
{
n = _TreeSet_update(self, seq); n = _TreeSet_update(self, seq);
if (n < 0) if (n < 0)
return NULL; return NULL;
} }
return PyInt_FromLong(n); return INT_FROM_LONG(n);
} }
...@@ -89,8 +93,10 @@ TreeSet_remove(BTree *self, PyObject *args) ...@@ -89,8 +93,10 @@ TreeSet_remove(BTree *self, PyObject *args)
{ {
PyObject *key; PyObject *key;
UNLESS (PyArg_ParseTuple(args, "O", &key)) return NULL; UNLESS (PyArg_ParseTuple(args, "O", &key))
if (_BTree_set(self, key, NULL, 0, 1) < 0) return NULL; return NULL;
if (_BTree_set(self, key, NULL, 0, 1) < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -100,18 +106,21 @@ TreeSet_setstate(BTree *self, PyObject *args) ...@@ -100,18 +106,21 @@ TreeSet_setstate(BTree *self, PyObject *args)
{ {
int r; int r;
if (!PyArg_ParseTuple(args,"O",&args)) return NULL; if (!PyArg_ParseTuple(args,"O",&args))
return NULL;
PER_PREVENT_DEACTIVATION(self); PER_PREVENT_DEACTIVATION(self);
r=_BTree_setstate(self, args, 1); r=_BTree_setstate(self, args, 1);
PER_UNUSE(self); PER_UNUSE(self);
if (r < 0) return NULL; if (r < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static struct PyMethodDef TreeSet_methods[] = { static struct PyMethodDef TreeSet_methods[] =
{
{"__getstate__", (PyCFunction) BTree_getstate, METH_NOARGS, {"__getstate__", (PyCFunction) BTree_getstate, METH_NOARGS,
"__getstate__() -> state\n\n" "__getstate__() -> state\n\n"
"Return the picklable state of the TreeSet."}, "Return the picklable state of the TreeSet."},
...@@ -124,7 +133,7 @@ static struct PyMethodDef TreeSet_methods[] = { ...@@ -124,7 +133,7 @@ static struct PyMethodDef TreeSet_methods[] = {
"has_key(key)\n\n" "has_key(key)\n\n"
"Return true if the TreeSet contains the given key."}, "Return true if the TreeSet contains the given key."},
{"keys", (PyCFunction) BTree_keys, METH_KEYWORDS, {"keys", (PyCFunction) BTree_keys, METH_VARARGS | METH_KEYWORDS,
"keys([min, max]) -> list of keys\n\n" "keys([min, max]) -> list of keys\n\n"
"Returns the keys of the TreeSet. If min and max are supplied, only\n" "Returns the keys of the TreeSet. If min and max are supplied, only\n"
"keys greater than min and less than max are returned."}, "keys greater than min and less than max are returned."},
...@@ -158,10 +167,12 @@ static struct PyMethodDef TreeSet_methods[] = { ...@@ -158,10 +167,12 @@ static struct PyMethodDef TreeSet_methods[] = {
"Perform sanity check on TreeSet, and raise exception if flawed."}, "Perform sanity check on TreeSet, and raise exception if flawed."},
#ifdef PERSISTENT #ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) BTree__p_resolveConflict, METH_VARARGS, {"_p_resolveConflict",
(PyCFunction) BTree__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"}, "_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) BTree__p_deactivate, METH_KEYWORDS, {"_p_deactivate",
(PyCFunction) BTree__p_deactivate, METH_VARARGS | METH_KEYWORDS,
"_p_deactivate()\n\nReinitialize from a newly created copy."}, "_p_deactivate()\n\nReinitialize from a newly created copy."},
#endif #endif
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
...@@ -198,10 +209,10 @@ TreeSet_init(PyObject *self, PyObject *args, PyObject *kwds) ...@@ -198,10 +209,10 @@ TreeSet_init(PyObject *self, PyObject *args, PyObject *kwds)
return 0; return 0;
} }
static PyTypeObject TreeSetType = { static PyTypeObject TreeSetType =
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */ {
0, /* ob_size */ PyVarObject_HEAD_INIT(NULL, 0)
MODULE_NAME MOD_NAME_PREFIX "TreeSet",/* tp_name */ MODULE_NAME MOD_NAME_PREFIX "TreeSet", /* tp_name */
sizeof(BTree), /* tp_basicsize */ sizeof(BTree), /* tp_basicsize */
0, /* tp_itemsize */ 0, /* tp_itemsize */
(destructor)BTree_dealloc, /* tp_dealloc */ (destructor)BTree_dealloc, /* tp_dealloc */
...@@ -219,7 +230,8 @@ static PyTypeObject TreeSetType = { ...@@ -219,7 +230,8 @@ static PyTypeObject TreeSetType = {
0, /* tp_getattro */ 0, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */ Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */ 0, /* tp_doc */
(traverseproc)BTree_traverse, /* tp_traverse */ (traverseproc)BTree_traverse, /* tp_traverse */
......
...@@ -25,10 +25,17 @@ ...@@ -25,10 +25,17 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "IF" #define MOD_NAME_PREFIX "IF"
#define INITMODULE init_IFBTree
#define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BUCKET_SIZE 120
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "floatvaluemacros.h" #include "floatvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__IFBTree
#else
#define INITMODULE init_IFBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -25,10 +25,17 @@ ...@@ -25,10 +25,17 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "II" #define MOD_NAME_PREFIX "II"
#define INITMODULE init_IIBTree
#define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BUCKET_SIZE 120
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "intvaluemacros.h" #include "intvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__IIBTree
#else
#define INITMODULE init_IIBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -23,10 +23,17 @@ ...@@ -23,10 +23,17 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "IO" #define MOD_NAME_PREFIX "IO"
#define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BUCKET_SIZE 60
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#define INITMODULE init_IOBTree
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "objectvaluemacros.h" #include "objectvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__IOBTree
#else
#define INITMODULE init_IOBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -25,12 +25,19 @@ ...@@ -25,12 +25,19 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "LF" #define MOD_NAME_PREFIX "LF"
#define INITMODULE init_LFBTree
#define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BUCKET_SIZE 120
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#define ZODB_64BIT_INTS #define ZODB_64BIT_INTS
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "floatvaluemacros.h" #include "floatvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__LFBTree
#else
#define INITMODULE init_LFBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -25,12 +25,19 @@ ...@@ -25,12 +25,19 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "LL" #define MOD_NAME_PREFIX "LL"
#define INITMODULE init_LLBTree
#define DEFAULT_MAX_BUCKET_SIZE 120 #define DEFAULT_MAX_BUCKET_SIZE 120
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#define ZODB_64BIT_INTS #define ZODB_64BIT_INTS
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "intvaluemacros.h" #include "intvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__LLBTree
#else
#define INITMODULE init_LLBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -23,12 +23,19 @@ ...@@ -23,12 +23,19 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "LO" #define MOD_NAME_PREFIX "LO"
#define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BUCKET_SIZE 60
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#define INITMODULE init_LOBTree
#define ZODB_64BIT_INTS #define ZODB_64BIT_INTS
#include "_compat.h"
#include "intkeymacros.h" #include "intkeymacros.h"
#include "objectvaluemacros.h" #include "objectvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__LOBTree
#else
#define INITMODULE init_LOBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -23,10 +23,17 @@ ...@@ -23,10 +23,17 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "OI" #define MOD_NAME_PREFIX "OI"
#define INITMODULE init_OIBTree
#define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BUCKET_SIZE 60
#define DEFAULT_MAX_BTREE_SIZE 250 #define DEFAULT_MAX_BTREE_SIZE 250
#include "_compat.h"
#include "objectkeymacros.h" #include "objectkeymacros.h"
#include "intvaluemacros.h" #include "intvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__OIBTree
#else
#define INITMODULE init_OIBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -23,12 +23,19 @@ ...@@ -23,12 +23,19 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "OL" #define MOD_NAME_PREFIX "OL"
#define INITMODULE init_OLBTree
#define DEFAULT_MAX_BUCKET_SIZE 60 #define DEFAULT_MAX_BUCKET_SIZE 60
#define DEFAULT_MAX_BTREE_SIZE 250 #define DEFAULT_MAX_BTREE_SIZE 250
#define ZODB_64BIT_INTS #define ZODB_64BIT_INTS
#include "_compat.h"
#include "objectkeymacros.h" #include "objectkeymacros.h"
#include "intvaluemacros.h" #include "intvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__OLBTree
#else
#define INITMODULE init_OLBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -23,10 +23,17 @@ ...@@ -23,10 +23,17 @@
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "OO" #define MOD_NAME_PREFIX "OO"
#define INITMODULE init_OOBTree
#define DEFAULT_MAX_BUCKET_SIZE 30 #define DEFAULT_MAX_BUCKET_SIZE 30
#define DEFAULT_MAX_BTREE_SIZE 250 #define DEFAULT_MAX_BTREE_SIZE 250
#include "_compat.h"
#include "objectkeymacros.h" #include "objectkeymacros.h"
#include "objectvaluemacros.h" #include "objectvaluemacros.h"
#ifdef PY3K
#define INITMODULE PyInit__OOBTree
#else
#define INITMODULE init_OOBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
...@@ -21,6 +21,10 @@ from struct import error as struct_error ...@@ -21,6 +21,10 @@ from struct import error as struct_error
from persistent import Persistent from persistent import Persistent
from .Interfaces import BTreesConflictError from .Interfaces import BTreesConflictError
from ._compat import PY3
from ._compat import cmp
from ._compat import int_types
from ._compat import xrange
_marker = object() _marker = object()
...@@ -156,7 +160,7 @@ class _SetIteration(object): ...@@ -156,7 +160,7 @@ class _SetIteration(object):
__slots__ = ('to_iterate', __slots__ = ('to_iterate',
'useValues', 'useValues',
'_next', '_iter',
'active', 'active',
'position', 'position',
'key', 'key',
...@@ -172,6 +176,9 @@ class _SetIteration(object): ...@@ -172,6 +176,9 @@ class _SetIteration(object):
try: try:
itmeth = to_iterate.iteritems itmeth = to_iterate.iteritems
except AttributeError: except AttributeError:
if PY3 and isinstance(to_iterate, dict): #pragma NO COVER Py3k
itmeth = to_iterate.items().__iter__
else:
itmeth = to_iterate.__iter__ itmeth = to_iterate.__iter__
useValues = False useValues = False
else: else:
...@@ -180,7 +187,7 @@ class _SetIteration(object): ...@@ -180,7 +187,7 @@ class _SetIteration(object):
itmeth = to_iterate.__iter__ itmeth = to_iterate.__iter__
self.useValues = useValues self.useValues = useValues
self._next = itmeth().next self._iter = itmeth()
self.active = True self.active = True
self.position = 0 self.position = 0
self.key = _marker self.key = _marker
...@@ -190,9 +197,9 @@ class _SetIteration(object): ...@@ -190,9 +197,9 @@ class _SetIteration(object):
def advance(self): def advance(self):
try: try:
if self.useValues: if self.useValues:
self.key, self.value = self._next() self.key, self.value = next(self._iter)
else: else:
self.key = self._next() self.key = next(self._iter)
self.position += 1 self.position += 1
except StopIteration: except StopIteration:
self.active = False self.active = False
...@@ -200,6 +207,15 @@ class _SetIteration(object): ...@@ -200,6 +207,15 @@ class _SetIteration(object):
return self return self
def _no_default_comparison(key):
# Enforce test that key has non-default comparison.
lt = getattr(key, '__lt__', None)
if lt is not None:
if getattr(lt, '__objclass__', None) is object: #pragma NO COVER Py3k
lt = None
if (lt is None and
getattr(key, '__cmp__', None) is None):
raise TypeError("Can't use default __cmp__")
class Bucket(_BucketBase): class Bucket(_BucketBase):
...@@ -237,10 +253,7 @@ class Bucket(_BucketBase): ...@@ -237,10 +253,7 @@ class Bucket(_BucketBase):
raise TypeError('items must be a sequence of 2-tuples') raise TypeError('items must be a sequence of 2-tuples')
def __setitem__(self, key, value): def __setitem__(self, key, value):
# Enforce test that key has non-default comparison. _no_default_comparison(key)
if ( getattr(key, '__lt__', None) is None and
getattr(key, '__cmp__', None) is None):
raise TypeError("Can't use default __cmp__")
self._set(self._to_key(key), self._to_value(value)) self._set(self._to_key(key), self._to_value(value))
def __delitem__(self, key): def __delitem__(self, key):
...@@ -298,7 +311,7 @@ class Bucket(_BucketBase): ...@@ -298,7 +311,7 @@ class Bucket(_BucketBase):
def _split(self, index=-1): def _split(self, index=-1):
if index < 0 or index >= len(self._keys): if index < 0 or index >= len(self._keys):
index = len(self._keys) / 2 index = len(self._keys) // 2
new_instance = self.__class__() new_instance = self.__class__()
new_instance._keys = self._keys[index:] new_instance._keys = self._keys[index:]
new_instance._values = self._values[index:] new_instance._values = self._values[index:]
...@@ -553,7 +566,7 @@ class Set(_BucketBase): ...@@ -553,7 +566,7 @@ class Set(_BucketBase):
def _split(self, index=-1): def _split(self, index=-1):
if index < 0 or index >= len(self._keys): if index < 0 or index >= len(self._keys):
index = len(self._keys) / 2 index = len(self._keys) // 2
new_instance = self.__class__() new_instance = self.__class__()
new_instance._keys = self._keys[index:] new_instance._keys = self._keys[index:]
del self._keys[index:] del self._keys[index:]
...@@ -727,10 +740,7 @@ class _Tree(_Base): ...@@ -727,10 +740,7 @@ class _Tree(_Base):
set(*i) set(*i)
def __setitem__(self, key, value): def __setitem__(self, key, value):
# Enforce test that key has non-default comparison. _no_default_comparison(key)
if ( getattr(key, '__lt__', None) is None and
getattr(key, '__cmp__', None) is None):
raise TypeError("Can't use default __cmp__")
self._set(self._to_key(key), self._to_value(value)) self._set(self._to_key(key), self._to_value(value))
def __delitem__(self, key): def __delitem__(self, key):
...@@ -742,6 +752,7 @@ class _Tree(_Base): ...@@ -742,6 +752,7 @@ class _Tree(_Base):
def __nonzero__(self): def __nonzero__(self):
return bool(self._data) return bool(self._data)
__bool__ = __nonzero__ #Py3k rename
def __len__(self): def __len__(self):
l = 0 l = 0
...@@ -760,7 +771,7 @@ class _Tree(_Base): ...@@ -760,7 +771,7 @@ class _Tree(_Base):
if data: if data:
lo = 0 lo = 0
hi = len(data) hi = len(data)
i = hi//2 i = hi // 2
while i > lo: while i > lo:
cmp_ = cmp(data[i].key, key) cmp_ = cmp(data[i].key, key)
if cmp_ < 0: if cmp_ < 0:
...@@ -769,7 +780,7 @@ class _Tree(_Base): ...@@ -769,7 +780,7 @@ class _Tree(_Base):
hi = i hi = i
else: else:
break break
i = (lo+hi)//2 i = (lo + hi) // 2
return i return i
return -1 return -1
...@@ -882,7 +893,7 @@ class _Tree(_Base): ...@@ -882,7 +893,7 @@ class _Tree(_Base):
def _split(self, index=None): def _split(self, index=None):
data = self._data data = self._data
if index is None: if index is None:
index = len(data)//2 index = len(data) // 2
next = self.__class__() next = self.__class__()
next._data = data[index:] next._data = data[index:]
...@@ -1083,7 +1094,7 @@ class _TreeItems(object): ...@@ -1083,7 +1094,7 @@ class _TreeItems(object):
while i > self.index: while i > self.index:
try: try:
self.v = self.it.next() self.v = next(self.it)
except StopIteration: except StopIteration:
raise IndexError(i) raise IndexError(i)
else: else:
...@@ -1158,7 +1169,6 @@ class TreeSet(_Tree): ...@@ -1158,7 +1169,6 @@ class TreeSet(_Tree):
__slots__ = () __slots__ = ()
#_next = None
def add(self, key): def add(self, key):
return self._set(self._to_key(key))[0] return self._set(self._to_key(key))[0]
...@@ -1270,6 +1280,14 @@ def intersection(set_type, o1, o2): ...@@ -1270,6 +1280,14 @@ def intersection(set_type, o1, o2):
i2.advance() i2.advance()
return result return result
def _prepMergeIterators(o1, o2):
MERGE_DEFAULT = getattr(o1, 'MERGE_DEFAULT', None)
if MERGE_DEFAULT is None:
raise TypeError("invalid set operation")
i1 = _SetIteration(o1, True, MERGE_DEFAULT)
i2 = _SetIteration(o2, True, MERGE_DEFAULT)
return i1, i2
def weightedUnion(set_type, o1, o2, w1=1, w2=1): def weightedUnion(set_type, o1, o2, w1=1, w2=1):
if o1 is None: if o1 is None:
if o2 is None: if o2 is None:
...@@ -1277,9 +1295,7 @@ def weightedUnion(set_type, o1, o2, w1=1, w2=1): ...@@ -1277,9 +1295,7 @@ def weightedUnion(set_type, o1, o2, w1=1, w2=1):
return w2, o2 return w2, o2
if o2 is None: if o2 is None:
return w1, o1 return w1, o1
MERGE_DEFAULT = getattr(o1, 'MERGE_DEFAULT', None) i1, i2 = _prepMergeIterators(o1, o2)
i1 = _SetIteration(o1, True, MERGE_DEFAULT)
i2 = _SetIteration(o2, True, MERGE_DEFAULT)
MERGE = getattr(o1, 'MERGE', None) MERGE = getattr(o1, 'MERGE', None)
if MERGE is None and i1.useValues and i2.useValues: if MERGE is None and i1.useValues and i2.useValues:
raise TypeError("invalid set operation") raise TypeError("invalid set operation")
...@@ -1287,12 +1303,6 @@ def weightedUnion(set_type, o1, o2, w1=1, w2=1): ...@@ -1287,12 +1303,6 @@ def weightedUnion(set_type, o1, o2, w1=1, w2=1):
if (not i1.useValues) and i2.useValues: if (not i1.useValues) and i2.useValues:
i1, i2 = i2, i1 i1, i2 = i2, i1
w1, w2 = w2, w1 w1, w2 = w2, w1
if MERGE_DEFAULT is None:
if i1.useValues:
if (not i2.useValues):
raise TypeError("invalid set operation")
else:
raise TypeError("invalid set operation")
_merging = i1.useValues or i2.useValues _merging = i1.useValues or i2.useValues
if _merging: if _merging:
result = o1._mapping_type() result = o1._mapping_type()
...@@ -1333,22 +1343,13 @@ def weightedIntersection(set_type, o1, o2, w1=1, w2=1): ...@@ -1333,22 +1343,13 @@ def weightedIntersection(set_type, o1, o2, w1=1, w2=1):
return w2, o2 return w2, o2
if o2 is None: if o2 is None:
return w1, o1 return w1, o1
MERGE_DEFAULT = getattr(o1, 'MERGE_DEFAULT', None) i1, i2 = _prepMergeIterators(o1, o2)
i1 = _SetIteration(o1, True, MERGE_DEFAULT)
i2 = _SetIteration(o2, True, MERGE_DEFAULT)
MERGE = getattr(o1, 'MERGE', None) MERGE = getattr(o1, 'MERGE', None)
if MERGE is None and i1.useValues and i2.useValues: if MERGE is None and i1.useValues and i2.useValues:
raise TypeError("invalid set operation") raise TypeError("invalid set operation")
MERGE_WEIGHT = getattr(o1, 'MERGE_WEIGHT')
if (not i1.useValues) and i2.useValues: if (not i1.useValues) and i2.useValues:
i1, i2 = i2, i1 i1, i2 = i2, i1
w1, w2 = w2, w1 w1, w2 = w2, w1
if MERGE_DEFAULT is None:
if i1.useValues:
if (not i2.useValues):
raise TypeError("invalid set operation")
else:
raise TypeError("invalid set operation")
_merging = i1.useValues or i2.useValues _merging = i1.useValues or i2.useValues
if _merging: if _merging:
result = o1._mapping_type() result = o1._mapping_type()
...@@ -1384,7 +1385,6 @@ def multiunion(set_type, seqs): ...@@ -1384,7 +1385,6 @@ def multiunion(set_type, seqs):
def to_ob(self, v): def to_ob(self, v):
return v return v
int_types = int, long
def to_int(self, v): def to_int(self, v):
try: try:
# XXX Python 2.6 doesn't truncate, it spews a warning. # XXX Python 2.6 doesn't truncate, it spews a warning.
...@@ -1420,10 +1420,10 @@ def to_long(self, v): ...@@ -1420,10 +1420,10 @@ def to_long(self, v):
return int(v) return int(v)
def to_str(l): def to_bytes(l):
def to(self, v): def to(self, v):
if not (isinstance(v, str) and len(v) == l): if not (isinstance(v, bytes) and len(v) == l):
raise TypeError("%s-character string expected" % l) raise TypeError("%s-byte array expected" % l)
return v return v
return to return to
......
/* Straddle Python 2 / 3 */
#ifndef BTREES__COMPAT_H
#define BTREES__COMPAT_H
#include "Python.h"
#ifdef INTERN
#undef INTERN
#endif
#ifdef INT_FROM_LONG
#undef INT_FROM_LONG
#endif
#ifdef INT_CHECK
#undef INT_CHECK
#endif
#if PY_MAJOR_VERSION >= 3
#define PY3K
#define INTERN PyUnicode_InternFromString
#define INT_FROM_LONG(x) PyLong_FromLong(x)
#define INT_CHECK(x) PyLong_Check(x)
#define INT_AS_LONG(x) PyLong_AS_LONG(x)
#define INT_GETMAX(x) 2<<31
#define TEXT_FROM_STRING PyUnicode_FromString
#define TEXT_FORMAT PyUnicode_Format
#define COMPARE(lhs, rhs) \
PyObject_RichCompareBool((lhs), (rhs), Py_LT) > 0 ? -1 : \
(PyObject_RichCompareBool((lhs), (rhs), Py_EQ) > 0 ? 0 : 1)
#else
#define INTERN PyString_InternFromString
#define INT_FROM_LONG(x) PyInt_FromLong(x)
#define INT_CHECK(x) PyInt_Check(x)
#define INT_AS_LONG(x) PyInt_AS_LONG(x)
#define INT_GETMAX(x) PyInt_GetMax(x)
#define TEXT_FROM_STRING PyString_FromString
#define TEXT_FORMAT PyString_Format
#define COMPARE(lhs, rhs) PyObject_Compare((lhs), (rhs))
#endif
#endif /* BTREES__COMPAT_H */
##############################################################################
#
# Copyright (c) 2001-2012 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
#
##############################################################################
import sys
if sys.version_info[0] < 3: #pragma NO COVER Python2
PY2 = True
PY3 = False
from StringIO import StringIO
BytesIO = StringIO
int_types = int, long
xrange = xrange
cmp = cmp
_bytes = str
def _ascii(x):
return bytes(x)
def _u(s, encoding='unicode_escape'):
return unicode(s, encoding)
else: #pragma NO COVER Python3
PY2 = False
PY3 = True
from io import StringIO
from io import BytesIO
int_types = int,
xrange = range
def cmp(x, y):
return (x > y) - (y > x)
_bytes = bytes
def _ascii(x):
return bytes(x, 'ascii')
def _u(s, encoding=None):
if encoding is None:
return s
return str(s, encoding)
...@@ -31,23 +31,24 @@ typedef unsigned char char6[6]; ...@@ -31,23 +31,24 @@ typedef unsigned char char6[6];
#define PERSISTENT #define PERSISTENT
#define MOD_NAME_PREFIX "fs" #define MOD_NAME_PREFIX "fs"
#define INITMODULE init_fsBTree
#define DEFAULT_MAX_BUCKET_SIZE 500 #define DEFAULT_MAX_BUCKET_SIZE 500
#define DEFAULT_MAX_BTREE_SIZE 500 #define DEFAULT_MAX_BTREE_SIZE 500
#include "_compat.h"
/*#include "intkeymacros.h"*/ /*#include "intkeymacros.h"*/
#define KEYMACROS_H "$Id$\n" #define KEYMACROS_H "$Id$\n"
#define KEY_TYPE char2 #define KEY_TYPE char2
#undef KEY_TYPE_IS_PYOBJECT #undef KEY_TYPE_IS_PYOBJECT
#define KEY_CHECK(K) (PyString_Check(K) && PyString_GET_SIZE(K)==2) #define KEY_CHECK(K) (PyBytes_Check(K) && PyBytes_GET_SIZE(K)==2)
#define TEST_KEY_SET_OR(V, K, T) if ( ( (V) = ((*(K) < *(T) || (*(K) == *(T) && (K)[1] < (T)[1])) ? -1 : ((*(K) == *(T) && (K)[1] == (T)[1]) ? 0 : 1)) ), 0 ) #define TEST_KEY_SET_OR(V, K, T) if ( ( (V) = ((*(K) < *(T) || (*(K) == *(T) && (K)[1] < (T)[1])) ? -1 : ((*(K) == *(T) && (K)[1] == (T)[1]) ? 0 : 1)) ), 0 )
#define DECREF_KEY(KEY) #define DECREF_KEY(KEY)
#define INCREF_KEY(k) #define INCREF_KEY(k)
#define COPY_KEY(KEY, E) (*(KEY)=*(E), (KEY)[1]=(E)[1]) #define COPY_KEY(KEY, E) (*(KEY)=*(E), (KEY)[1]=(E)[1])
#define COPY_KEY_TO_OBJECT(O, K) O=PyString_FromStringAndSize((const char*)K,2) #define COPY_KEY_TO_OBJECT(O, K) O=PyBytes_FromStringAndSize((const char*)K,2)
#define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \
if (KEY_CHECK(ARG)) memcpy(TARGET, PyString_AS_STRING(ARG), 2); else { \ if (KEY_CHECK(ARG)) memcpy(TARGET, PyBytes_AS_STRING(ARG), 2); else { \
PyErr_SetString(PyExc_TypeError, "expected two-character string key"); \ PyErr_SetString(PyExc_TypeError, "expected two-character string key"); \
(STATUS)=0; } (STATUS)=0; }
...@@ -59,10 +60,10 @@ typedef unsigned char char6[6]; ...@@ -59,10 +60,10 @@ typedef unsigned char char6[6];
#define DECREF_VALUE(k) #define DECREF_VALUE(k)
#define INCREF_VALUE(k) #define INCREF_VALUE(k)
#define COPY_VALUE(V, E) (memcpy(V, E, 6)) #define COPY_VALUE(V, E) (memcpy(V, E, 6))
#define COPY_VALUE_TO_OBJECT(O, K) O=PyString_FromStringAndSize((const char*)K,6) #define COPY_VALUE_TO_OBJECT(O, K) O=PyBytes_FromStringAndSize((const char*)K,6)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
if ((PyString_Check(ARG) && PyString_GET_SIZE(ARG)==6)) \ if ((PyBytes_Check(ARG) && PyBytes_GET_SIZE(ARG)==6)) \
memcpy(TARGET, PyString_AS_STRING(ARG), 6); else { \ memcpy(TARGET, PyBytes_AS_STRING(ARG), 6); else { \
PyErr_SetString(PyExc_TypeError, "expected six-character string key"); \ PyErr_SetString(PyExc_TypeError, "expected six-character string key"); \
(STATUS)=0; } (STATUS)=0; }
...@@ -70,20 +71,29 @@ typedef unsigned char char6[6]; ...@@ -70,20 +71,29 @@ typedef unsigned char char6[6];
#include "Python.h" #include "Python.h"
static PyObject *bucket_toString(PyObject *self); static PyObject *bucket_toBytes(PyObject *self);
static PyObject *bucket_fromString(PyObject *self, PyObject *state); static PyObject *bucket_fromBytes(PyObject *self, PyObject *state);
#define EXTRA_BUCKET_METHODS \ #define EXTRA_BUCKET_METHODS \
{"toString", (PyCFunction) bucket_toString, METH_NOARGS, \ {"toBytes", (PyCFunction) bucket_toBytes, METH_NOARGS, \
"toString() -- Return the state as a string"}, \ "toBytes() -- Return the state as a bytes array"}, \
{"fromString", (PyCFunction) bucket_fromString, METH_O, \ {"fromBytes", (PyCFunction) bucket_fromBytes, METH_O, \
"fromString(s) -- Set the state of the object from a string"}, \ "fromSBytes(s) -- Set the state of the object from a bytes array"}, \
{"toString", (PyCFunction) bucket_toBytes, METH_NOARGS, \
"toString() -- Deprecated alias for 'toBytes'"}, \
{"fromString", (PyCFunction) bucket_fromBytes, METH_O, \
"fromString(s) -- Deprecated alias for 'fromBytes'"}, \
#ifdef PY3K
#define INITMODULE PyInit__fsBTree
#else
#define INITMODULE init_fsBTree
#endif
#include "BTreeModuleTemplate.c" #include "BTreeModuleTemplate.c"
static PyObject * static PyObject *
bucket_toString(PyObject *oself) bucket_toBytes(PyObject *oself)
{ {
Bucket *self = (Bucket *)oself; Bucket *self = (Bucket *)oself;
PyObject *items = NULL; PyObject *items = NULL;
...@@ -93,11 +103,11 @@ bucket_toString(PyObject *oself) ...@@ -93,11 +103,11 @@ bucket_toString(PyObject *oself)
len = self->len; len = self->len;
items = PyString_FromStringAndSize(NULL, len*8); items = PyBytes_FromStringAndSize(NULL, len*8);
if (items == NULL) if (items == NULL)
goto err; goto err;
memcpy(PyString_AS_STRING(items), self->keys, len*2); memcpy(PyBytes_AS_STRING(items), self->keys, len*2);
memcpy(PyString_AS_STRING(items)+len*2, self->values, len*6); memcpy(PyBytes_AS_STRING(items)+len*2, self->values, len*6);
PER_UNUSE(self); PER_UNUSE(self);
return items; return items;
...@@ -109,14 +119,14 @@ bucket_toString(PyObject *oself) ...@@ -109,14 +119,14 @@ bucket_toString(PyObject *oself)
} }
static PyObject * static PyObject *
bucket_fromString(PyObject *oself, PyObject *state) bucket_fromBytes(PyObject *oself, PyObject *state)
{ {
Bucket *self = (Bucket *)oself; Bucket *self = (Bucket *)oself;
int len; int len;
KEY_TYPE *keys; KEY_TYPE *keys;
VALUE_TYPE *values; VALUE_TYPE *values;
len = PyString_Size(state); len = PyBytes_Size(state);
if (len < 0) if (len < 0)
return NULL; return NULL;
...@@ -144,8 +154,8 @@ bucket_fromString(PyObject *oself, PyObject *state) ...@@ -144,8 +154,8 @@ bucket_fromString(PyObject *oself, PyObject *state)
self->size = len; self->size = len;
} }
memcpy(self->keys, PyString_AS_STRING(state), len*2); memcpy(self->keys, PyBytes_AS_STRING(state), len*2);
memcpy(self->values, PyString_AS_STRING(state)+len*2, len*6); memcpy(self->values, PyBytes_AS_STRING(state)+len*2, len*6);
self->len = len; self->len = len;
......
...@@ -378,30 +378,30 @@ class Printer(Walker): #pragma NO COVER ...@@ -378,30 +378,30 @@ class Printer(Walker): #pragma NO COVER
def visit_btree(self, obj, path, parent, is_mapping, def visit_btree(self, obj, path, parent, is_mapping,
keys, kids, lo, hi): keys, kids, lo, hi):
indent = " " * len(path) indent = " " * len(path)
print "%s%s %s with %d children" % ( print("%s%s %s with %d children" % (
indent, indent,
".".join(map(str, path)), ".".join(map(str, path)),
type_and_adr(obj), type_and_adr(obj),
len(kids)) len(kids)))
indent += " " indent += " "
n = len(keys) n = len(keys)
for i in range(n): for i in range(n):
print "%skey %d: %r" % (indent, i, keys[i]) print("%skey %d: %r" % (indent, i, keys[i]))
def visit_bucket(self, obj, path, parent, is_mapping, def visit_bucket(self, obj, path, parent, is_mapping,
keys, values, lo, hi): keys, values, lo, hi):
indent = " " * len(path) indent = " " * len(path)
print "%s%s %s with %d keys" % ( print("%s%s %s with %d keys" % (
indent, indent,
".".join(map(str, path)), ".".join(map(str, path)),
type_and_adr(obj), type_and_adr(obj),
len(keys)) len(keys)))
indent += " " indent += " "
n = len(keys) n = len(keys)
for i in range(n): for i in range(n):
print "%skey %d: %r" % (indent, i, keys[i]), print("%skey %d: %r" % (indent, i, keys[i]),)
if is_mapping: if is_mapping:
print "value %r" % (values[i],) print("value %r" % (values[i],))
def check(btree): def check(btree):
"""Check internal value-based invariants in a BTree or TreeSet. """Check internal value-based invariants in a BTree or TreeSet.
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#define COPY_VALUE_TO_OBJECT(O, K) O=PyFloat_FromDouble(K) #define COPY_VALUE_TO_OBJECT(O, K) O=PyFloat_FromDouble(K)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
if (PyFloat_Check(ARG)) TARGET = (float)PyFloat_AsDouble(ARG); \ if (PyFloat_Check(ARG)) TARGET = (float)PyFloat_AsDouble(ARG); \
else if (PyInt_Check(ARG)) TARGET = (float)PyInt_AsLong(ARG); \ else if (INT_CHECK(ARG)) TARGET = (float)INT_AS_LONG(ARG); \
else { \ else { \
PyErr_SetString(PyExc_TypeError, "expected float or int value"); \ PyErr_SetString(PyExc_TypeError, "expected float or int value"); \
(STATUS)=0; (TARGET)=0; } (STATUS)=0; (TARGET)=0; }
......
...@@ -14,10 +14,11 @@ ...@@ -14,10 +14,11 @@
# fsBTrees are data structures used for ZODB FileStorage. They are not # fsBTrees are data structures used for ZODB FileStorage. They are not
# expected to be "public" excpect to FileStorage. # expected to be "public" excpect to FileStorage.
# Each item in an fsBTree maps a two-byte key to a six-byte value.
__all__ = ('Bucket', 'Set', 'BTree', 'TreeSet', __all__ = ('Bucket', 'Set', 'BTree', 'TreeSet',
'fsBucket', 'fsSet', 'fsBTree', 'fsTreeSet', 'fsBucket', 'fsSet', 'fsBTree', 'fsTreeSet',
'union', 'intersection', 'difference', 'multiunion', 'union', 'intersection', 'difference',
) )
...@@ -30,16 +31,15 @@ from ._base import Tree as BTree ...@@ -30,16 +31,15 @@ from ._base import Tree as BTree
from ._base import TreeSet from ._base import TreeSet
from ._base import difference as _difference from ._base import difference as _difference
from ._base import intersection as _intersection from ._base import intersection as _intersection
from ._base import multiunion as _multiunion
from ._base import set_operation as _set_operation from ._base import set_operation as _set_operation
from ._base import to_str as _to_str from ._base import to_bytes as _to_bytes
from ._base import union as _union from ._base import union as _union
_BUCKET_SIZE = 500 _BUCKET_SIZE = 500
_TREE_SIZE = 500 _TREE_SIZE = 500
using64bits = False using64bits = False
_to_key = _to_str(2) _to_key = _to_bytes(2)
_to_value = _to_str(6) _to_value = _to_bytes(6)
class fsBucketPy(Bucket): class fsBucketPy(Bucket):
...@@ -47,11 +47,8 @@ class fsBucketPy(Bucket): ...@@ -47,11 +47,8 @@ class fsBucketPy(Bucket):
_to_key = _to_key _to_key = _to_key
_to_value = _to_value _to_value = _to_value
def MERGE_WEIGHT(self, value, weight):
return value
def toString(self): def toString(self):
return ''.join(self._keys) + ''.join(self._values) return b''.join(self._keys) + b''.join(self._values)
def fromString(self, v): def fromString(self, v):
length = len(v) length = len(v)
...@@ -77,8 +74,6 @@ class fsBTreePy(BTree): ...@@ -77,8 +74,6 @@ class fsBTreePy(BTree):
MAX_SIZE = _TREE_SIZE MAX_SIZE = _TREE_SIZE
_to_key = _to_key _to_key = _to_key
_to_value = _to_value _to_value = _to_value
def MERGE_WEIGHT(self, value, weight):
return value
class fsTreeSetPy(TreeSet): class fsTreeSetPy(TreeSet):
...@@ -104,18 +99,10 @@ fsTreeSetPy._set_type = fsTreeSetPy._bucket_type = fsSetPy ...@@ -104,18 +99,10 @@ fsTreeSetPy._set_type = fsTreeSetPy._bucket_type = fsSetPy
differencePy = _set_operation(_difference, fsSetPy) differencePy = _set_operation(_difference, fsSetPy)
unionPy = _set_operation(_union, fsSetPy) unionPy = _set_operation(_union, fsSetPy)
intersectionPy = _set_operation(_intersection, fsSetPy) intersectionPy = _set_operation(_intersection, fsSetPy)
multiunionPy = _set_operation(_multiunion, fsSetPy)
try: try:
from _fsBTree import fsBucket from ._fsBTree import fsBucket
from _fsBTree import fsSet except ImportError: #pragma NO COVER w/ C extensions
from _fsBTree import fsBTree
from _fsBTree import fsTreeSet
from _fsBTree import difference
from _fsBTree import union
from _fsBTree import intersection
from _fsBTree import multiunion
except ImportError: #pragma NO COVER
fsBucket = fsBucketPy fsBucket = fsBucketPy
fsSet = fsSetPy fsSet = fsSetPy
fsBTree = fsBTreePy fsBTree = fsBTreePy
...@@ -123,7 +110,13 @@ except ImportError: #pragma NO COVER ...@@ -123,7 +110,13 @@ except ImportError: #pragma NO COVER
difference = differencePy difference = differencePy
union = unionPy union = unionPy
intersection = intersectionPy intersection = intersectionPy
multiunion = multiunionPy else: #pragma NO COVER w/o C extensions
from ._fsBTree import fsSet
from ._fsBTree import fsBTree
from ._fsBTree import fsTreeSet
from ._fsBTree import difference
from ._fsBTree import union
from ._fsBTree import intersection
Bucket = fsBucket Bucket = fsBucket
Set = fsSet Set = fsSet
......
...@@ -4,26 +4,23 @@ ...@@ -4,26 +4,23 @@
#ifdef ZODB_64BIT_INTS #ifdef ZODB_64BIT_INTS
/* PY_LONG_LONG as key */ /* PY_LONG_LONG as key */
#define NEED_LONG_LONG_SUPPORT #define NEED_LONG_LONG_SUPPORT
#define NEED_LONG_LONG_KEYS
#define KEY_TYPE PY_LONG_LONG #define KEY_TYPE PY_LONG_LONG
#define KEY_CHECK longlong_check #define KEY_CHECK longlong_check
#define COPY_KEY_TO_OBJECT(O, K) O=longlong_as_object(K) #define COPY_KEY_TO_OBJECT(O, K) O=longlong_as_object(K)
#define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \
if (PyInt_Check(ARG)) TARGET=PyInt_AS_LONG(ARG); else \ if (!longlong_convert((ARG), &TARGET)) \
if (longlong_check(ARG)) TARGET=PyLong_AsLongLong(ARG); else \ { \
if (PyLong_Check(ARG)) { \ (STATUS)=0; (TARGET)=0; \
PyErr_SetString(PyExc_ValueError, "long integer out of range"); \ }
(STATUS)=0; (TARGET)=0; } \
else { \
PyErr_SetString(PyExc_TypeError, "expected integer key"); \
(STATUS)=0; (TARGET)=0; }
#else #else
/* C int as key */ /* C int as key */
#define KEY_TYPE int #define KEY_TYPE int
#define KEY_CHECK PyInt_Check #define KEY_CHECK INT_CHECK
#define COPY_KEY_TO_OBJECT(O, K) O=PyInt_FromLong(K) #define COPY_KEY_TO_OBJECT(O, K) O=INT_FROM_LONG(K)
#define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \
if (PyInt_Check(ARG)) { \ if (INT_CHECK(ARG)) { \
long vcopy = PyInt_AS_LONG(ARG); \ long vcopy = INT_AS_LONG(ARG); \
if ((int)vcopy != vcopy) { \ if ((int)vcopy != vcopy) { \
PyErr_SetString(PyExc_TypeError, "integer out of range"); \ PyErr_SetString(PyExc_TypeError, "integer out of range"); \
(STATUS)=0; (TARGET)=0; \ (STATUS)=0; (TARGET)=0; \
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#define VALUE_PARSE "L" #define VALUE_PARSE "L"
#define COPY_VALUE_TO_OBJECT(O, K) O=longlong_as_object(K) #define COPY_VALUE_TO_OBJECT(O, K) O=longlong_as_object(K)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
if (PyInt_Check(ARG)) TARGET=PyInt_AS_LONG(ARG); else \ if (INT_CHECK(ARG)) TARGET=INT_AS_LONG(ARG); else \
if (longlong_check(ARG)) TARGET=PyLong_AsLongLong(ARG); else \ if (longlong_check(ARG)) TARGET=PyLong_AsLongLong(ARG); else \
if (PyLong_Check(ARG)) { \ if (PyLong_Check(ARG)) { \
PyErr_SetString(PyExc_ValueError, "long integer out of range"); \ PyErr_SetString(PyExc_ValueError, "long integer out of range"); \
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#else #else
#define VALUE_TYPE int #define VALUE_TYPE int
#define VALUE_PARSE "i" #define VALUE_PARSE "i"
#define COPY_VALUE_TO_OBJECT(O, K) O=PyInt_FromLong(K) #define COPY_VALUE_TO_OBJECT(O, K) O=INT_FROM_LONG(K)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \ #define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
if (PyInt_Check(ARG)) { \ if (INT_CHECK(ARG)) { \
long vcopy = PyInt_AS_LONG(ARG); \ long vcopy = INT_AS_LONG(ARG); \
if ((int)vcopy != vcopy) { \ if ((int)vcopy != vcopy) { \
PyErr_SetString(PyExc_TypeError, "integer out of range"); \ PyErr_SetString(PyExc_TypeError, "integer out of range"); \
(STATUS)=0; (TARGET)=0; \ (STATUS)=0; (TARGET)=0; \
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
#define KEY_TYPE_IS_PYOBJECT #define KEY_TYPE_IS_PYOBJECT
#include "Python.h" #include "Python.h"
#include "_compat.h"
static PyObject *object_; static PyObject *object_; /* initialized in BTreeModuleTemplate init */
static int static int
check_argument_cmp(PyObject *arg) check_argument_cmp(PyObject *arg)
...@@ -15,15 +16,12 @@ check_argument_cmp(PyObject *arg) ...@@ -15,15 +16,12 @@ check_argument_cmp(PyObject *arg)
/* arg->ob_type->tp_compare, */ /* arg->ob_type->tp_compare, */
/* ((PyTypeObject *)object_)->ob_type->tp_compare); */ /* ((PyTypeObject *)object_)->ob_type->tp_compare); */
if (arg->ob_type->tp_richcompare == NULL #ifdef PY3K
&& if (Py_TYPE(arg)->tp_richcompare == Py_TYPE(object_)->tp_richcompare)
#if PY_MAJOR_VERSION==2 && PY_MINOR_VERSION < 6
arg->ob_type->tp_compare == NULL
#else #else
arg->ob_type->tp_compare == if (Py_TYPE(arg)->tp_richcompare == NULL
((PyTypeObject *)object_)->ob_type->tp_compare && Py_TYPE(arg)->tp_compare == Py_TYPE(object_)->tp_compare)
#endif #endif
)
{ {
PyErr_SetString(PyExc_TypeError, "Object has default comparison"); PyErr_SetString(PyExc_TypeError, "Object has default comparison");
return 0; return 0;
...@@ -31,7 +29,8 @@ check_argument_cmp(PyObject *arg) ...@@ -31,7 +29,8 @@ check_argument_cmp(PyObject *arg)
return 1; return 1;
} }
#define TEST_KEY_SET_OR(V, KEY, TARGET) if ( ( (V) = PyObject_Compare((KEY),(TARGET)) ), PyErr_Occurred() ) #define TEST_KEY_SET_OR(V, KEY, TARGET) \
if ( ( (V) = COMPARE((KEY),(TARGET)) ), PyErr_Occurred() )
#define INCREF_KEY(k) Py_INCREF(k) #define INCREF_KEY(k) Py_INCREF(k)
#define DECREF_KEY(KEY) Py_DECREF(KEY) #define DECREF_KEY(KEY) Py_DECREF(KEY)
#define COPY_KEY(KEY, E) KEY=(E) #define COPY_KEY(KEY, E) KEY=(E)
......
#define VALUEMACROS_H "$Id$\n" #define VALUEMACROS_H "$Id$\n"
#define VALUE_TYPE PyObject * #define VALUE_TYPE PyObject *
#define VALUE_TYPE_IS_PYOBJECT #define VALUE_TYPE_IS_PYOBJECT
#define TEST_VALUE(VALUE, TARGET) PyObject_Compare((VALUE),(TARGET)) #define TEST_VALUE(VALUE, TARGET) COMPARE((VALUE),(TARGET))
#define DECLARE_VALUE(NAME) VALUE_TYPE NAME #define DECLARE_VALUE(NAME) VALUE_TYPE NAME
#define INCREF_VALUE(k) Py_INCREF(k) #define INCREF_VALUE(k) Py_INCREF(k)
#define DECREF_VALUE(k) Py_DECREF(k) #define DECREF_VALUE(k) Py_DECREF(k)
......
/* Backport type definitions from Python 2.5's object.h */
#ifndef BTREE_PY24COMPATH_H
#define BTREE_PY24COMPAT_H
#if PY_VERSION_HEX < 0x02050000
typedef Py_ssize_t (*lenfunc)(PyObject *);
typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
#endif /* PY_VERSION_HEX */
#endif /* BTREE_PY24COMPAT_H */
...@@ -22,6 +22,16 @@ def _skip_wo_ZODB(test_method): #pragma NO COVER ...@@ -22,6 +22,16 @@ def _skip_wo_ZODB(test_method): #pragma NO COVER
else: else:
return test_method return test_method
def _skip_under_Py3k(test_method): #pragma NO COVER
try:
unicode
except NameError: # skip this test
def _dummy(*args):
pass
return _dummy
else:
return test_method
class Base(object): class Base(object):
# Tests common to all types: sets, buckets, and BTrees # Tests common to all types: sets, buckets, and BTrees
...@@ -75,7 +85,7 @@ class Base(object): ...@@ -75,7 +85,7 @@ class Base(object):
def testSetstateArgumentChecking(self): def testSetstateArgumentChecking(self):
try: try:
self._makeOne().__setstate__(('',)) self._makeOne().__setstate__(('',))
except TypeError, v: except TypeError as v:
self.assertEqual(str(v), 'tuple required for first state element') self.assertEqual(str(v), 'tuple required for first state element')
else: else:
raise AssertionError("Expected exception") raise AssertionError("Expected exception")
...@@ -171,17 +181,17 @@ class Base(object): ...@@ -171,17 +181,17 @@ class Base(object):
# Modifying a thing # Modifying a thing
remove(100) remove(100)
self.assert_(t in read) self.assertTrue(t in read)
del read[:] del read[:]
add(100) add(100)
self.assert_(t in read) self.assertTrue(t in read)
del read[:] del read[:]
transaction.abort() transaction.abort()
conn.cacheMinimize() conn.cacheMinimize()
list(t) list(t)
self.assert_(100 in t) self.assertTrue(100 in t)
self.assert_(not read) self.assertTrue(not read)
class MappingBase(Base): class MappingBase(Base):
...@@ -189,7 +199,8 @@ class MappingBase(Base): ...@@ -189,7 +199,8 @@ class MappingBase(Base):
def _populate(self, t, l): def _populate(self, t, l):
# Make some data # Make some data
for i in range(l): t[i]=i for i in range(l):
t[i]=i
def testRepr(self): def testRepr(self):
# test the repr because buckets have a complex repr implementation # test the repr because buckets have a complex repr implementation
...@@ -203,7 +214,7 @@ class MappingBase(Base): ...@@ -203,7 +214,7 @@ class MappingBase(Base):
# But since the test is also run for btrees, skip the length # But since the test is also run for btrees, skip the length
# check if the repr starts with '<' # check if the repr starts with '<'
if not r.startswith('<'): if not r.startswith('<'):
self.assert_(len(r) > 10000) self.assertTrue(len(r) > 10000)
def testGetItemFails(self): def testGetItemFails(self):
self.assertRaises(KeyError, self._getitemfail) self.assertRaises(KeyError, self._getitemfail)
...@@ -219,7 +230,7 @@ class MappingBase(Base): ...@@ -219,7 +230,7 @@ class MappingBase(Base):
t = self._makeOne() t = self._makeOne()
t[1] = 1 t[1] = 1
a = t[1] a = t[1]
self.assertEqual(a , 1, `a`) self.assertEqual(a , 1, repr(a))
def testReplaceWorks(self): def testReplaceWorks(self):
t = self._makeOne() t = self._makeOne()
...@@ -232,7 +243,7 @@ class MappingBase(Base): ...@@ -232,7 +243,7 @@ class MappingBase(Base):
import random import random
t = self._makeOne() t = self._makeOne()
added = {} added = {}
r = range(1000) r = list(range(1000))
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
t[k] = x t[k] = x
...@@ -241,12 +252,14 @@ class MappingBase(Base): ...@@ -241,12 +252,14 @@ class MappingBase(Base):
self.assertEqual(len(t) , len(addl), len(t)) self.assertEqual(len(t) , len(addl), len(t))
def testHasKeyWorks(self): def testHasKeyWorks(self):
from .._compat import PY2
t = self._makeOne() t = self._makeOne()
t[1] = 1 t[1] = 1
self.assert_(t.has_key(1)) if PY2:
self.assert_(1 in t) self.assertTrue(t.has_key(1))
self.assert_(0 not in t) self.assertTrue(1 in t)
self.assert_(2 not in t) self.assertTrue(0 not in t)
self.assertTrue(2 not in t)
def testValuesWorks(self): def testValuesWorks(self):
t = self._makeOne() t = self._makeOne()
...@@ -267,20 +280,18 @@ class MappingBase(Base): ...@@ -267,20 +280,18 @@ class MappingBase(Base):
t[99-x] = x t[99-x] = x
for x in range(40): for x in range(40):
lst = list(t.values(0+x,99-x)) lst = sorted(t.values(0+x,99-x))
lst.sort() self.assertEqual(lst, list(range(0+x,99-x+1)))
self.assertEqual(lst,range(0+x,99-x+1))
lst = list(t.values(max=99-x, min=0+x)) lst = sorted(t.values(max=99-x, min=0+x))
lst.sort() self.assertEqual(lst, list(range(0+x,99-x+1)))
self.assertEqual(lst,range(0+x,99-x+1))
def testValuesNegativeIndex(self): def testValuesNegativeIndex(self):
t = self._makeOne() t = self._makeOne()
L = [-3, 6, -11, 4] L = [-3, 6, -11, 4]
for i in L: for i in L:
t[i] = i t[i] = i
L.sort() L = sorted(L)
vals = t.values() vals = t.values()
for i in range(-1, -5, -1): for i in range(-1, -5, -1):
self.assertEqual(vals[i], L[i]) self.assertEqual(vals[i], L[i])
...@@ -299,10 +310,10 @@ class MappingBase(Base): ...@@ -299,10 +310,10 @@ class MappingBase(Base):
for x in range(40): for x in range(40):
lst = t.keys(0+x,99-x) lst = t.keys(0+x,99-x)
self.assertEqual(list(lst), range(0+x, 99-x+1)) self.assertEqual(list(lst), list(range(0+x, 99-x+1)))
lst = t.keys(max=99-x, min=0+x) lst = t.keys(max=99-x, min=0+x)
self.assertEqual(list(lst), range(0+x, 99-x+1)) self.assertEqual(list(lst), list(range(0+x, 99-x+1)))
self.assertEqual(len(v), 100) self.assertEqual(len(v), 100)
...@@ -311,7 +322,7 @@ class MappingBase(Base): ...@@ -311,7 +322,7 @@ class MappingBase(Base):
L = [-3, 6, -11, 4] L = [-3, 6, -11, 4]
for i in L: for i in L:
t[i] = i t[i] = i
L.sort() L = sorted(L)
keys = t.keys() keys = t.keys()
for i in range(-1, -5, -1): for i in range(-1, -5, -1):
self.assertEqual(keys[i], L[i]) self.assertEqual(keys[i], L[i])
...@@ -335,17 +346,17 @@ class MappingBase(Base): ...@@ -335,17 +346,17 @@ class MappingBase(Base):
i += 1 i += 1
items = list(t.items(min=12, max=20)) items = list(t.items(min=12, max=20))
self.assertEqual(items, zip(range(12, 21), range(24, 43, 2))) self.assertEqual(items, list(zip(range(12, 21), range(24, 43, 2))))
items = list(t.iteritems(min=12, max=20)) items = list(t.iteritems(min=12, max=20))
self.assertEqual(items, zip(range(12, 21), range(24, 43, 2))) self.assertEqual(items, list(zip(range(12, 21), range(24, 43, 2))))
def testItemsNegativeIndex(self): def testItemsNegativeIndex(self):
t = self._makeOne() t = self._makeOne()
L = [-3, 6, -11, 4] L = [-3, 6, -11, 4]
for i in L: for i in L:
t[i] = i t[i] = i
L.sort() L = sorted(L)
items = t.items() items = t.items()
for i in range(-1, -5, -1): for i in range(-1, -5, -1):
self.assertEqual(items[i], (L[i], L[i])) self.assertEqual(items[i], (L[i], L[i]))
...@@ -378,14 +389,14 @@ class MappingBase(Base): ...@@ -378,14 +389,14 @@ class MappingBase(Base):
try: try:
t.maxKey(t.minKey() - 1) t.maxKey(t.minKey() - 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
try: try:
t.minKey(t.maxKey() + 1) t.minKey(t.maxKey() + 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
...@@ -393,7 +404,7 @@ class MappingBase(Base): ...@@ -393,7 +404,7 @@ class MappingBase(Base):
def testClear(self): def testClear(self):
import random import random
t = self._makeOne() t = self._makeOne()
r = range(100) r = list(range(100))
for x in r: for x in r:
rnd = random.choice(r) rnd = random.choice(r)
t[rnd] = 0 t[rnd] = 0
...@@ -411,8 +422,7 @@ class MappingBase(Base): ...@@ -411,8 +422,7 @@ class MappingBase(Base):
d[k]=i d[k]=i
l.append((k, i)) l.append((k, i))
items=d.items() items= sorted(d.items())
items.sort()
t.update(d) t.update(d)
self.assertEqual(list(t.items()), items) self.assertEqual(list(t.items()), items)
...@@ -447,7 +457,7 @@ class MappingBase(Base): ...@@ -447,7 +457,7 @@ class MappingBase(Base):
# For IITreeSets, this one was returning 31 for len(keys), and # For IITreeSets, this one was returning 31 for len(keys), and
# list(keys) produced a list with 100 elements. # list(keys) produced a list with 100 elements.
t.clear() t.clear()
t.update(zip(range(300), range(300))) t.update(list(zip(range(300), range(300))))
keys = t.keys(200, 50) keys = t.keys(200, 50)
self.assertEqual(len(keys), 0) self.assertEqual(len(keys), 0)
self.assertEqual(list(keys), []) self.assertEqual(list(keys), [])
...@@ -464,6 +474,7 @@ class MappingBase(Base): ...@@ -464,6 +474,7 @@ class MappingBase(Base):
# This tests fixes to several bugs in this area, starting with # This tests fixes to several bugs in this area, starting with
# http://collector.zope.org/Zope/419, # http://collector.zope.org/Zope/419,
# "BTreeItems slice contains 1 too many elements". # "BTreeItems slice contains 1 too many elements".
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
for n in range(10): for n in range(10):
t.clear() t.clear()
...@@ -531,12 +542,12 @@ class MappingBase(Base): ...@@ -531,12 +542,12 @@ class MappingBase(Base):
t[i] = 1 t[i] = 1
tslice = t.items()[20:80] tslice = t.items()[20:80]
self.assertEqual(len(tslice), 60) self.assertEqual(len(tslice), 60)
self.assertEqual(list(tslice), zip(range(20, 80), [1]*60)) self.assertEqual(list(tslice), list(zip(range(20, 80), [1]*60)))
def testIterators(self): def testIterators(self):
t = self._makeOne() t = self._makeOne()
for keys in [], [-2], [1, 4], range(-170, 2000, 6): for keys in [], [-2], [1, 4], list(range(-170, 2000, 6)):
t.clear() t.clear()
for k in keys: for k in keys:
t[k] = -3 * k t[k] = -3 * k
...@@ -549,11 +560,11 @@ class MappingBase(Base): ...@@ -549,11 +560,11 @@ class MappingBase(Base):
self.assertEqual(x, keys) self.assertEqual(x, keys)
it = iter(t) it = iter(t)
self.assert_(it is iter(it)) self.assertTrue(it is iter(it))
x = [] x = []
try: try:
while 1: while 1:
x.append(it.next()) x.append(next(it))
except StopIteration: except StopIteration:
pass pass
self.assertEqual(x, keys) self.assertEqual(x, keys)
...@@ -565,14 +576,14 @@ class MappingBase(Base): ...@@ -565,14 +576,14 @@ class MappingBase(Base):
def testRangedIterators(self): def testRangedIterators(self):
t = self._makeOne() t = self._makeOne()
for keys in [], [-2], [1, 4], range(-170, 2000, 13): for keys in [], [-2], [1, 4], list(range(-170, 2000, 13)):
t.clear() t.clear()
values = [] values = []
for k in keys: for k in keys:
value = -3 * k value = -3 * k
t[k] = value t[k] = value
values.append(value) values.append(value)
items = zip(keys, values) items = list(zip(keys, values))
self.assertEqual(list(t.iterkeys()), keys) self.assertEqual(list(t.iterkeys()), keys)
self.assertEqual(list(t.itervalues()), values) self.assertEqual(list(t.itervalues()), values)
...@@ -593,7 +604,7 @@ class MappingBase(Base): ...@@ -593,7 +604,7 @@ class MappingBase(Base):
got = t.itervalues(lo) got = t.itervalues(lo)
self.assertEqual(goodvalues, list(got)) self.assertEqual(goodvalues, list(got))
gooditems = zip(goodkeys, goodvalues) gooditems = list(zip(goodkeys, goodvalues))
got = t.iteritems(lo) got = t.iteritems(lo)
self.assertEqual(gooditems, list(got)) self.assertEqual(gooditems, list(got))
...@@ -607,7 +618,7 @@ class MappingBase(Base): ...@@ -607,7 +618,7 @@ class MappingBase(Base):
got = t.itervalues(lo, max=hi) got = t.itervalues(lo, max=hi)
self.assertEqual(goodvalues, list(got)) self.assertEqual(goodvalues, list(got))
gooditems = zip(goodkeys, goodvalues) gooditems = list(zip(goodkeys, goodvalues))
got = t.iteritems(max=hi, min=lo) got = t.iteritems(max=hi, min=lo)
self.assertEqual(gooditems, list(got)) self.assertEqual(gooditems, list(got))
...@@ -684,7 +695,7 @@ class MappingBase(Base): ...@@ -684,7 +695,7 @@ class MappingBase(Base):
self.assertEqual(t.setdefault(1, 2), 2) self.assertEqual(t.setdefault(1, 2), 2)
# That should also have associated 1 with 2 in the tree. # That should also have associated 1 with 2 in the tree.
self.assert_(1 in t) self.assertTrue(1 in t)
self.assertEqual(t[1], 2) self.assertEqual(t[1], 2)
# And trying to change it again should have no effect. # And trying to change it again should have no effect.
self.assertEqual(t.setdefault(1, 666), 2) self.assertEqual(t.setdefault(1, 666), 2)
...@@ -820,14 +831,13 @@ class BTreeTests(MappingBase): ...@@ -820,14 +831,13 @@ class BTreeTests(MappingBase):
import random import random
t = self._makeOne() t = self._makeOne()
added = {} added = {}
r = range(100) r = list(range(100))
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
if not added.has_key(k): if k not in added:
t[k] = x t[k] = x
added[k] = 1 added[k] = 1
addl = added.keys() addl = sorted(added.keys())
addl.sort()
diff = lsubtract(list(t.keys()), addl) diff = lsubtract(list(t.keys()), addl)
self.assertEqual(diff , [], (diff, addl, list(t.keys()))) self.assertEqual(diff , [], (diff, addl, list(t.keys())))
self._checkIt(t) self._checkIt(t)
...@@ -836,13 +846,12 @@ class BTreeTests(MappingBase): ...@@ -836,13 +846,12 @@ class BTreeTests(MappingBase):
import random import random
t = self._makeOne() t = self._makeOne()
added = {} added = {}
r = range(100) r = list(range(100))
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
t[k] = x t[k] = x
added[k] = 1 added[k] = 1
addl = added.keys() addl = sorted(added.keys())
addl.sort()
diff = lsubtract(t.keys(), addl) diff = lsubtract(t.keys(), addl)
self.assertEqual(diff , [], diff) self.assertEqual(diff , [], diff)
self._checkIt(t) self._checkIt(t)
...@@ -850,7 +859,7 @@ class BTreeTests(MappingBase): ...@@ -850,7 +859,7 @@ class BTreeTests(MappingBase):
def testRandomDeletes(self): def testRandomDeletes(self):
import random import random
t = self._makeOne() t = self._makeOne()
r = range(1000) r = list(range(1000))
added = [] added = []
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
...@@ -859,15 +868,15 @@ class BTreeTests(MappingBase): ...@@ -859,15 +868,15 @@ class BTreeTests(MappingBase):
deleted = [] deleted = []
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
if t.has_key(k): if k in t:
self.assert_(k in t) self.assertTrue(k in t)
del t[k] del t[k]
deleted.append(k) deleted.append(k)
if t.has_key(k): if k in t:
self.fail( "had problems deleting %s" % k ) self.fail( "had problems deleting %s" % k )
badones = [] badones = []
for x in deleted: for x in deleted:
if t.has_key(x): if x in t:
badones.append(x) badones.append(x)
self.assertEqual(badones , [], (badones, added, deleted)) self.assertEqual(badones , [], (badones, added, deleted))
self._checkIt(t) self._checkIt(t)
...@@ -875,7 +884,7 @@ class BTreeTests(MappingBase): ...@@ -875,7 +884,7 @@ class BTreeTests(MappingBase):
def testTargetedDeletes(self): def testTargetedDeletes(self):
import random import random
t = self._makeOne() t = self._makeOne()
r = range(1000) r = list(range(1000))
for x in r: for x in r:
k = random.choice(r) k = random.choice(r)
t[k] = x t[k] = x
...@@ -889,7 +898,7 @@ class BTreeTests(MappingBase): ...@@ -889,7 +898,7 @@ class BTreeTests(MappingBase):
def testPathologicalRightBranching(self): def testPathologicalRightBranching(self):
t = self._makeOne() t = self._makeOne()
r = range(1000) r = list(range(1000))
for x in r: for x in r:
t[x] = 1 t[x] = 1
self.assertEqual(realseq(t.keys()) , r, realseq(t.keys())) self.assertEqual(realseq(t.keys()) , r, realseq(t.keys()))
...@@ -900,9 +909,8 @@ class BTreeTests(MappingBase): ...@@ -900,9 +909,8 @@ class BTreeTests(MappingBase):
def testPathologicalLeftBranching(self): def testPathologicalLeftBranching(self):
t = self._makeOne() t = self._makeOne()
r = range(1000) r = list(range(1000))
revr = r[:] revr = list(reversed(r[:]))
revr.reverse()
for x in revr: for x in revr:
t[x] = 1 t[x] = 1
self.assertEqual(realseq(t.keys()) , r, realseq(t.keys())) self.assertEqual(realseq(t.keys()) , r, realseq(t.keys()))
...@@ -955,9 +963,10 @@ class BTreeTests(MappingBase): ...@@ -955,9 +963,10 @@ class BTreeTests(MappingBase):
for x in add_order: for x in add_order:
t[x] = 1 t[x] = 1
for x in delete_order: for x in delete_order:
try: del t[x] try:
del t[x]
except KeyError: except KeyError:
if t.has_key(x): if x in t:
self.assertEqual(1,2,"failed to delete %s" % x) self.assertEqual(1,2,"failed to delete %s" % x)
self._checkIt(t) self._checkIt(t)
...@@ -989,14 +998,14 @@ class BTreeTests(MappingBase): ...@@ -989,14 +998,14 @@ class BTreeTests(MappingBase):
for i in range(200): for i in range(200):
t[i] = i t[i] = i
items, dummy = t.__getstate__() items, dummy = t.__getstate__()
self.assert_(len(items) > 2) # at least two buckets and a key self.assertTrue(len(items) > 2) # at least two buckets and a key
# All values in the first bucket are < firstkey. All in the # All values in the first bucket are < firstkey. All in the
# second bucket are >= firstkey, and firstkey is the first key in # second bucket are >= firstkey, and firstkey is the first key in
# the second bucket. # the second bucket.
firstkey = items[1] firstkey = items[1]
therange = t.keys(-1, firstkey) therange = t.keys(-1, firstkey)
self.assertEqual(len(therange), firstkey + 1) self.assertEqual(len(therange), firstkey + 1)
self.assertEqual(list(therange), range(firstkey + 1)) self.assertEqual(list(therange), list(range(firstkey + 1)))
# Now for the tricky part. If we delete firstkey, the second bucket # Now for the tricky part. If we delete firstkey, the second bucket
# loses its smallest key, but firstkey remains in the BTree node. # loses its smallest key, but firstkey remains in the BTree node.
# If we then do a high-end range search on firstkey, the BTree node # If we then do a high-end range search on firstkey, the BTree node
...@@ -1008,7 +1017,7 @@ class BTreeTests(MappingBase): ...@@ -1008,7 +1017,7 @@ class BTreeTests(MappingBase):
del t[firstkey] del t[firstkey]
therange = t.keys(min=-1, max=firstkey) therange = t.keys(min=-1, max=firstkey)
self.assertEqual(len(therange), firstkey) self.assertEqual(len(therange), firstkey)
self.assertEqual(list(therange), range(firstkey)) self.assertEqual(list(therange), list(range(firstkey)))
self._checkIt(t) self._checkIt(t)
def testInsertMethod(self): def testInsertMethod(self):
...@@ -1037,11 +1046,11 @@ class BTreeTests(MappingBase): ...@@ -1037,11 +1046,11 @@ class BTreeTests(MappingBase):
for dummy in range(20): for dummy in range(20):
try: try:
del t[k[0]] del t[k[0]]
except RuntimeError, detail: except RuntimeError as detail:
self.assertEqual(str(detail), "the bucket being iterated " self.assertEqual(str(detail), "the bucket being iterated "
"changed size") "changed size")
break break
except KeyError, v: except KeyError as v:
# The Python implementation behaves very differently and # The Python implementation behaves very differently and
# gives a key error in this situation. It can't mess up # gives a key error in this situation. It can't mess up
# memory and can't readily detect changes to underlying buckets # memory and can't readily detect changes to underlying buckets
...@@ -1069,22 +1078,28 @@ class NormalSetTests(Base): ...@@ -1069,22 +1078,28 @@ class NormalSetTests(Base):
self.assertEqual(t.add(5) , 0) self.assertEqual(t.add(5) , 0)
def testInsert(self): def testInsert(self):
from .._compat import PY2
t = self._makeOne() t = self._makeOne()
t.insert(1) t.insert(1)
self.assert_(t.has_key(1)) if PY2:
self.assert_(1 in t) self.assertTrue(t.has_key(1))
self.assert_(2 not in t) self.assertTrue(1 in t)
self.assertTrue(2 not in t)
def testBigInsert(self): def testBigInsert(self):
from .._compat import PY2
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(10000) r = xrange(10000)
for x in r: for x in r:
t.insert(x) t.insert(x)
for x in r: for x in r:
self.assert_(t.has_key(x)) if PY2:
self.assert_(x in t) self.assertTrue(t.has_key(x))
self.assertTrue(x in t)
def testRemoveSucceeds(self): def testRemoveSucceeds(self):
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(10000) r = xrange(10000)
for x in r: t.insert(x) for x in r: t.insert(x)
...@@ -1097,11 +1112,14 @@ class NormalSetTests(Base): ...@@ -1097,11 +1112,14 @@ class NormalSetTests(Base):
self._makeOne().remove(1) self._makeOne().remove(1)
def testHasKeyFails(self): def testHasKeyFails(self):
from .._compat import PY2
t = self._makeOne() t = self._makeOne()
self.assert_(not t.has_key(1)) if PY2:
self.assert_(1 not in t) self.assertTrue(not t.has_key(1))
self.assertTrue(1 not in t)
def testKeys(self): def testKeys(self):
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(1000) r = xrange(1000)
for x in r: for x in r:
...@@ -1111,6 +1129,7 @@ class NormalSetTests(Base): ...@@ -1111,6 +1129,7 @@ class NormalSetTests(Base):
def testClear(self): def testClear(self):
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(1000) r = xrange(1000)
for x in r: t.insert(x) for x in r: t.insert(x)
...@@ -1134,21 +1153,21 @@ class NormalSetTests(Base): ...@@ -1134,21 +1153,21 @@ class NormalSetTests(Base):
self.assertEqual(t.minKey() , 1) self.assertEqual(t.minKey() , 1)
self.assertEqual(t.minKey(3) , 3) self.assertEqual(t.minKey(3) , 3)
self.assertEqual(t.minKey(9) , 10) self.assertEqual(t.minKey(9) , 10)
self.assert_(t.minKey() in t) self.assertTrue(t.minKey() in t)
self.assert_(t.minKey()-1 not in t) self.assertTrue(t.minKey()-1 not in t)
self.assert_(t.maxKey() in t) self.assertTrue(t.maxKey() in t)
self.assert_(t.maxKey()+1 not in t) self.assertTrue(t.maxKey()+1 not in t)
try: try:
t.maxKey(t.minKey() - 1) t.maxKey(t.minKey() - 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
try: try:
t.minKey(t.maxKey() + 1) t.minKey(t.maxKey() + 1)
except ValueError, err: except ValueError as err:
self.assertEqual(str(err), "no key satisfies the conditions") self.assertEqual(str(err), "no key satisfies the conditions")
else: else:
self.fail("expected ValueError") self.fail("expected ValueError")
...@@ -1163,8 +1182,7 @@ class NormalSetTests(Base): ...@@ -1163,8 +1182,7 @@ class NormalSetTests(Base):
d[k]=i d[k]=i
l.append(k) l.append(k)
items = d.keys() items = sorted(d.keys())
items.sort()
t.update(l) t.update(l)
self.assertEqual(list(t.keys()), items) self.assertEqual(list(t.keys()), items)
...@@ -1203,28 +1221,28 @@ class NormalSetTests(Base): ...@@ -1203,28 +1221,28 @@ class NormalSetTests(Base):
self.assertEqual(len(t), n) self.assertEqual(len(t), n)
kslice = t.keys() kslice = t.keys()
self.assertEqual(len(kslice), n) self.assertEqual(len(list(kslice)), n)
# Test whole-structure slices. # Test whole-structure slices.
x = kslice[:] x = kslice[:]
self.assertEqual(list(x), keys[:]) self.assertEqual(list(x), list(keys[:]))
for lo in range(-2*n, 2*n+1): for lo in range(-2*n, 2*n+1):
# Test one-sided slices. # Test one-sided slices.
x = kslice[:lo] x = kslice[:lo]
self.assertEqual(list(x), keys[:lo]) self.assertEqual(list(x), list(keys[:lo]))
x = kslice[lo:] x = kslice[lo:]
self.assertEqual(list(x), keys[lo:]) self.assertEqual(list(x), list(keys[lo:]))
for hi in range(-2*n, 2*n+1): for hi in range(-2*n, 2*n+1):
# Test two-sided slices. # Test two-sided slices.
x = kslice[lo:hi] x = kslice[lo:hi]
self.assertEqual(list(x), keys[lo:hi]) self.assertEqual(list(x), list(keys[lo:hi]))
def testIterator(self): def testIterator(self):
t = self._makeOne() t = self._makeOne()
for keys in [], [-2], [1, 4], range(-170, 2000, 6): for keys in [], [-2], [1, 4], list(range(-170, 2000, 6)):
t.clear() t.clear()
t.update(keys) t.update(keys)
...@@ -1236,11 +1254,11 @@ class NormalSetTests(Base): ...@@ -1236,11 +1254,11 @@ class NormalSetTests(Base):
self.assertEqual(x, keys) self.assertEqual(x, keys)
it = iter(t) it = iter(t)
self.assert_(it is iter(it)) self.assertTrue(it is iter(it))
x = [] x = []
try: try:
while 1: while 1:
x.append(it.next()) x.append(next(it))
except StopIteration: except StopIteration:
pass pass
self.assertEqual(x, keys) self.assertEqual(x, keys)
...@@ -1248,12 +1266,14 @@ class NormalSetTests(Base): ...@@ -1248,12 +1266,14 @@ class NormalSetTests(Base):
class ExtendedSetTests(NormalSetTests): class ExtendedSetTests(NormalSetTests):
def testLen(self): def testLen(self):
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(10000) r = xrange(10000)
for x in r: t.insert(x) for x in r: t.insert(x)
self.assertEqual(len(t) , 10000, len(t)) self.assertEqual(len(t) , 10000, len(t))
def testGetItem(self): def testGetItem(self):
from .._compat import xrange
t = self._makeOne() t = self._makeOne()
r = xrange(10000) r = xrange(10000)
for x in r: t.insert(x) for x in r: t.insert(x)
...@@ -1300,10 +1320,10 @@ class InternalKeysMappingTest(object): ...@@ -1300,10 +1320,10 @@ class InternalKeysMappingTest(object):
key = data[1] key = data[1]
del tree[key] del tree[key]
data = tree.__getstate__()[0] data = tree.__getstate__()[0]
self.assert_(data[1] != key) self.assertTrue(data[1] != key)
# The tree should have changed: # The tree should have changed:
self.assert_(tree._p_changed) self.assertTrue(tree._p_changed)
# Grow the btree until we have multiple levels # Grow the btree until we have multiple levels
while 1: while 1:
...@@ -1318,7 +1338,7 @@ class InternalKeysMappingTest(object): ...@@ -1318,7 +1338,7 @@ class InternalKeysMappingTest(object):
key = data[1] key = data[1]
del tree[key] del tree[key]
data = tree.__getstate__()[0] data = tree.__getstate__()[0]
self.assert_(data[1] != key) self.assertTrue(data[1] != key)
transaction.abort() transaction.abort()
db.close() db.close()
...@@ -1340,7 +1360,7 @@ class ModuleTest(object): ...@@ -1340,7 +1360,7 @@ class ModuleTest(object):
for name in ('Bucket', 'BTree', 'Set', 'TreeSet'): for name in ('Bucket', 'BTree', 'Set', 'TreeSet'):
klass = getattr(self._getModule(), name) klass = getattr(self._getModule(), name)
self.assertEqual(klass.__module__, self._getModule().__name__) self.assertEqual(klass.__module__, self._getModule().__name__)
self.assert_(klass is getattr(self._getModule(), self.assertTrue(klass is getattr(self._getModule(),
self.prefix + name)) self.prefix + name))
def testModuleProvides(self): def testModuleProvides(self):
...@@ -1350,12 +1370,12 @@ class ModuleTest(object): ...@@ -1350,12 +1370,12 @@ class ModuleTest(object):
def testFamily(self): def testFamily(self):
import BTrees import BTrees
if self.prefix == 'OO': if self.prefix == 'OO':
self.assert_( self.assertTrue(
getattr(self._getModule(), 'family', self) is self) getattr(self._getModule(), 'family', self) is self)
elif 'L' in self.prefix: elif 'L' in self.prefix:
self.assert_(self._getModule().family is BTrees.family64) self.assertTrue(self._getModule().family is BTrees.family64)
elif 'I' in self.prefix: elif 'I' in self.prefix:
self.assert_(self._getModule().family is BTrees.family32) self.assertTrue(self._getModule().family is BTrees.family32)
class TypeTest(object): class TypeTest(object):
...@@ -1423,6 +1443,12 @@ class TestLongIntSupport: ...@@ -1423,6 +1443,12 @@ class TestLongIntSupport:
class TestLongIntKeys(TestLongIntSupport): class TestLongIntKeys(TestLongIntSupport):
def _makeLong(self, v):
try:
return long(v)
except NameError: #pragma NO COVER Py3k
return int(v)
def testLongIntKeysWork(self): def testLongIntKeysWork(self):
from BTrees.IIBTree import using64bits from BTrees.IIBTree import using64bits
if not using64bits: if not using64bits:
...@@ -1432,10 +1458,11 @@ class TestLongIntKeys(TestLongIntSupport): ...@@ -1432,10 +1458,11 @@ class TestLongIntKeys(TestLongIntSupport):
assert o1 != o2 assert o1 != o2
# Test some small key values first: # Test some small key values first:
t[0L] = o1 zero_long = self._makeLong(0)
t[zero_long] = o1
self.assertEqual(t[0], o1) self.assertEqual(t[0], o1)
t[0] = o2 t[0] = o2
self.assertEqual(t[0L], o2) self.assertEqual(t[zero_long], o2)
self.assertEqual(list(t.keys()), [0]) self.assertEqual(list(t.keys()), [0])
# Test some large key values too: # Test some large key values too:
...@@ -1469,8 +1496,7 @@ class TestLongIntValues(TestLongIntSupport): ...@@ -1469,8 +1496,7 @@ class TestLongIntValues(TestLongIntSupport):
if not using64bits: if not using64bits:
return return
t = self._makeOne() t = self._makeOne()
keys = list(self.getTwoKeys()) keys = sorted(self.getTwoKeys())
keys.sort()
k1, k2 = keys k1, k2 = keys
assert k1 != k2 assert k1 != k2
...@@ -1500,7 +1526,7 @@ class TestLongIntValues(TestLongIntSupport): ...@@ -1500,7 +1526,7 @@ class TestLongIntValues(TestLongIntSupport):
# that builds an object of that type given only a list of keys. # that builds an object of that type given only a list of keys.
def makeBuilder(mapbuilder): def makeBuilder(mapbuilder):
def result(keys=[], mapbuilder=mapbuilder): def result(keys=[], mapbuilder=mapbuilder):
return mapbuilder(zip(keys, keys)) return mapbuilder(list(zip(keys, keys)))
return result return result
# Subclasses have to set up: # Subclasses have to set up:
...@@ -1521,8 +1547,7 @@ class SetResult(object): ...@@ -1521,8 +1547,7 @@ class SetResult(object):
for e in y: for e in y:
if e not in result: if e not in result:
result.append(e) result.append(e)
result.sort() return sorted(result)
return result
def _intersection(self, x, y): def _intersection(self, x, y):
result = [] result = []
...@@ -1544,39 +1569,39 @@ class SetResult(object): ...@@ -1544,39 +1569,39 @@ class SetResult(object):
def testNone(self): def testNone(self):
for op in self.union, self.intersection, self.difference: for op in self.union, self.intersection, self.difference:
C = op(None, None) C = op(None, None)
self.assert_(C is None) self.assertTrue(C is None)
for op in self.union, self.intersection, self.difference: for op in self.union, self.intersection, self.difference:
for A in self.As: for A in self.As:
C = op(A, None) C = op(A, None)
self.assert_(C is A) self.assertTrue(C is A)
C = op(None, A) C = op(None, A)
if op == self.difference: if op == self.difference:
self.assert_(C is None) self.assertTrue(C is None)
else: else:
self.assert_(C is A) self.assertTrue(C is A)
def testEmptyUnion(self): def testEmptyUnion(self):
for A in self.As: for A in self.As:
for E in self.emptys: for E in self.emptys:
C = self.union(A, E) C = self.union(A, E)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), self.Akeys) self.assertEqual(list(C), self.Akeys)
C = self.union(E, A) C = self.union(E, A)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), self.Akeys) self.assertEqual(list(C), self.Akeys)
def testEmptyIntersection(self): def testEmptyIntersection(self):
for A in self.As: for A in self.As:
for E in self.emptys: for E in self.emptys:
C = self.intersection(A, E) C = self.intersection(A, E)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), []) self.assertEqual(list(C), [])
C = self.intersection(E, A) C = self.intersection(E, A)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), []) self.assertEqual(list(C), [])
def testEmptyDifference(self): def testEmptyDifference(self):
...@@ -1599,7 +1624,7 @@ class SetResult(object): ...@@ -1599,7 +1624,7 @@ class SetResult(object):
for A in inputs: for A in inputs:
for B in inputs: for B in inputs:
C = self.union(A, B) C = self.union(A, B)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), self._union(A, B)) self.assertEqual(list(C), self._union(A, B))
def testIntersection(self): def testIntersection(self):
...@@ -1607,7 +1632,7 @@ class SetResult(object): ...@@ -1607,7 +1632,7 @@ class SetResult(object):
for A in inputs: for A in inputs:
for B in inputs: for B in inputs:
C = self.intersection(A, B) C = self.intersection(A, B)
self.assert_(not hasattr(C, "values")) self.assertTrue(not hasattr(C, "values"))
self.assertEqual(list(C), self._intersection(A, B)) self.assertEqual(list(C), self._intersection(A, B))
def testDifference(self): def testDifference(self):
...@@ -1673,39 +1698,39 @@ class Weighted(object): ...@@ -1673,39 +1698,39 @@ class Weighted(object):
def testBothNone(self): def testBothNone(self):
for op in self.weightedUnion(), self.weightedIntersection(): for op in self.weightedUnion(), self.weightedIntersection():
w, C = op(None, None) w, C = op(None, None)
self.assert_(C is None) self.assertTrue(C is None)
self.assertEqual(w, 0) self.assertEqual(w, 0)
w, C = op(None, None, 42, 666) w, C = op(None, None, 42, 666)
self.assert_(C is None) self.assertTrue(C is None)
self.assertEqual(w, 0) self.assertEqual(w, 0)
def testLeftNone(self): def testLeftNone(self):
for op in self.weightedUnion(), self.weightedIntersection(): for op in self.weightedUnion(), self.weightedIntersection():
for A in self.As + self.emptys: for A in self.As + self.emptys:
w, C = op(None, A) w, C = op(None, A)
self.assert_(C is A) self.assertTrue(C is A)
self.assertEqual(w, 1) self.assertEqual(w, 1)
w, C = op(None, A, 42, 666) w, C = op(None, A, 42, 666)
self.assert_(C is A) self.assertTrue(C is A)
self.assertEqual(w, 666) self.assertEqual(w, 666)
def testRightNone(self): def testRightNone(self):
for op in self.weightedUnion(), self.weightedIntersection(): for op in self.weightedUnion(), self.weightedIntersection():
for A in self.As + self.emptys: for A in self.As + self.emptys:
w, C = op(A, None) w, C = op(A, None)
self.assert_(C is A) self.assertTrue(C is A)
self.assertEqual(w, 1) self.assertEqual(w, 1)
w, C = op(A, None, 42, 666) w, C = op(A, None, 42, 666)
self.assert_(C is A) self.assertTrue(C is A)
self.assertEqual(w, 42) self.assertEqual(w, 42)
# If obj is a set, return a bucket with values all 1; else return obj. # If obj is a set, return a bucket with values all 1; else return obj.
def _normalize(self, obj): def _normalize(self, obj):
if isaset(obj): if isaset(obj):
obj = self.mkbucket(zip(obj, [1] * len(obj))) obj = self.mkbucket(list(zip(obj, [1] * len(obj))))
return obj return obj
# Python simulation of weightedUnion. # Python simulation of weightedUnion.
...@@ -1796,12 +1821,13 @@ class MultiUnion(object): ...@@ -1796,12 +1821,13 @@ class MultiUnion(object):
self.assertEqual(len(self.multiunion([])), 0) self.assertEqual(len(self.multiunion([])), 0)
def testOne(self): def testOne(self):
for sequence in [3], range(20), range(-10, 0, 2) + range(1, 10, 2): for sequence in ([3],
list(range(20)),
list(range(-10, 0, 2)) + list(range(1, 10, 2)),
):
seq1 = sequence[:] seq1 = sequence[:]
seq2 = sequence[:] seq2 = list(reversed(sequence[:]))
seq2.reverse() seqsorted = sorted(sequence[:])
seqsorted = sequence[:]
seqsorted.sort()
for seq in seq1, seq2, seqsorted: for seq in seq1, seq2, seqsorted:
for builder in self.mkset, self.mktreeset: for builder in self.mkset, self.mktreeset:
input = builder(seq) input = builder(seq)
...@@ -1817,12 +1843,12 @@ class MultiUnion(object): ...@@ -1817,12 +1843,12 @@ class MultiUnion(object):
def testBigInput(self): def testBigInput(self):
N = 100000 N = 100000
input = self.mkset(range(N)) input = self.mkset(list(range(N)))
output = self.multiunion([input] * 10) output = self.multiunion([input] * 10)
self.assertEqual(len(output), N) self.assertEqual(len(output), N)
self.assertEqual(output.minKey(), 0) self.assertEqual(output.minKey(), 0)
self.assertEqual(output.maxKey(), N-1) self.assertEqual(output.maxKey(), N-1)
self.assertEqual(list(output), range(N)) self.assertEqual(list(output), list(range(N)))
def testLotsOfLittleOnes(self): def testLotsOfLittleOnes(self):
from random import shuffle from random import shuffle
...@@ -1836,7 +1862,7 @@ class MultiUnion(object): ...@@ -1836,7 +1862,7 @@ class MultiUnion(object):
shuffle(inputs) shuffle(inputs)
output = self.multiunion(inputs) output = self.multiunion(inputs)
self.assertEqual(len(output), N*4) self.assertEqual(len(output), N*4)
self.assertEqual(list(output), range(-N, 3*N)) self.assertEqual(list(output), list(range(-N, 3*N)))
def testFunkyKeyIteration(self): def testFunkyKeyIteration(self):
# The internal set iteration protocol allows "iterating over" a # The internal set iteration protocol allows "iterating over" a
...@@ -1846,11 +1872,11 @@ class MultiUnion(object): ...@@ -1846,11 +1872,11 @@ class MultiUnion(object):
slow = mkset() slow = mkset()
for i in range(N): for i in range(N):
slow = union(slow, mkset([i])) slow = union(slow, mkset([i]))
fast = self.multiunion(range(N)) # acts like N distinct singleton sets fast = self.multiunion(list(range(N))) # like N distinct singleton sets
self.assertEqual(len(slow), N) self.assertEqual(len(slow), N)
self.assertEqual(len(fast), N) self.assertEqual(len(fast), N)
self.assertEqual(list(slow), list(fast)) self.assertEqual(list(slow), list(fast))
self.assertEqual(list(fast), range(N)) self.assertEqual(list(fast), list(range(N)))
class ConflictTestBase(object): class ConflictTestBase(object):
...@@ -1890,7 +1916,7 @@ def _test_merge(o1, o2, o3, expect, message='failed to merge', should_fail=0): ...@@ -1890,7 +1916,7 @@ def _test_merge(o1, o2, o3, expect, message='failed to merge', should_fail=0):
if should_fail: if should_fail:
try: try:
merged = o1._p_resolveConflict(s1, s2, s3) merged = o1._p_resolveConflict(s1, s2, s3)
except BTreesConflictError, err: except BTreesConflictError as err:
pass pass
else: else:
assert 0, message assert 0, message
...@@ -2143,9 +2169,8 @@ class SetConflictTestBase(ConflictTestBase): ...@@ -2143,9 +2169,8 @@ class SetConflictTestBase(ConflictTestBase):
def lsubtract(l1, l2): def lsubtract(l1, l2):
l1 = list(l1) l1 = list(l1)
l2 = list(l2) l2 = list(l2)
l = filter(lambda x, l1=l1: x not in l1, l2) return (list(filter(lambda x, l1=l1: x not in l1, l2)) +
l = l + filter(lambda x, l2=l2: x not in l2, l1) list(filter(lambda x, l2=l2: x not in l2, l1)))
return l
def realseq(itemsob): def realseq(itemsob):
return [x for x in itemsob] return [x for x in itemsob]
......
...@@ -121,7 +121,7 @@ class DegenerateBTree(unittest.TestCase): ...@@ -121,7 +121,7 @@ class DegenerateBTree(unittest.TestCase):
self.assertEqual(t.has_key(7), 5) self.assertEqual(t.has_key(7), 5)
self.assertEqual(t.has_key(11), 5) self.assertEqual(t.has_key(11), 5)
for i in 0, 2, 4, 6, 8, 9, 10, 12: for i in 0, 2, 4, 6, 8, 9, 10, 12:
self.assert_(i not in t) self.assertTrue(i not in t)
def _checkRanges(self, tree, keys): def _checkRanges(self, tree, keys):
self.assertEqual(len(tree), len(keys)) self.assertEqual(len(tree), len(keys))
...@@ -129,7 +129,7 @@ class DegenerateBTree(unittest.TestCase): ...@@ -129,7 +129,7 @@ class DegenerateBTree(unittest.TestCase):
sorted_keys.sort() sorted_keys.sort()
self.assertEqual(list(tree.keys()), sorted_keys) self.assertEqual(list(tree.keys()), sorted_keys)
for k in keys: for k in keys:
self.assert_(k in tree) self.assertTrue(k in tree)
if keys: if keys:
lokey = sorted_keys[0] lokey = sorted_keys[0]
hikey = sorted_keys[-1] hikey = sorted_keys[-1]
...@@ -206,6 +206,24 @@ class ToBeDeleted(object): ...@@ -206,6 +206,24 @@ class ToBeDeleted(object):
def __cmp__(self, other): def __cmp__(self, other):
return cmp(self.id, other.id) return cmp(self.id, other.id)
def __le__(self, other):
return self.id <= other.id
def __lt__(self, other):
return self.id < other.id
def __eq__(self, other):
return self.id == other.id
def __ne__(self, other):
return self.id != other.id
def __gt__(self, other):
return self.id > other.id
def __ge__(self, other):
return self.id >= other.id
def __hash__(self): def __hash__(self):
return hash(self.id) return hash(self.id)
...@@ -236,6 +254,8 @@ class BugFixes(unittest.TestCase): ...@@ -236,6 +254,8 @@ class BugFixes(unittest.TestCase):
import gc import gc
import random import random
from BTrees.OOBTree import OOBTree from BTrees.OOBTree import OOBTree
from .._compat import _u
from .._compat import xrange
t = OOBTree() t = OOBTree()
...@@ -257,12 +277,12 @@ class BugFixes(unittest.TestCase): ...@@ -257,12 +277,12 @@ class BugFixes(unittest.TestCase):
t[id] = ToBeDeleted(id) t[id] = ToBeDeleted(id)
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del t[id] del t[id]
del ids[id] del ids[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
ids = None ids = None
...@@ -287,15 +307,15 @@ class BugFixes(unittest.TestCase): ...@@ -287,15 +307,15 @@ class BugFixes(unittest.TestCase):
id = trandom.randint(0,1000000) id = trandom.randint(0,1000000)
ids[id] = 1 ids[id] = 1
t[id] = (id, ToBeDeleted(id), u'somename') t[id] = (id, ToBeDeleted(id), _u('somename'))
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del t[id] del t[id]
del ids[id] del ids[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
ids = None ids = None
...@@ -325,12 +345,12 @@ class BugFixes(unittest.TestCase): ...@@ -325,12 +345,12 @@ class BugFixes(unittest.TestCase):
t[id] = 1 t[id] = 1
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del ids[id] del ids[id]
del t[id] del t[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
#release all refs #release all refs
...@@ -354,18 +374,18 @@ class BugFixes(unittest.TestCase): ...@@ -354,18 +374,18 @@ class BugFixes(unittest.TestCase):
id = None id = None
while id is None or id in ids: while id is None or id in ids:
id = trandom.randint(0,1000000) id = trandom.randint(0,1000000)
id = (id, ToBeDeleted(id), u'somename') id = (id, ToBeDeleted(id), _u('somename'))
ids[id] = 1 ids[id] = 1
t[id] = 1 t[id] = 1
else: else:
#del #del
id = trandom.choice(ids.keys()) id = trandom.choice(list(ids.keys()))
del ids[id] del ids[id]
del t[id] del t[id]
ids = ids.keys() ids = ids.keys()
trandom.shuffle(ids) trandom.shuffle(list(ids))
for id in ids: for id in ids:
del t[id] del t[id]
#release all refs #release all refs
...@@ -387,7 +407,7 @@ class DoesntLikeBeingCompared: ...@@ -387,7 +407,7 @@ class DoesntLikeBeingCompared:
def __cmp__(self,other): def __cmp__(self,other):
raise ValueError('incomparable') raise ValueError('incomparable')
__lt__ = __le__ = __eq__ = __ne__ = __ge__ = __gt__ = __cmp__
class TestCmpError(unittest.TestCase): class TestCmpError(unittest.TestCase):
...@@ -397,7 +417,7 @@ class TestCmpError(unittest.TestCase): ...@@ -397,7 +417,7 @@ class TestCmpError(unittest.TestCase):
t['hello world'] = None t['hello world'] = None
try: try:
t[DoesntLikeBeingCompared()] = None t[DoesntLikeBeingCompared()] = None
except ValueError,e: except ValueError as e:
self.assertEqual(str(e), 'incomparable') self.assertEqual(str(e), 'incomparable')
else: else:
self.fail('incomarable objects should not be allowed into ' self.fail('incomarable objects should not be allowed into '
...@@ -410,22 +430,22 @@ class FamilyTest(unittest.TestCase): ...@@ -410,22 +430,22 @@ class FamilyTest(unittest.TestCase):
import BTrees import BTrees
from BTrees.IOBTree import IOTreeSet from BTrees.IOBTree import IOTreeSet
verifyObject(BTrees.Interfaces.IBTreeFamily, BTrees.family32) verifyObject(BTrees.Interfaces.IBTreeFamily, BTrees.family32)
self.assertEquals( self.assertEqual(
BTrees.family32.IO, BTrees.IOBTree) BTrees.family32.IO, BTrees.IOBTree)
self.assertEquals( self.assertEqual(
BTrees.family32.OI, BTrees.OIBTree) BTrees.family32.OI, BTrees.OIBTree)
self.assertEquals( self.assertEqual(
BTrees.family32.II, BTrees.IIBTree) BTrees.family32.II, BTrees.IIBTree)
self.assertEquals( self.assertEqual(
BTrees.family32.IF, BTrees.IFBTree) BTrees.family32.IF, BTrees.IFBTree)
self.assertEquals( self.assertEqual(
BTrees.family32.OO, BTrees.OOBTree) BTrees.family32.OO, BTrees.OOBTree)
s = IOTreeSet() s = IOTreeSet()
s.insert(BTrees.family32.maxint) s.insert(BTrees.family32.maxint)
self.assert_(BTrees.family32.maxint in s) self.assertTrue(BTrees.family32.maxint in s)
s = IOTreeSet() s = IOTreeSet()
s.insert(BTrees.family32.minint) s.insert(BTrees.family32.minint)
self.assert_(BTrees.family32.minint in s) self.assertTrue(BTrees.family32.minint in s)
s = IOTreeSet() s = IOTreeSet()
# this next bit illustrates an, um, "interesting feature". If # this next bit illustrates an, um, "interesting feature". If
# the characteristics change to match the 64 bit version, please # the characteristics change to match the 64 bit version, please
...@@ -440,22 +460,22 @@ class FamilyTest(unittest.TestCase): ...@@ -440,22 +460,22 @@ class FamilyTest(unittest.TestCase):
import BTrees import BTrees
from BTrees.LOBTree import LOTreeSet from BTrees.LOBTree import LOTreeSet
verifyObject(BTrees.Interfaces.IBTreeFamily, BTrees.family64) verifyObject(BTrees.Interfaces.IBTreeFamily, BTrees.family64)
self.assertEquals( self.assertEqual(
BTrees.family64.IO, BTrees.LOBTree) BTrees.family64.IO, BTrees.LOBTree)
self.assertEquals( self.assertEqual(
BTrees.family64.OI, BTrees.OLBTree) BTrees.family64.OI, BTrees.OLBTree)
self.assertEquals( self.assertEqual(
BTrees.family64.II, BTrees.LLBTree) BTrees.family64.II, BTrees.LLBTree)
self.assertEquals( self.assertEqual(
BTrees.family64.IF, BTrees.LFBTree) BTrees.family64.IF, BTrees.LFBTree)
self.assertEquals( self.assertEqual(
BTrees.family64.OO, BTrees.OOBTree) BTrees.family64.OO, BTrees.OOBTree)
s = LOTreeSet() s = LOTreeSet()
s.insert(BTrees.family64.maxint) s.insert(BTrees.family64.maxint)
self.assert_(BTrees.family64.maxint in s) self.assertTrue(BTrees.family64.maxint in s)
s = LOTreeSet() s = LOTreeSet()
s.insert(BTrees.family64.minint) s.insert(BTrees.family64.minint)
self.assert_(BTrees.family64.minint in s) self.assertTrue(BTrees.family64.minint in s)
s = LOTreeSet() s = LOTreeSet()
# XXX why oh why do we expect ValueError here, but TypeError in test32? # XXX why oh why do we expect ValueError here, but TypeError in test32?
self.assertRaises(ValueError, s.insert, BTrees.family64.maxint + 1) self.assertRaises(ValueError, s.insert, BTrees.family64.maxint + 1)
...@@ -468,35 +488,35 @@ class FamilyTest(unittest.TestCase): ...@@ -468,35 +488,35 @@ class FamilyTest(unittest.TestCase):
# unpickling, whether from the same unpickler or different # unpickling, whether from the same unpickler or different
# unpicklers. # unpicklers.
import pickle import pickle
import StringIO from .._compat import BytesIO
s = pickle.dumps((family, family)) s = pickle.dumps((family, family))
(f1, f2) = pickle.loads(s) (f1, f2) = pickle.loads(s)
self.failUnless(f1 is family) self.assertTrue(f1 is family)
self.failUnless(f2 is family) self.assertTrue(f2 is family)
# Using a single memo across multiple pickles: # Using a single memo across multiple pickles:
sio = StringIO.StringIO() sio = BytesIO()
p = pickle.Pickler(sio) p = pickle.Pickler(sio)
p.dump(family) p.dump(family)
p.dump([family]) p.dump([family])
u = pickle.Unpickler(StringIO.StringIO(sio.getvalue())) u = pickle.Unpickler(BytesIO(sio.getvalue()))
f1 = u.load() f1 = u.load()
f2, = u.load() f2, = u.load()
self.failUnless(f1 is family) self.assertTrue(f1 is family)
self.failUnless(f2 is family) self.assertTrue(f2 is family)
# Using separate memos for each pickle: # Using separate memos for each pickle:
sio = StringIO.StringIO() sio = BytesIO()
p = pickle.Pickler(sio) p = pickle.Pickler(sio)
p.dump(family) p.dump(family)
p.clear_memo() p.clear_memo()
p.dump([family]) p.dump([family])
u = pickle.Unpickler(StringIO.StringIO(sio.getvalue())) u = pickle.Unpickler(BytesIO(sio.getvalue()))
f1 = u.load() f1 = u.load()
f2, = u.load() f2, = u.load()
self.failUnless(f1 is family) self.assertTrue(f1 is family)
self.failUnless(f2 is family) self.assertTrue(f2 is family)
def test_suite(): def test_suite():
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
############################################################################## ##############################################################################
import unittest import unittest
from BTrees.OOBTree import OOBTree from .common import _skip_under_Py3k
# When an OOBtree contains unicode strings as keys, # When an OOBtree contains unicode strings as keys,
# it is neccessary accessing non-unicode strings are # it is neccessary accessing non-unicode strings are
...@@ -26,33 +26,40 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -26,33 +26,40 @@ class TestBTreesUnicode(unittest.TestCase):
""" test unicode""" """ test unicode"""
def setUp(self): def setUp(self):
"""setup an OOBTree with some unicode strings""" #setup an OOBTree with some unicode strings
from BTrees.OOBTree import OOBTree
from BTrees._compat import _bytes
from BTrees._compat import _u
self.s = unicode('dreit\xe4gigen', 'latin1') self.s = _u(b'dreit\xe4gigen', 'latin1')
self.data = [('alien', 1), self.data = [(b'alien', 1),
('k\xf6nnten', 2), (b'k\xf6nnten', 2),
('fox', 3), (b'fox', 3),
('future', 4), (b'future', 4),
('quick', 5), (b'quick', 5),
('zerst\xf6rt', 6), (b'zerst\xf6rt', 6),
(unicode('dreit\xe4gigen','latin1'), 7), (_u(b'dreit\xe4gigen','latin1'), 7),
] ]
self.tree = OOBTree() self.tree = OOBTree()
for k, v in self.data: for k, v in self.data:
if isinstance(k, str): if isinstance(k, _bytes):
k = unicode(k, 'latin1') k = _u(k, 'latin1')
self.tree[k] = v self.tree[k] = v
@_skip_under_Py3k
def testAllKeys(self): def testAllKeys(self):
# check every item of the tree # check every item of the tree
from BTrees._compat import _u
from BTrees._compat import _bytes
for k, v in self.data: for k, v in self.data:
if isinstance(k, str): if isinstance(k, _bytes):
k = unicode(k, encoding) k = _u(k, encoding)
self.assert_(self.tree.has_key(k)) self.assertTrue(k in self.tree)
self.assertEqual(self.tree[k], v) self.assertEqual(self.tree[k], v)
@_skip_under_Py3k
def testUnicodeKeys(self): def testUnicodeKeys(self):
# try to access unicode keys in tree # try to access unicode keys in tree
k, v = self.data[-1] k, v = self.data[-1]
...@@ -60,10 +67,11 @@ class TestBTreesUnicode(unittest.TestCase): ...@@ -60,10 +67,11 @@ class TestBTreesUnicode(unittest.TestCase):
self.assertEqual(self.tree[k], v) self.assertEqual(self.tree[k], v)
self.assertEqual(self.tree[self.s], v) self.assertEqual(self.tree[self.s], v)
@_skip_under_Py3k
def testAsciiKeys(self): def testAsciiKeys(self):
# try to access some "plain ASCII" keys in the tree # try to access some "plain ASCII" keys in the tree
for k, v in self.data[0], self.data[2]: for k, v in self.data[0], self.data[2]:
self.assert_(isinstance(k, str)) self.assertTrue(isinstance(k, str))
self.assertEqual(self.tree[k], v) self.assertEqual(self.tree[k], v)
def test_suite(): def test_suite():
......
...@@ -136,7 +136,7 @@ class NastyConfictFunctionalTests(ConflictTestBase, unittest.TestCase): ...@@ -136,7 +136,7 @@ class NastyConfictFunctionalTests(ConflictTestBase, unittest.TestCase):
numtoadd = 16 numtoadd = 16
candidate = 60 candidate = 60
while numtoadd: while numtoadd:
if not b.has_key(candidate): if candidate not in b:
b[candidate] = candidate b[candidate] = candidate
numtoadd -= 1 numtoadd -= 1
candidate += 1 candidate += 1
...@@ -332,10 +332,10 @@ class NastyConfictFunctionalTests(ConflictTestBase, unittest.TestCase): ...@@ -332,10 +332,10 @@ class NastyConfictFunctionalTests(ConflictTestBase, unittest.TestCase):
state1 = bucket.__getstate__() state1 = bucket.__getstate__()
state2 = bucket.__getstate__() state2 = bucket.__getstate__()
state3 = bucket.__getstate__() state3 = bucket.__getstate__()
self.assert_(state2 is not state1 and self.assertTrue(state2 is not state1 and
state2 is not state3 and state2 is not state3 and
state3 is not state1) state3 is not state1)
self.assert_(state2 == state1 and self.assertTrue(state2 == state1 and
state3 == state1) state3 == state1)
self.assertRaises(BTreesConflictError, bucket._p_resolveConflict, self.assertRaises(BTreesConflictError, bucket._p_resolveConflict,
state1, state2, state3) state1, state2, state3)
......
...@@ -53,24 +53,42 @@ class LengthTestCase(unittest.TestCase): ...@@ -53,24 +53,42 @@ class LengthTestCase(unittest.TestCase):
length = self._makeOne() length = self._makeOne()
self.assertEqual(length._p_resolveConflict(5, 7, 9), 11) self.assertEqual(length._p_resolveConflict(5, 7, 9), 11)
def test_change_w_positive_delta(self):
length = self._makeOne()
length.change(3)
self.assertEqual(length.value, 3)
def test_change_w_negative_delta(self):
length = self._makeOne()
length.change(-3)
self.assertEqual(length.value, -3)
def test_change_overflows_to_long(self): def test_change_overflows_to_long(self):
import sys import sys
try:
length = self._makeOne(sys.maxint) length = self._makeOne(sys.maxint)
except AttributeError: #pragma NO COVER Py3k
return
else: #pragma NO COVER Py2
self.assertEqual(length(), sys.maxint) self.assertEqual(length(), sys.maxint)
self.assert_(type(length()) is int) self.assertTrue(type(length()) is int)
length.change(+1) length.change(+1)
self.assertEqual(length(), sys.maxint + 1) self.assertEqual(length(), sys.maxint + 1)
self.assert_(type(length()) is long) self.assertTrue(type(length()) is long)
def test_change_underflows_to_long(self): def test_change_underflows_to_long(self):
import sys import sys
try:
minint = (-sys.maxint) - 1 minint = (-sys.maxint) - 1
except AttributeError: #pragma NO COVER Py3k
return
else: #pragma NO COVER Py2
length = self._makeOne(minint) length = self._makeOne(minint)
self.assertEqual(length(), minint) self.assertEqual(length(), minint)
self.assert_(type(length()) is int) self.assertTrue(type(length()) is int)
length.change(-1) length.change(-1)
self.assertEqual(length(), minint - 1) self.assertEqual(length(), minint - 1)
self.assert_(type(length()) is long) self.assertTrue(type(length()) is long)
def test___call___no_args(self): def test___call___no_args(self):
length = self._makeOne(42) length = self._makeOne(42)
......
...@@ -143,6 +143,7 @@ class _TestOIBTreesBase(TypeTest): ...@@ -143,6 +143,7 @@ class _TestOIBTreesBase(TypeTest):
self._makeOne()[1] = None self._makeOne()[1] = None
def testEmptyFirstBucketReportedByGuido(self): def testEmptyFirstBucketReportedByGuido(self):
from .._compat import xrange
b = self._makeOne() b = self._makeOne()
for i in xrange(29972): # reduce to 29971 and it works for i in xrange(29972): # reduce to 29971 and it works
b[i] = i b[i] = i
......
...@@ -112,6 +112,7 @@ class OOBTreeTest(BTreeTests, unittest.TestCase): ...@@ -112,6 +112,7 @@ class OOBTreeTest(BTreeTests, unittest.TestCase):
# used in a function that's used in lots of places. # used in a function that's used in lots of places.
# Otherwise, there are many permutations that would have to be # Otherwise, there are many permutations that would have to be
# checked. # checked.
from .._compat import PY2
t = self._makeOne() t = self._makeOne()
class C(object): class C(object):
...@@ -119,30 +120,31 @@ class OOBTreeTest(BTreeTests, unittest.TestCase): ...@@ -119,30 +120,31 @@ class OOBTreeTest(BTreeTests, unittest.TestCase):
self.assertRaises(TypeError, lambda : t.__setitem__(C(), 1)) self.assertRaises(TypeError, lambda : t.__setitem__(C(), 1))
class C(object): if PY2: # we only check for __cmp__ on Python2
class With___cmp__(object):
def __cmp__(*args): def __cmp__(*args):
return 1 return 1
c = With___cmp__()
c = C()
t[c] = 1 t[c] = 1
t.clear() t.clear()
class C(object): class With___lt__(object):
def __lt__(*args): def __lt__(*args):
return 1 return 1
c = C() c = With___lt__()
t[c] = 1 t[c] = 1
t.clear() t.clear()
#class OOBTreePyTest(OOBTreeTest): class OOBTreePyTest(OOBTreeTest):
# #
# Right now, we can't match the C extension's test / prohibition of the # Right now, we can't match the C extension's test / prohibition of the
# default 'object' comparison semantics. # default 'object' comparison semantics.
class OOBTreePyTest(BTreeTests, unittest.TestCase): #class OOBTreePyTest(BTreeTests, unittest.TestCase):
def _makeOne(self): def _makeOne(self):
from BTrees.OOBTree import OOBTreePy from BTrees.OOBTree import OOBTreePy
......
...@@ -640,7 +640,7 @@ class BucketTests(unittest.TestCase): ...@@ -640,7 +640,7 @@ class BucketTests(unittest.TestCase):
bucket = self._makeOne() bucket = self._makeOne()
for i, c in enumerate('abcdef'): for i, c in enumerate('abcdef'):
bucket[c] = i bucket[c] = i
self.assertEqual(bucket.values(), range(6)) self.assertEqual(bucket.values(), list(range(6)))
def test_values_filled_w_args(self): def test_values_filled_w_args(self):
bucket = self._makeOne() bucket = self._makeOne()
...@@ -657,7 +657,7 @@ class BucketTests(unittest.TestCase): ...@@ -657,7 +657,7 @@ class BucketTests(unittest.TestCase):
bucket = self._makeOne() bucket = self._makeOne()
for i, c in enumerate('abcdef'): for i, c in enumerate('abcdef'):
bucket[c] = i bucket[c] = i
self.assertEqual(list(bucket.itervalues()), range(6)) self.assertEqual(list(bucket.itervalues()), list(range(6)))
def test_itervalues_filled_w_args(self): def test_itervalues_filled_w_args(self):
bucket = self._makeOne() bucket = self._makeOne()
...@@ -1783,8 +1783,8 @@ class Test_Tree(unittest.TestCase): ...@@ -1783,8 +1783,8 @@ class Test_Tree(unittest.TestCase):
def test__set_calls_readCurrent_on_jar(self): def test__set_calls_readCurrent_on_jar(self):
tree = self._makeOne() tree = self._makeOne()
tree._p_oid = 'OID' tree._p_oid = b'OID'
tree._p_serial = '01234567' tree._p_serial = b'01234567'
tree._p_jar = jar = _Jar() tree._p_jar = jar = _Jar()
tree._set('a', 'b') tree._set('a', 'b')
self.assertTrue(tree in jar._current) self.assertTrue(tree in jar._current)
...@@ -1839,8 +1839,8 @@ class Test_Tree(unittest.TestCase): ...@@ -1839,8 +1839,8 @@ class Test_Tree(unittest.TestCase):
def test__del_calls_readCurrent_on_jar(self): def test__del_calls_readCurrent_on_jar(self):
tree = self._makeOne({'a': 'b'}) tree = self._makeOne({'a': 'b'})
tree._p_oid = 'OID' tree._p_oid = b'OID'
tree._p_serial = '01234567' tree._p_serial = b'01234567'
tree._p_jar = jar = _Jar() tree._p_jar = jar = _Jar()
tree._del('a') tree._del('a')
self.assertTrue(tree in jar._current) self.assertTrue(tree in jar._current)
...@@ -1898,7 +1898,7 @@ class Test_Tree(unittest.TestCase): ...@@ -1898,7 +1898,7 @@ class Test_Tree(unittest.TestCase):
bucket = tree._firstbucket bucket = tree._firstbucket
jar = _Jar() jar = _Jar()
bucket._p_jar = jar bucket._p_jar = jar
bucket._p_oid = 'OID' bucket._p_oid = b'OID'
self.assertEqual(tree.__getstate__(), ((bucket,), bucket)) self.assertEqual(tree.__getstate__(), ((bucket,), bucket))
def test___getstate___multiple_buckets(self): def test___getstate___multiple_buckets(self):
...@@ -2273,7 +2273,7 @@ class TreeTests(unittest.TestCase): ...@@ -2273,7 +2273,7 @@ class TreeTests(unittest.TestCase):
def test_values_filled_no_args(self): def test_values_filled_no_args(self):
ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')] ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')]
tree = self._makeOne(ITEMS) tree = self._makeOne(ITEMS)
self.assertEqual(list(tree.values()), range(26)) self.assertEqual(list(tree.values()), list(range(26)))
def test_values_filled_w_args(self): def test_values_filled_w_args(self):
ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')] ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')]
...@@ -2289,7 +2289,7 @@ class TreeTests(unittest.TestCase): ...@@ -2289,7 +2289,7 @@ class TreeTests(unittest.TestCase):
def test_itervalues_filled_no_args(self): def test_itervalues_filled_no_args(self):
ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')] ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')]
tree = self._makeOne(ITEMS) tree = self._makeOne(ITEMS)
self.assertEqual(list(tree.itervalues()), range(26)) self.assertEqual(list(tree.itervalues()), list(range(26)))
def test_itervalues_filled_w_args(self): def test_itervalues_filled_w_args(self):
ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')] ITEMS = [(y, x) for x, y in enumerate('abcdefghijklmnopqrstuvwxyz')]
...@@ -2634,6 +2634,28 @@ class Test_weightedUnion(unittest.TestCase, _SetObBase): ...@@ -2634,6 +2634,28 @@ class Test_weightedUnion(unittest.TestCase, _SetObBase):
rhs = self._makeSet('a', 'b', 'c') rhs = self._makeSet('a', 'b', 'c')
self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs) self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs)
def test_lhs_mapping_wo_MERGE_DEFAULT_rhs_set(self):
class _MappingWoDefault(dict):
def MERGE(self, v1, w1, v2, w2):
return (v1 * w1) + (v2 * w2)
def MERGE_WEIGHT(self, v, w):
return v
lhs = _MappingWoDefault({'a': 13, 'b': 12, 'c': 11})
lhs._mapping_type = _MappingWoDefault
rhs = self._makeSet('a', 'b', 'c')
self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs)
def test_lhs_mapping_wo_MERGE_rhs_mapping(self):
class _MappingWoMerge(dict):
def MERGE_DEFAULT(self):
return 1
def MERGE_WEIGHT(self, v, w):
return v
lhs = _MappingWoMerge({'a': 13, 'b': 12, 'c': 11})
lhs._mapping_type = _MappingWoMerge
rhs = self._makeMapping({'a': 1, 'b': 2, 'c': 3})
self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs)
def test_lhs_set_wo_MERGE_DEFAULT_rhs_mapping(self): def test_lhs_set_wo_MERGE_DEFAULT_rhs_mapping(self):
lhs = self._makeSet('a', 'd') lhs = self._makeSet('a', 'd')
lhs.MERGE = lambda v1, w1, v2, w2: (v1 * w1) + (v2 * w2) lhs.MERGE = lambda v1, w1, v2, w2: (v1 * w1) + (v2 * w2)
...@@ -2725,6 +2747,17 @@ class Test_weightedIntersection(unittest.TestCase, _SetObBase): ...@@ -2725,6 +2747,17 @@ class Test_weightedIntersection(unittest.TestCase, _SetObBase):
rhs = {'b': 22, 'd': 14} rhs = {'b': 22, 'd': 14}
self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs) self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs)
def test_lhs_mapping_wo_MERGE_rhs_mapping(self):
class _MappingWoMerge(dict):
def MERGE_DEFAULT(self):
return 1
def MERGE_WEIGHT(self, v, w):
return v
lhs = _MappingWoMerge({'a': 13, 'b': 12, 'c': 11})
lhs._mapping_type = _MappingWoMerge
rhs = self._makeMapping({'a': 1, 'b': 2, 'c': 3})
self.assertRaises(TypeError, self._callFUT, lhs.__class__, lhs, rhs)
def test_lhs_set_wo_MERGE_DEFAULT_rhs_set(self): def test_lhs_set_wo_MERGE_DEFAULT_rhs_set(self):
lhs = self._makeSet('a', 'd') lhs = self._makeSet('a', 'd')
lhs.MERGE = lambda v1, w1, v2, w2: (v1 * w1) + (v2 * w2) lhs.MERGE = lambda v1, w1, v2, w2: (v1 * w1) + (v2 * w2)
...@@ -2824,7 +2857,10 @@ class Test_helpers(unittest.TestCase): ...@@ -2824,7 +2857,10 @@ class Test_helpers(unittest.TestCase):
import sys import sys
from BTrees._base import to_int from BTrees._base import to_int
faux_self = object() faux_self = object()
try:
self.assertRaises(TypeError, to_int, faux_self, sys.maxint + 1) self.assertRaises(TypeError, to_int, faux_self, sys.maxint + 1)
except AttributeError: #pragma NO COVER Py3k
pass
def test_to_int_w_invalid(self): def test_to_int_w_invalid(self):
from BTrees._base import to_int from BTrees._base import to_int
...@@ -2863,25 +2899,28 @@ class Test_helpers(unittest.TestCase): ...@@ -2863,25 +2899,28 @@ class Test_helpers(unittest.TestCase):
import sys import sys
from BTrees._base import to_long from BTrees._base import to_long
faux_self = object() faux_self = object()
try:
self.assertRaises(ValueError, to_long, faux_self, sys.maxint + 1) self.assertRaises(ValueError, to_long, faux_self, sys.maxint + 1)
except AttributeError: #pragma NO COVER Py3k
pass
def test_to_long_w_invalid(self): def test_to_long_w_invalid(self):
from BTrees._base import to_long from BTrees._base import to_long
faux_self = object() faux_self = object()
self.assertRaises(TypeError, to_long, faux_self, ()) self.assertRaises(TypeError, to_long, faux_self, ())
def test_to_str_w_ok(self): def test_to_bytes_w_ok(self):
from BTrees._base import to_str from BTrees._base import to_bytes
faux_self = object() faux_self = object()
conv = to_str(3) conv = to_bytes(3)
self.assertEqual(conv(faux_self, 'abc'), 'abc') self.assertEqual(conv(faux_self, b'abc'), b'abc')
def test_to_str_w_invalid_length(self): def test_to_bytes_w_invalid_length(self):
from BTrees._base import to_str from BTrees._base import to_bytes
faux_self = object() faux_self = object()
conv = to_str(3) conv = to_bytes(3)
self.assertRaises(TypeError, conv, faux_self, 'ab') self.assertRaises(TypeError, conv, faux_self, b'ab')
self.assertRaises(TypeError, conv, faux_self, 'abcd') self.assertRaises(TypeError, conv, faux_self, b'abcd')
def test_MERGE(self): def test_MERGE(self):
from BTrees._base import MERGE from BTrees._base import MERGE
......
...@@ -38,7 +38,7 @@ class SubclassTest(unittest.TestCase): ...@@ -38,7 +38,7 @@ class SubclassTest(unittest.TestCase):
t[i] = i t[i] = i
state = t.__getstate__() state = t.__getstate__()
self.assert_(state[0][0].__class__ is B) self.assertTrue(state[0][0].__class__ is B)
def test_suite(): def test_suite():
return unittest.makeSuite(SubclassTest) return unittest.makeSuite(SubclassTest)
...@@ -149,10 +149,10 @@ class Test_type_and_adr(unittest.TestCase): ...@@ -149,10 +149,10 @@ class Test_type_and_adr(unittest.TestCase):
def test_type_and_adr_w_oid(self): def test_type_and_adr_w_oid(self):
from BTrees.utils import oid_repr from BTrees.utils import oid_repr
class WithOid(object): class WithOid(object):
_p_oid = 'DEADBEEF' _p_oid = b'DEADBEEF'
t_and_a = self._callFUT(WithOid()) t_and_a = self._callFUT(WithOid())
self.assertTrue(t_and_a.startswith('WithOid (0x')) self.assertTrue(t_and_a.startswith('WithOid (0x'))
self.assertTrue(t_and_a.endswith('oid=%s)' % oid_repr('DEADBEEF'))) self.assertTrue(t_and_a.endswith('oid=%s)' % oid_repr(b'DEADBEEF')))
def test_type_and_adr_wo_oid(self): def test_type_and_adr_wo_oid(self):
class WithoutOid(object): class WithoutOid(object):
......
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Test errors during comparison of BTree keys."""
import unittest
STR = "A string with hi-bit-set characters: \700\701"
UNICODE = u"A unicode string"
class CompareTest(unittest.TestCase):
def setUp(self):
# These defaults only make sense if the default encoding
# prevents STR from being promoted to Unicode.
self.assertRaises(UnicodeError, unicode, STR)
def _makeBucket(self):
from BTrees.OOBTree import OOBucket
return OOBucket()
def _makeSet(self):
from BTrees.OOBTree import OOSet
return OOSet()
def assertUE(self, callable, *args):
self.assertRaises(UnicodeError, callable, *args)
def testBucketGet(self):
import warnings
b = self._makeBucket()
with warnings.catch_warnings(True) as _warnlog:
b[STR] = 1
self.assertUE(b.get, UNICODE)
self.assertEqual(len(_warnlog), 1)
def testSetGet(self):
s = self._makeSet()
s.insert(STR)
self.assertUE(s.remove, UNICODE)
def testBucketSet(self):
b = self._makeBucket()
b[STR] = 1
self.assertUE(b.__setitem__, UNICODE, 1)
def testSetSet(self):
s = self._makeSet()
s.insert(STR)
self.assertUE(s.insert, UNICODE)
def testBucketMinKey(self):
b = self._makeBucket()
b[STR] = 1
self.assertUE(b.minKey, UNICODE)
def testSetMinKey(self):
s = self._makeSet()
s.insert(STR)
self.assertUE(s.minKey, UNICODE)
def test_suite():
return unittest.makeSuite(CompareTest)
...@@ -14,54 +14,51 @@ ...@@ -14,54 +14,51 @@
import unittest import unittest
class fsBucketTests(unittest.TestCase): class fsBucketBase(object):
def _getTargetClass(self):
from BTrees.fsBTree import fsBucket
return fsBucket
def _makeOne(self, *args, **kw): def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw) return self._getTargetClass()(*args, **kw)
def test_MERGE_WEIGHT(self): def _makeBytesItems(self):
bucket = self._makeOne() from .._compat import _ascii
self.assertEqual(bucket.MERGE_WEIGHT(42, 17), 42) return[(_ascii(c*2), _ascii(c*6)) for c in 'abcdef']
def test_toString(self): def test_toString(self):
bucket = self._makeOne([(c*2, c*6) for c in 'abcdef']) bucket = self._makeOne(self._makeBytesItems())
self.assertEqual(bucket.toString(), self.assertEqual(bucket.toString(),
'aabbccddeeffaaaaaabbbbbbccccccddddddeeeeeeffffff') b'aabbccddeeffaaaaaabbbbbbccccccddddddeeeeeeffffff')
def test_fromString(self): def test_fromString(self):
before = self._makeOne([(c*2, c*6) for c in 'abcdef']) before = self._makeOne(self._makeBytesItems())
after = before.fromString(before.toString()) after = before.fromString(before.toString())
self.assertEqual(before.__getstate__(), after.__getstate__()) self.assertEqual(before.__getstate__(), after.__getstate__())
def test_fromString_empty(self): def test_fromString_empty(self):
before = self._makeOne([(c*2, c*6) for c in 'abcdef']) before = self._makeOne(self._makeBytesItems())
after = before.fromString('') after = before.fromString(b'')
self.assertEqual(after.__getstate__(), ((),)) self.assertEqual(after.__getstate__(), ((),))
def test_fromString_invalid(self): def test_fromString_invalid_length(self):
bucket = self._makeOne([(c*2, c*6) for c in 'abcdef']) bucket = self._makeOne(self._makeBytesItems())
self.assertRaises(ValueError, bucket.fromString, 'xxx') self.assertRaises(ValueError, bucket.fromString, b'xxx')
class fsBTreeTests(unittest.TestCase): class fsBucketTests(unittest.TestCase, fsBucketBase):
def _getTargetClass(self): def _getTargetClass(self):
from BTrees.fsBTree import fsBTree from BTrees.fsBTree import fsBucket
return fsBTree return fsBucket
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def test_MERGE_WEIGHT(self): class fsBucketPyTests(unittest.TestCase, fsBucketBase):
bucket = self._makeOne()
self.assertEqual(bucket.MERGE_WEIGHT(42, 17), 42) def _getTargetClass(self):
from BTrees.fsBTree import fsBucketPy
return fsBucketPy
def test_suite(): def test_suite():
return unittest.TestSuite(( return unittest.TestSuite((
unittest.makeSuite(fsBucketTests), unittest.makeSuite(fsBucketTests),
unittest.makeSuite(fsBucketPyTests),
)) ))
...@@ -22,11 +22,17 @@ class Test_non_negative(unittest.TestCase): ...@@ -22,11 +22,17 @@ class Test_non_negative(unittest.TestCase):
def test_w_big_negative(self): def test_w_big_negative(self):
import sys import sys
try:
self.assertEqual(self._callFUT(-sys.maxint), 1) self.assertEqual(self._callFUT(-sys.maxint), 1)
except AttributeError: #pragma NO COVER Py3k
pass
def test_w_negative(self): def test_w_negative(self):
import sys import sys
try:
self.assertEqual(self._callFUT(-1), sys.maxint) self.assertEqual(self._callFUT(-1), sys.maxint)
except AttributeError: #pragma NO COVER Py3k
pass
def test_w_zero(self): def test_w_zero(self):
self.assertEqual(self._callFUT(0), 0) self.assertEqual(self._callFUT(0), 0)
...@@ -36,7 +42,10 @@ class Test_non_negative(unittest.TestCase): ...@@ -36,7 +42,10 @@ class Test_non_negative(unittest.TestCase):
def test_w_big_positive(self): def test_w_big_positive(self):
import sys import sys
try:
self.assertEqual(self._callFUT(sys.maxint), sys.maxint) self.assertEqual(self._callFUT(sys.maxint), sys.maxint)
except AttributeError: #pragma NO COVER Py3k
pass
class Test_oid_repr(unittest.TestCase): class Test_oid_repr(unittest.TestCase):
...@@ -63,16 +72,16 @@ class Test_oid_repr(unittest.TestCase): ...@@ -63,16 +72,16 @@ class Test_oid_repr(unittest.TestCase):
self.assertEqual(self._callFUT(faux), repr(faux)) self.assertEqual(self._callFUT(faux), repr(faux))
def test_w_zero(self): def test_w_zero(self):
self.assertEqual(self._callFUT('\0\0\0\0\0\0\0\0'), '0x00') self.assertEqual(self._callFUT(b'\0\0\0\0\0\0\0\0'), b'0x00')
def test_w_one(self): def test_w_one(self):
self.assertEqual(self._callFUT('\0\0\0\0\0\0\0\1'), '0x01') self.assertEqual(self._callFUT(b'\0\0\0\0\0\0\0\1'), b'0x01')
def test_w_even_length(self): def test_w_even_length(self):
self.assertEqual(self._callFUT('\0\0\0\0\0\0\xAB\xC4'), '0xabc4') self.assertEqual(self._callFUT(b'\0\0\0\0\0\0\xAB\xC4'), b'0xabc4')
def test_w_odd_length(self): def test_w_odd_length(self):
self.assertEqual(self._callFUT('\0\0\0\0\0\0\x0D\xEF'), '0x0def') self.assertEqual(self._callFUT(b'\0\0\0\0\0\0\x0D\xEF'), b'0x0def')
def test_suite(): def test_suite():
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
from binascii import hexlify from binascii import hexlify
from ._compat import _bytes
def non_negative(int_val): def non_negative(int_val):
if int_val < 0: if int_val < 0:
# Coerce to non-negative. # Coerce to non-negative.
...@@ -28,14 +30,16 @@ def positive_id(obj): #pragma NO COVER ...@@ -28,14 +30,16 @@ def positive_id(obj): #pragma NO COVER
def oid_repr(oid): def oid_repr(oid):
if isinstance(oid, str) and len(oid) == 8: if isinstance(oid, _bytes) and len(oid) == 8:
# Convert to hex and strip leading zeroes. # Convert to hex and strip leading zeroes.
as_hex = hexlify(oid).lstrip('0') as_hex = hexlify(oid).lstrip(b'0')
# Ensure two characters per input byte. # Ensure two characters per input byte.
chunks = [b'0x']
if len(as_hex) & 1: if len(as_hex) & 1:
as_hex = '0' + as_hex chunks.append(b'0')
elif as_hex == '': elif as_hex == b'':
as_hex = '00' as_hex = b'00'
return '0x' + as_hex chunks.append(as_hex)
return b''.join(chunks)
else: else:
return repr(oid) return repr(oid)
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
4.0.2 (unreleased) 4.0.2 (unreleased)
------------------ ------------------
- Added explicit support for Python 3.2, Python 3.3, and PyPy.
Note that the C extensions are not (yet) available on PyPy.
- Python reference implementations now tested separately from the C - Python reference implementations now tested separately from the C
verions on all platforms. verions on all platforms.
......
...@@ -100,16 +100,22 @@ is_jython = 'java' in sys.platform ...@@ -100,16 +100,22 @@ is_jython = 'java' in sys.platform
# Jython cannot build the C optimizations, while on PyPy they are # Jython cannot build the C optimizations, while on PyPy they are
# anti-optimizations (the C extension compatibility layer is known-slow, # anti-optimizations (the C extension compatibility layer is known-slow,
# and defeats JIT opportunities). # and defeats JIT opportunities).
if pure_python or is_pypy or is_jython or sys.version_info[0] > 2: if pure_python or is_pypy or is_jython:
ext_modules = [] ext_modules = []
else: else:
ext_modules = [BTreeExtension(family) for family in FAMILIES] ext_modules = [BTreeExtension(family) for family in FAMILIES]
REQUIRES = [ if sys.version_info[0] > 3:
REQUIRES = [
'persistent>=4.0.4',
'zope.interface',
]
else:
REQUIRES = [
'persistent', 'persistent',
'zope.interface', 'zope.interface',
] ]
TESTS_REQUIRE = REQUIRES + ['transaction'] TESTS_REQUIRE = REQUIRES + ['transaction']
setup(name='BTrees', setup(name='BTrees',
...@@ -123,8 +129,9 @@ setup(name='BTrees', ...@@ -123,8 +129,9 @@ setup(name='BTrees',
'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
#'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
#'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
"Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Database", "Topic :: Database",
......
...@@ -3,7 +3,7 @@ envlist = ...@@ -3,7 +3,7 @@ envlist =
# Jython support pending 2.7 support, due 2012-07-15 or so. See: # Jython support pending 2.7 support, due 2012-07-15 or so. See:
# http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html # http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html
# py26,py27,py32,jython,pypy,coverage,docs # py26,py27,py32,jython,pypy,coverage,docs
py26,py27,pypy,w_zodb,coverage,docs py26,py27,pypy,py32,py33,w_zodb,coverage,docs
[testenv] [testenv]
deps = deps =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment