Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
BTrees
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
BTrees
Commits
f108be3a
Commit
f108be3a
authored
Dec 12, 2012
by
Tres Seaver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
All modules compiling under Py3k.
parent
6cb58ca0
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
3602 additions
and
3192 deletions
+3602
-3192
BTrees/BTreeItemsTemplate.c
BTrees/BTreeItemsTemplate.c
+349
-309
BTrees/BTreeModuleTemplate.c
BTrees/BTreeModuleTemplate.c
+84
-45
BTrees/BTreeTemplate.c
BTrees/BTreeTemplate.c
+1569
-1393
BTrees/BucketTemplate.c
BTrees/BucketTemplate.c
+1159
-1069
BTrees/SetTemplate.c
BTrees/SetTemplate.c
+199
-185
BTrees/TreeSetTemplate.c
BTrees/TreeSetTemplate.c
+145
-134
BTrees/_compat.h
BTrees/_compat.h
+47
-0
BTrees/_fsBTree.c
BTrees/_fsBTree.c
+12
-12
BTrees/floatvaluemacros.h
BTrees/floatvaluemacros.h
+1
-1
BTrees/intkeymacros.h
BTrees/intkeymacros.h
+5
-5
BTrees/intvaluemacros.h
BTrees/intvaluemacros.h
+4
-4
BTrees/objectkeymacros.h
BTrees/objectkeymacros.h
+16
-17
BTrees/objectvaluemacros.h
BTrees/objectvaluemacros.h
+1
-2
BTrees/py24compat.h
BTrees/py24compat.h
+0
-11
setup.py
setup.py
+11
-5
No files found.
BTrees/BTreeItemsTemplate.c
View file @
f108be3a
...
...
@@ -41,7 +41,8 @@
* a search finger weren't being used at all, but is still quadratic time
* in the number of buckets in the slice.
*/
typedef
struct
{
typedef
struct
{
PyObject_HEAD
Bucket
*
firstbucket
;
/* First bucket */
Bucket
*
currentbucket
;
/* Current bucket (search finger) */
...
...
@@ -90,7 +91,8 @@ BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero)
Py_INCREF
(
b
);
PER_USE_OR_RETURN
(
b
,
-
1
);
while
((
next
=
b
->
next
))
{
while
((
next
=
b
->
next
))
{
r
+=
b
->
len
;
if
(
nonzero
&&
r
>
0
)
/* Short-circuit if all we care about is nonempty */
...
...
@@ -141,10 +143,12 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
pseudoindex
=
self
->
pseudoindex
;
currentoffset
=
self
->
currentoffset
;
currentbucket
=
self
->
currentbucket
;
if
(
currentbucket
==
NULL
)
goto
no_match
;
if
(
currentbucket
==
NULL
)
goto
no_match
;
delta
=
i
-
pseudoindex
;
while
(
delta
>
0
)
{
/* move right */
while
(
delta
>
0
)
/* move right */
{
int
max
;
/* Want to move right delta positions; the most we can move right in
* this bucket is currentbucket->len - currentoffset - 1 positions.
...
...
@@ -153,34 +157,41 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
max
=
currentbucket
->
len
-
currentoffset
-
1
;
b
=
currentbucket
->
next
;
PER_UNUSE
(
currentbucket
);
if
(
delta
<=
max
)
{
if
(
delta
<=
max
)
{
currentoffset
+=
delta
;
pseudoindex
+=
delta
;
if
(
currentbucket
==
self
->
lastbucket
&&
currentoffset
>
self
->
last
)
goto
no_match
;
&&
currentoffset
>
self
->
last
)
goto
no_match
;
break
;
}
/* 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
;
pseudoindex
+=
max
+
1
;
delta
-=
max
+
1
;
currentoffset
=
0
;
}
while
(
delta
<
0
)
{
/* move left */
while
(
delta
<
0
)
/* move left */
{
int
status
;
/* Want to move left -delta positions; the most we can move left in
* this bucket is currentoffset positions.
*/
if
((
-
delta
)
<=
currentoffset
)
{
if
((
-
delta
)
<=
currentoffset
)
{
currentoffset
+=
delta
;
pseudoindex
+=
delta
;
if
(
currentbucket
==
self
->
firstbucket
&&
currentoffset
<
self
->
first
)
goto
no_match
;
&&
currentoffset
<
self
->
first
)
goto
no_match
;
break
;
}
/* 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
);
if
(
status
==
0
)
goto
no_match
;
...
...
@@ -202,7 +213,8 @@ BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
PER_USE_OR_RETURN
(
currentbucket
,
-
1
);
error
=
currentoffset
<
0
||
currentoffset
>=
currentbucket
->
len
;
PER_UNUSE
(
currentbucket
);
if
(
error
)
{
if
(
error
)
{
PyErr_SetString
(
PyExc_RuntimeError
,
"the bucket being iterated changed size"
);
return
-
1
;
...
...
@@ -232,8 +244,8 @@ getBucketEntry(Bucket *b, int i, char kind)
assert
(
b
);
assert
(
0
<=
i
&&
i
<
b
->
len
);
switch
(
kind
)
{
switch
(
kind
)
{
case
'k'
:
COPY_KEY_TO_OBJECT
(
result
,
b
->
keys
[
i
]);
break
;
...
...
@@ -242,25 +254,30 @@ getBucketEntry(Bucket *b, int i, char kind)
COPY_VALUE_TO_OBJECT
(
result
,
b
->
values
[
i
]);
break
;
case
'i'
:
{
case
'i'
:
{
PyObject
*
key
;
PyObject
*
value
;;
COPY_KEY_TO_OBJECT
(
key
,
b
->
keys
[
i
]);
if
(
!
key
)
break
;
if
(
!
key
)
break
;
COPY_VALUE_TO_OBJECT
(
value
,
b
->
values
[
i
]);
if
(
!
value
)
{
if
(
!
value
)
{
Py_DECREF
(
key
);
break
;
}
result
=
PyTuple_New
(
2
);
if
(
result
)
{
if
(
result
)
{
PyTuple_SET_ITEM
(
result
,
0
,
key
);
PyTuple_SET_ITEM
(
result
,
1
,
value
);
}
else
{
else
{
Py_DECREF
(
key
);
Py_DECREF
(
value
);
}
...
...
@@ -289,7 +306,8 @@ BTreeItems_item(BTreeItems *self, Py_ssize_t i)
{
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
);
result
=
getBucketEntry
(
self
->
currentbucket
,
self
->
currentoffset
,
...
...
@@ -334,7 +352,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
*/
if
(
ilow
<
0
)
ilow
=
0
;
else
{
else
{
if
(
length
<
0
)
length
=
BTreeItems_length
(
self
);
if
(
ilow
>
length
)
...
...
@@ -343,7 +362,8 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
if
(
ihigh
<
ilow
)
ihigh
=
ilow
;
else
{
else
{
if
(
length
<
0
)
length
=
BTreeItems_length
(
self
);
if
(
ihigh
>
length
)
...
...
@@ -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.
* It seems simplest to deal with empty slices as a special case here.
*/
if
(
ilow
==
ihigh
)
{
/* empty slice */
if
(
ilow
==
ihigh
)
/* empty slice */
{
lowbucket
=
highbucket
=
NULL
;
lowoffset
=
1
;
highoffset
=
0
;
}
else
{
else
{
assert
(
ilow
<
ihigh
);
--
ihigh
;
/* exclusive -> inclusive */
if
(
BTreeItems_seek
(
self
,
ilow
)
<
0
)
return
NULL
;
if
(
BTreeItems_seek
(
self
,
ilow
)
<
0
)
return
NULL
;
lowbucket
=
self
->
currentbucket
;
lowoffset
=
self
->
currentoffset
;
if
(
BTreeItems_seek
(
self
,
ihigh
)
<
0
)
return
NULL
;
if
(
BTreeItems_seek
(
self
,
ihigh
)
<
0
)
return
NULL
;
highbucket
=
self
->
currentbucket
;
highoffset
=
self
->
currentoffset
;
...
...
@@ -385,12 +408,13 @@ BTreeItems_slice(BTreeItems *self, Py_ssize_t ilow, Py_ssize_t ihigh)
lowbucket
,
lowoffset
,
highbucket
,
highoffset
);
}
static
PySequenceMethods
BTreeItems_as_sequence
=
{
(
lenfunc
)
BTreeItems_length
,
(
binaryfunc
)
0
,
(
ssizeargfunc
)
0
,
(
ssizeargfunc
)
BTreeItems_item
,
(
ssizessizeargfunc
)
BTreeItems_slice
,
static
PySequenceMethods
BTreeItems_as_sequence
=
{
(
lenfunc
)
BTreeItems_length
,
/* sq_length */
(
binaryfunc
)
0
,
/* sq_concat */
(
ssizeargfunc
)
0
,
/* sq_repeat */
(
ssizeargfunc
)
BTreeItems_item
,
/* sq_item */
(
ssizessizeargfunc
)
BTreeItems_slice
,
/* sq_slice */
};
/* Number Method items (just for nb_nonzero!) */
...
...
@@ -402,31 +426,41 @@ BTreeItems_nonzero(BTreeItems *self)
}
static
PyNumberMethods
BTreeItems_as_number_for_nonzero
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
(
inquiry
)
BTreeItems_nonzero
};
0
,
/* nb_add */
0
,
/* nb_subtract */
0
,
/* nb_multiply */
#ifndef PY3K
0
,
/* nb_divide */
#endif
0
,
/* nb_remainder */
0
,
/* nb_divmod */
0
,
/* nb_power */
0
,
/* nb_negative */
0
,
/* nb_positive */
0
,
/* nb_absolute */
(
inquiry
)
BTreeItems_nonzero
/* nb_nonzero */
};
static
PyTypeObject
BTreeItemsType
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/*ob_size*/
MOD_NAME_PREFIX
"BTreeItems"
,
/*tp_name*/
sizeof
(
BTreeItems
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
PyVarObject_HEAD_INIT
(
NULL
,
0
)
MOD_NAME_PREFIX
"BTreeItems"
,
/* tp_name */
sizeof
(
BTreeItems
),
/* tp_basicsize */
0
,
/* tp_itemsize */
/* methods */
(
destructor
)
BTreeItems_dealloc
,
/*tp_dealloc*/
(
printfunc
)
0
,
/*tp_print*/
(
getattrfunc
)
0
,
/*obsolete tp_getattr*/
(
setattrfunc
)
0
,
/*obsolete tp_setattr*/
(
cmpfunc
)
0
,
/*tp_compare*/
(
reprfunc
)
0
,
/*tp_repr*/
&
BTreeItems_as_number_for_nonzero
,
/*tp_as_number*/
&
BTreeItems_as_sequence
,
/*tp_as_sequence*/
0
,
/*tp_as_mapping*/
(
hashfunc
)
0
,
/*tp_hash*/
(
ternaryfunc
)
0
,
/*tp_call*/
(
reprfunc
)
0
,
/*tp_str*/
0
,
/*tp_getattro*/
0
,
/*tp_setattro*/
(
destructor
)
BTreeItems_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* obsolete tp_getattr */
0
,
/* obsolete tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
&
BTreeItems_as_number_for_nonzero
,
/* tp_as_number */
&
BTreeItems_as_sequence
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
(
hashfunc
)
0
,
/* tp_hash */
(
ternaryfunc
)
0
,
/* tp_call */
(
reprfunc
)
0
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
/* Space for future expansion */
0L
,
0L
,
"Sequence type used to iterate over BTree items."
/* Documentation string */
...
...
@@ -445,7 +479,8 @@ newBTreeItems(char kind,
{
BTreeItems
*
self
;
UNLESS
(
self
=
PyObject_NEW
(
BTreeItems
,
&
BTreeItemsType
))
return
NULL
;
UNLESS
(
self
=
PyObject_NEW
(
BTreeItems
,
&
BTreeItemsType
))
return
NULL
;
self
->
kind
=
kind
;
self
->
first
=
lowoffset
;
...
...
@@ -564,7 +599,8 @@ nextTreeSetItems(SetIteration *i)
static
PyTypeObject
BTreeIter_Type
;
/* The type of iterator objects, returned by e.g. iter(IIBTree()). */
typedef
struct
{
typedef
struct
{
PyObject_HEAD
/* We use a BTreeItems object because it's convenient and flexible.
* We abuse it two ways:
...
...
@@ -584,7 +620,8 @@ BTreeIter_new(BTreeItems *pitems)
assert
(
pitems
!=
NULL
);
result
=
PyObject_New
(
BTreeIter
,
&
BTreeIter_Type
);
if
(
result
)
{
if
(
result
)
{
Py_INCREF
(
pitems
);
result
->
pitems
=
pitems
;
}
...
...
@@ -615,7 +652,8 @@ BTreeIter_next(BTreeIter *bi, PyObject *args)
return
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
* else mutated the current bucket.
*/
...
...
@@ -630,14 +668,17 @@ BTreeIter_next(BTreeIter *bi, PyObject *args)
result
=
getBucketEntry
(
bucket
,
i
,
items
->
kind
);
/* 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. */
Py_DECREF
(
items
->
currentbucket
);
items
->
currentbucket
=
NULL
;
}
else
{
else
{
++
i
;
if
(
i
>=
bucket
->
len
)
{
if
(
i
>=
bucket
->
len
)
{
Py_XINCREF
(
bucket
->
next
);
items
->
currentbucket
=
bucket
->
next
;
Py_DECREF
(
bucket
);
...
...
@@ -659,8 +700,7 @@ BTreeIter_getiter(PyObject *it)
}
static
PyTypeObject
BTreeIter_Type
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/* ob_size */
PyVarObject_HEAD_INIT
(
NULL
,
0
)
MOD_NAME_PREFIX
"-iterator"
,
/* tp_name */
sizeof
(
BTreeIter
),
/* tp_basicsize */
0
,
/* tp_itemsize */
...
...
BTrees/BTreeModuleTemplate.c
View file @
f108be3a
...
...
@@ -15,6 +15,7 @@
#include "Python.h"
/* include structmember.h for offsetof */
#include "structmember.h"
#include "bytesobject.h"
#ifdef PERSISTENT
#include "persistent/cPersistence.h"
...
...
@@ -27,7 +28,7 @@
#define PER_ACCESSED(O) 1
#endif
#include "
py24
compat.h"
#include "
_
compat.h"
/* So sue me. This pair gets used all over the place, so much so that it
* 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;}
#define MAX_BTREE_SIZE(B) DEFAULT_MAX_BTREE_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)) { \
PyErr_SetString(PyExc_AssertionError, (S)); return (R); }
...
...
@@ -81,7 +82,7 @@ static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
static
int
longlong_check
(
PyObject
*
ob
)
{
if
(
PyInt_Check
(
ob
))
if
(
INT_CHECK
(
ob
))
return
1
;
if
(
PyLong_Check
(
ob
))
{
...
...
@@ -101,10 +102,10 @@ longlong_as_object(PY_LONG_LONG val)
static
PY_LONG_LONG
maxint
=
0
;
if
(
maxint
==
0
)
maxint
=
PyInt_GetMax
();
maxint
=
INT_GETMAX
();
if
((
val
>
maxint
)
||
(
val
<
(
-
maxint
-
1
)))
return
PyLong_FromLongLong
(
val
);
return
PyInt_FromLong
((
long
)
val
);
return
INT_FROM_LONG
((
long
)
val
);
}
#endif
...
...
@@ -291,7 +292,7 @@ IndexError(int i)
{
PyObject
*
v
;
v
=
PyInt_FromLong
(
i
);
v
=
INT_FROM_LONG
(
i
);
if
(
!
v
)
{
v
=
Py_None
;
Py_INCREF
(
v
);
...
...
@@ -451,7 +452,11 @@ BTREEITEMSTEMPLATE_C
int
init_persist_type
(
PyTypeObject
*
type
)
{
#ifdef PY3K
((
PyObject
*
)
type
)
->
ob_type
=
&
PyType_Type
;
#else
type
->
ob_type
=
&
PyType_Type
;
#endif
type
->
tp_base
=
cPersistenceCAPI
->
pertype
;
if
(
PyType_Ready
(
type
)
<
0
)
...
...
@@ -460,6 +465,21 @@ init_persist_type(PyTypeObject *type)
return
1
;
}
#ifdef PY3K
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
void
INITMODULE
(
void
)
{
...
...
@@ -471,40 +491,53 @@ INITMODULE (void)
return
;
#endif
sort_str
=
PyString_InternFromString
(
"sort"
);
sort_str
=
INTERN
(
"sort"
);
if
(
!
sort_str
)
return
;
reverse_str
=
PyString_InternFromString
(
"reverse"
);
reverse_str
=
INTERN
(
"reverse"
);
if
(
!
reverse_str
)
return
;
__setstate___str
=
PyString_InternFromString
(
"__setstate__"
);
__setstate___str
=
INTERN
(
"__setstate__"
);
if
(
!
__setstate___str
)
return
;
_bucket_type_str
=
PyString_InternFromString
(
"_bucket_type"
);
_bucket_type_str
=
INTERN
(
"_bucket_type"
);
if
(
!
_bucket_type_str
)
return
;
/* Grab the ConflictError class */
m
=
PyImport_ImportModule
(
"BTrees.Interfaces"
);
if
(
m
!=
NULL
)
{
if
(
m
!=
NULL
)
{
c
=
PyObject_GetAttrString
(
m
,
"BTreesConflictError"
);
if
(
c
!=
NULL
)
ConflictError
=
c
;
Py_DECREF
(
m
);
}
if
(
ConflictError
==
NULL
)
{
if
(
ConflictError
==
NULL
)
{
Py_INCREF
(
PyExc_ValueError
);
ConflictError
=
PyExc_ValueError
;
}
/* 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
)
return
;
BTreeItemsType
.
ob_type
=
&
PyType_Type
;
BTreeIter_Type
.
ob_type
=
&
PyType_Type
;
#ifdef PY3K
#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
;
BucketType
.
tp_new
=
PyType_GenericNew
;
SetType
.
tp_new
=
PyType_GenericNew
;
...
...
@@ -520,20 +553,26 @@ INITMODULE (void)
return
;
if
(
PyDict_SetItem
(
BTreeType
.
tp_dict
,
_bucket_type_str
,
(
PyObject
*
)
&
BucketType
)
<
0
)
{
(
PyObject
*
)
&
BucketType
)
<
0
)
{
fprintf
(
stderr
,
"btree failed
\n
"
);
return
;
}
if
(
PyDict_SetItem
(
TreeSetType
.
tp_dict
,
_bucket_type_str
,
(
PyObject
*
)
&
SetType
)
<
0
)
{
(
PyObject
*
)
&
SetType
)
<
0
)
{
fprintf
(
stderr
,
"bucket failed
\n
"
);
return
;
}
#ifdef PY3K
m
=
PyModule_Create
(
&
moduledef
);
#else
/* Create the module and add the functions */
m
=
Py_InitModule4
(
"_"
MOD_NAME_PREFIX
"BTree"
,
module_methods
,
BTree_module_documentation
,
(
PyObject
*
)
NULL
,
PYTHON_API_VERSION
);
#endif
/* Add some symbolic constants to the module */
d
=
PyModule_GetDict
(
m
);
...
...
BTrees/BTreeTemplate.c
View file @
f108be3a
...
...
@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE
****************************************************************************/
#include "_compat.h"
#define BTREETEMPLATE_C "$Id$\n"
...
...
@@ -42,8 +43,8 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
PER_USE_OR_RETURN
(
self
,
-
1
);
CHECK
(
self
->
len
>=
0
,
"BTree len < 0"
);
CHECK
(
self
->
len
<=
self
->
size
,
"BTree len > size"
);
if
(
self
->
len
==
0
)
{
/* Empty BTree. */
if
(
self
->
len
==
0
)
/* Empty BTree. */
{
CHECK
(
self
->
firstbucket
==
NULL
,
"Empty BTree has non-NULL firstbucket"
);
result
=
0
;
...
...
@@ -59,58 +60,67 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
* on self's pointers being intact.
*/
#ifdef PERSISTENT
CHECK
(
self
->
firstbucket
->
ob_refcnt
>=
1
,
CHECK
(
Py_REFCNT
(
self
->
firstbucket
)
>=
1
,
"Non-empty BTree firstbucket has refcount < 1"
);
#else
CHECK
(
self
->
firstbucket
->
ob_refcnt
>=
2
,
CHECK
(
Py_REFCNT
(
self
->
firstbucket
)
>=
2
,
"Non-empty BTree firstbucket has refcount < 2"
);
#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"
);
}
if
(
SameType_Check
(
self
,
self
->
data
[
0
].
child
))
{
if
(
SameType_Check
(
self
,
self
->
data
[
0
].
child
))
{
/* Our children are also BTrees. */
child
=
self
->
data
[
0
].
child
;
UNLESS
(
PER_USE
(
child
))
goto
Done
;
UNLESS
(
PER_USE
(
child
))
goto
Done
;
activated_child
=
child
;
CHECK
(
self
->
firstbucket
==
BTREE
(
child
)
->
firstbucket
,
"BTree has firstbucket different than "
"its first child's firstbucket"
);
PER_ALLOW_DEACTIVATION
(
child
);
activated_child
=
NULL
;
for
(
i
=
0
;
i
<
self
->
len
;
++
i
)
{
for
(
i
=
0
;
i
<
self
->
len
;
++
i
)
{
child
=
self
->
data
[
i
].
child
;
CHECK
(
SameType_Check
(
self
,
child
),
"BTree children have different types"
);
if
(
i
==
self
->
len
-
1
)
bucketafter
=
nextbucket
;
else
{
else
{
BTree
*
child2
=
BTREE
(
self
->
data
[
i
+
1
].
child
);
UNLESS
(
PER_USE
(
child2
))
goto
Done
;
UNLESS
(
PER_USE
(
child2
))
goto
Done
;
bucketafter
=
child2
->
firstbucket
;
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
{
/* Our children are buckets. */
else
/* Our children are buckets. */
{
CHECK
(
self
->
firstbucket
==
BUCKET
(
self
->
data
[
0
].
child
),
"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
;
UNLESS
(
PER_USE
(
child
))
goto
Done
;
UNLESS
(
PER_USE
(
child
))
goto
Done
;
activated_child
=
child
;
CHECK
(
!
SameType_Check
(
self
,
child
),
"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"
);
#ifdef PERSISTENT
CHECK
(
child
->
ob_refcnt
>=
1
,
"Bucket has refcount < 1"
);
CHECK
(
Py_REFCNT
(
child
)
>=
1
,
"Bucket has refcount < 1"
);
#else
CHECK
(
child
->
ob_refcnt
>=
2
,
"Bucket has refcount < 2"
);
CHECK
(
Py_REFCNT
(
child
)
>=
2
,
"Bucket has refcount < 2"
);
#endif
if
(
i
==
self
->
len
-
1
)
bucketafter
=
nextbucket
;
...
...
@@ -125,13 +135,15 @@ BTree_check_inner(BTree *self, Bucket *nextbucket)
result
=
0
;
goto
Done
;
Error:
Error:
PyErr_SetString
(
PyExc_AssertionError
,
errormsg
);
result
=
-
1
;
Done:
Done:
/* No point updating access time -- this isn't a "real" use. */
PER_ALLOW_DEACTIVATION
(
self
);
if
(
activated_child
)
{
if
(
activated_child
)
{
PER_ALLOW_DEACTIVATION
(
activated_child
);
}
return
result
;
...
...
@@ -150,7 +162,8 @@ BTree_check(BTree *self)
PyObject
*
result
=
NULL
;
int
i
=
BTree_check_inner
(
self
,
NULL
);
if
(
i
>=
0
)
{
if
(
i
>=
0
)
{
result
=
Py_None
;
Py_INCREF
(
result
);
}
...
...
@@ -187,34 +200,39 @@ _BTree_get(BTree *self, PyObject *keyarg, int has_key)
UNLESS
(
copied
)
return
NULL
;
PER_USE_OR_RETURN
(
self
,
NULL
);
if
(
self
->
len
==
0
)
{
if
(
self
->
len
==
0
)
{
/* empty BTree */
if
(
has_key
)
result
=
PyInt_FromLong
(
0
);
result
=
INT_FROM_LONG
(
0
);
else
PyErr_SetObject
(
PyExc_KeyError
,
keyarg
);
}
else
{
for
(;;)
{
else
{
for
(;;)
{
int
i
;
Sized
*
child
;
BTREE_SEARCH
(
i
,
self
,
key
,
goto
Done
);
child
=
self
->
data
[
i
].
child
;
has_key
+=
has_key
!=
0
;
/* bump depth counter, maybe */
if
(
SameType_Check
(
self
,
child
))
{
if
(
SameType_Check
(
self
,
child
))
{
PER_UNUSE
(
self
);
self
=
BTREE
(
child
);
PER_USE_OR_RETURN
(
self
,
NULL
);
}
else
{
else
{
result
=
_bucket_get
(
BUCKET
(
child
),
keyarg
,
has_key
);
break
;
}
}
}
Done:
Done:
PER_UNUSE
(
self
);
return
result
;
}
...
...
@@ -236,7 +254,7 @@ BTree_newBucket(BTree *self)
Sized
*
result
;
/* _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
)
return
NULL
;
/* TODO: Should we check that the factory actually returns something
...
...
@@ -282,7 +300,8 @@ BTree_split(BTree *self, int index, BTree *next)
/* Set next's firstbucket. self->firstbucket is still correct. */
child
=
next
->
data
[
0
].
child
;
if
(
SameType_Check
(
self
,
child
))
{
if
(
SameType_Check
(
self
,
child
))
{
PER_USE_OR_RETURN
(
child
,
-
1
);
next
->
firstbucket
=
BTREE
(
child
)
->
firstbucket
;
PER_UNUSE
(
child
);
...
...
@@ -318,8 +337,9 @@ BTree_split_root(BTree *self, int noval)
BTreeItem
*
d
;
/* Create a child BTree, and a new data vector for self. */
child
=
BTREE
(
PyObject_CallObject
(
OBJECT
(
self
->
ob_type
),
NULL
));
if
(
!
child
)
return
-
1
;
child
=
BTREE
(
PyObject_CallObject
(
OBJECT
(
Py_TYPE
(
self
)),
NULL
));
if
(
!
child
)
return
-
1
;
d
=
BTree_Malloc
(
sizeof
(
BTreeItem
)
*
2
);
if
(
!
d
)
{
...
...
@@ -368,15 +388,18 @@ BTree_grow(BTree *self, int index, int noval)
Sized
*
v
,
*
e
=
0
;
BTreeItem
*
d
;
if
(
self
->
len
==
self
->
size
)
{
if
(
self
->
size
)
{
if
(
self
->
len
==
self
->
size
)
{
if
(
self
->
size
)
{
d
=
BTree_Realloc
(
self
->
data
,
sizeof
(
BTreeItem
)
*
self
->
size
*
2
);
if
(
d
==
NULL
)
return
-
1
;
self
->
data
=
d
;
self
->
size
*=
2
;
}
else
{
else
{
d
=
BTree_Malloc
(
sizeof
(
BTreeItem
)
*
2
);
if
(
d
==
NULL
)
return
-
1
;
...
...
@@ -385,15 +408,17 @@ BTree_grow(BTree *self, int index, int noval)
}
}
if
(
self
->
len
)
{
if
(
self
->
len
)
{
d
=
self
->
data
+
index
;
v
=
d
->
child
;
/* 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
)
return
-
1
;
UNLESS
(
PER_USE
(
v
))
{
UNLESS
(
PER_USE
(
v
))
{
Py_DECREF
(
e
);
return
-
1
;
}
...
...
@@ -405,7 +430,8 @@ BTree_grow(BTree *self, int index, int noval)
i
=
bucket_split
((
Bucket
*
)
v
,
-
1
,
(
Bucket
*
)
e
);
PER_ALLOW_DEACTIVATION
(
v
);
if
(
i
<
0
)
{
if
(
i
<
0
)
{
Py_DECREF
(
e
);
assert
(
PyErr_Occurred
());
return
-
1
;
...
...
@@ -416,7 +442,8 @@ BTree_grow(BTree *self, int index, int noval)
if
(
self
->
len
>
index
)
/* Shift up the old values one array slot */
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
);
/* We take the unused reference from e, so there's no
...
...
@@ -424,7 +451,8 @@ BTree_grow(BTree *self, int index, int noval)
*/
/* INCREF_KEY(self->data[1].key); */
}
else
{
else
{
COPY_KEY
(
d
->
key
,
BUCKET
(
e
)
->
keys
[
0
]);
INCREF_KEY
(
d
->
key
);
}
...
...
@@ -434,7 +462,8 @@ BTree_grow(BTree *self, int index, int noval)
if
(
self
->
len
>=
MAX_BTREE_SIZE
(
self
)
*
2
)
/* the root is huge */
return
BTree_split_root
(
self
,
noval
);
}
else
{
else
{
/* The BTree is empty. Create an empty bucket. See CAUTION in
* the comments preceding.
*/
...
...
@@ -468,19 +497,22 @@ BTree_lastBucket(BTree *self)
Sized
*
pchild
;
Bucket
*
result
;
UNLESS
(
self
->
data
&&
self
->
len
)
{
UNLESS
(
self
->
data
&&
self
->
len
)
{
IndexError
(
-
1
);
/* is this the best action to take? */
return
NULL
;
}
pchild
=
self
->
data
[
self
->
len
-
1
].
child
;
if
(
SameType_Check
(
self
,
pchild
))
{
if
(
SameType_Check
(
self
,
pchild
))
{
self
=
BTREE
(
pchild
);
PER_USE_OR_RETURN
(
self
,
NULL
);
result
=
BTree_lastBucket
(
self
);
PER_UNUSE
(
self
);
}
else
{
else
{
Py_INCREF
(
pchild
);
result
=
BUCKET
(
pchild
);
}
...
...
@@ -492,7 +524,8 @@ BTree_deleteNextBucket(BTree *self)
{
Bucket
*
b
;
UNLESS
(
PER_USE
(
self
))
return
-
1
;
UNLESS
(
PER_USE
(
self
))
return
-
1
;
b
=
BTree_lastBucket
(
self
);
if
(
b
==
NULL
)
...
...
@@ -505,7 +538,7 @@ BTree_deleteNextBucket(BTree *self)
return
0
;
err:
err:
Py_XDECREF
(
b
);
PER_ALLOW_DEACTIVATION
(
self
);
return
-
1
;
...
...
@@ -538,7 +571,8 @@ _BTree_clear(BTree *self)
{
const
int
len
=
self
->
len
;
if
(
self
->
firstbucket
)
{
if
(
self
->
firstbucket
)
{
/* Obscure: The first bucket is pointed to at least by
* self->firstbucket and data[0].child of whichever BTree node it's
* a child of. However, if persistence is enabled then the latter
...
...
@@ -546,23 +580,26 @@ _BTree_clear(BTree *self)
* count": we can only rely on self's pointers being intact.
*/
#ifdef PERSISTENT
ASSERT
(
self
->
firstbucket
->
ob_refcnt
>
0
,
ASSERT
(
Py_REFCNT
(
self
->
firstbucket
)
>
0
,
"Invalid firstbucket pointer"
,
-
1
);
#else
ASSERT
(
self
->
firstbucket
->
ob_refcnt
>
1
,
ASSERT
(
Py_REFCNT
(
self
->
firstbucket
)
>
1
,
"Invalid firstbucket pointer"
,
-
1
);
#endif
Py_DECREF
(
self
->
firstbucket
);
self
->
firstbucket
=
NULL
;
}
if
(
self
->
data
)
{
if
(
self
->
data
)
{
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
);
}
for
(
i
=
1
;
i
<
len
;
i
++
)
{
for
(
i
=
1
;
i
<
len
;
i
++
)
{
#ifdef KEY_TYPE_IS_PYOBJECT
DECREF_KEY
(
self
->
data
[
i
].
key
);
#endif
...
...
@@ -617,18 +654,22 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
int
copied
=
1
;
COPY_KEY_FROM_ARG
(
key
,
keyarg
,
copied
);
if
(
!
copied
)
return
-
1
;
if
(
!
copied
)
return
-
1
;
PER_USE_OR_RETURN
(
self
,
-
1
);
self_was_empty
=
self
->
len
==
0
;
if
(
self_was_empty
)
{
if
(
self_was_empty
)
{
/* We're empty. Make room. */
if
(
value
)
{
if
(
value
)
{
if
(
BTree_grow
(
self
,
0
,
noval
)
<
0
)
goto
Error
;
}
else
{
else
{
/* Can't delete a key from an empty BTree. */
PyErr_SetObject
(
PyExc_KeyError
,
keyarg
);
goto
Error
;
...
...
@@ -645,7 +686,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
if
(
SameType_Check
(
self
,
d
->
child
))
status
=
_BTree_set
(
BTREE
(
d
->
child
),
keyarg
,
value
,
unique
,
noval
);
else
{
else
{
int
bucket_changed
=
0
;
status
=
_bucket_set
(
BUCKET
(
d
->
child
),
keyarg
,
value
,
unique
,
noval
,
&
bucket_changed
);
...
...
@@ -664,19 +706,23 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
}
#endif
}
if
(
status
==
0
)
goto
Done
;
if
(
status
<
0
)
goto
Error
;
if
(
status
==
0
)
goto
Done
;
if
(
status
<
0
)
goto
Error
;
assert
(
status
==
1
||
status
==
2
);
/* 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:
* our status must be >= 1 too.
*/
UNLESS
(
PER_USE
(
d
->
child
))
goto
Error
;
UNLESS
(
PER_USE
(
d
->
child
))
goto
Error
;
childlength
=
d
->
child
->
len
;
PER_UNUSE
(
d
->
child
);
if
(
value
)
{
if
(
value
)
{
/* A bucket got bigger -- if it's "too big", split it. */
int
toobig
;
...
...
@@ -687,7 +733,8 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
toobig
=
childlength
>
MAX_BUCKET_SIZE
(
d
->
child
);
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 */
}
goto
Done
;
/* and status still == 1 */
...
...
@@ -706,45 +753,53 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
*/
int
_cmp
=
1
;
TEST_KEY_SET_OR
(
_cmp
,
key
,
d
->
key
)
goto
Error
;
if
(
_cmp
==
0
)
{
/* Need to replace key with first key from child */
if
(
_cmp
==
0
)
/* Need to replace key with first key from child */
{
Bucket
*
bucket
;
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
;
PER_UNUSE
(
d
->
child
);
}
else
bucket
=
BUCKET
(
d
->
child
);
UNLESS
(
PER_USE
(
bucket
))
goto
Error
;
UNLESS
(
PER_USE
(
bucket
))
goto
Error
;
DECREF_KEY
(
d
->
key
);
COPY_KEY
(
d
->
key
,
bucket
->
keys
[
0
]);
INCREF_KEY
(
d
->
key
);
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 */
/* Two problems to solve: May have to adjust our own firstbucket,
* 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
* that it can't be the firstbucket of any node above us either).
* 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 */
}
else
{
else
{
/* This was our firstbucket. Update to new firstbucket value. */
Bucket
*
nextbucket
;
UNLESS
(
PER_USE
(
d
->
child
))
goto
Error
;
UNLESS
(
PER_USE
(
d
->
child
))
goto
Error
;
nextbucket
=
BTREE
(
d
->
child
)
->
firstbucket
;
PER_UNUSE
(
d
->
child
);
...
...
@@ -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
* 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.
* But first, if we're a bottom-level node, we've got more bucket-fiddling
* 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. */
if
(
min
)
{
if
(
min
)
{
/* It's not our first bucket, so we can tell the previous
* bucket to adjust its reference to it. It can't be anyone
* 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
* block above would have set it to 1 in its min != 0 branch.
*/
assert
(
status
==
1
);
}
else
{
else
{
Bucket
*
nextbucket
;
/* It's our first bucket. We can't unlink it directly. */
/* '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
;
PER_UNUSE
(
d
->
child
);
...
...
@@ -802,10 +863,12 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
/* Remove the child from self->data. */
Py_DECREF
(
d
->
child
);
#ifdef KEY_TYPE_IS_PYOBJECT
if
(
min
)
{
if
(
min
)
{
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
* 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
...
...
@@ -822,18 +885,21 @@ _BTree_set(BTree *self, PyObject *keyarg, PyObject *value,
memmove
(
d
,
d
+
1
,
(
self
->
len
-
min
)
*
sizeof
(
BTreeItem
));
changed
=
1
;
Done:
Done:
#ifdef PERSISTENT
if
(
changed
)
{
if
(
PER_CHANGED
(
self
)
<
0
)
goto
Error
;
if
(
changed
)
{
if
(
PER_CHANGED
(
self
)
<
0
)
goto
Error
;
}
#endif
PER_UNUSE
(
self
);
return
status
;
Error:
Error:
assert
(
PyErr_Occurred
());
if
(
self_was_empty
)
{
if
(
self_was_empty
)
{
/* BTree_grow may have left the BTree in an invalid state. Make
* sure the tree is a legitimate empty tree.
*/
...
...
@@ -870,32 +936,38 @@ BTree__p_deactivate(BTree *self, PyObject *args, PyObject *keywords)
int
ghostify
=
1
;
PyObject
*
force
=
NULL
;
if
(
args
&&
PyTuple_GET_SIZE
(
args
)
>
0
)
{
if
(
args
&&
PyTuple_GET_SIZE
(
args
)
>
0
)
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_deactivate takes not positional arguments"
);
return
NULL
;
}
if
(
keywords
)
{
if
(
keywords
)
{
int
size
=
PyDict_Size
(
keywords
);
force
=
PyDict_GetItemString
(
keywords
,
"force"
);
if
(
force
)
size
--
;
if
(
size
)
{
if
(
size
)
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_deactivate only accepts keyword arg force"
);
return
NULL
;
}
}
if
(
self
->
jar
&&
self
->
oid
)
{
if
(
self
->
jar
&&
self
->
oid
)
{
ghostify
=
self
->
state
==
cPersistent_UPTODATE_STATE
;
if
(
!
ghostify
&&
force
)
{
if
(
!
ghostify
&&
force
)
{
if
(
PyObject_IsTrue
(
force
))
ghostify
=
1
;
if
(
PyErr_Occurred
())
return
NULL
;
}
if
(
ghostify
)
{
if
(
ghostify
)
{
if
(
_BTree_clear
(
self
)
<
0
)
return
NULL
;
PER_GHOSTIFY
(
self
);
...
...
@@ -925,7 +997,7 @@ BTree_clear(BTree *self)
Py_INCREF
(
Py_None
);
return
Py_None
;
err:
err:
PER_UNUSE
(
self
);
return
NULL
;
}
...
...
@@ -964,19 +1036,22 @@ BTree_getstate(BTree *self)
PyObject
*
o
;
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
);
if
(
r
==
NULL
)
goto
err
;
if
(
self
->
len
==
1
&&
self
->
data
->
child
->
ob_type
!=
self
->
ob_type
&&
Py_TYPE
(
self
->
data
->
child
)
!=
Py_TYPE
(
self
)
#ifdef PERSISTENT
&&
BUCKET
(
self
->
data
->
child
)
->
oid
==
NULL
#endif
)
{
)
{
/* We have just one bucket. Save its data directly. */
o
=
bucket_getstate
((
Bucket
*
)
self
->
data
->
child
);
if
(
o
==
NULL
)
...
...
@@ -984,9 +1059,12 @@ BTree_getstate(BTree *self)
PyTuple_SET_ITEM
(
r
,
0
,
o
);
ASSIGN
(
r
,
Py_BuildValue
(
"(O)"
,
r
));
}
else
{
for
(
i
=
0
,
l
=
0
;
i
<
self
->
len
;
i
++
)
{
if
(
i
)
{
else
{
for
(
i
=
0
,
l
=
0
;
i
<
self
->
len
;
i
++
)
{
if
(
i
)
{
COPY_KEY_TO_OBJECT
(
o
,
self
->
data
[
i
].
key
);
PyTuple_SET_ITEM
(
r
,
l
,
o
);
l
++
;
...
...
@@ -1000,7 +1078,8 @@ BTree_getstate(BTree *self)
}
}
else
{
else
{
r
=
Py_None
;
Py_INCREF
(
r
);
}
...
...
@@ -1009,7 +1088,7 @@ BTree_getstate(BTree *self)
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
return
NULL
;
...
...
@@ -1038,7 +1117,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
if
(
!
PyArg_ParseTuple
(
state
,
"O|O:__setstate__"
,
&
items
,
&
firstbucket
))
return
-
1
;
if
(
!
PyTuple_Check
(
items
))
{
if
(
!
PyTuple_Check
(
items
))
{
PyErr_SetString
(
PyExc_TypeError
,
"tuple required for first state element"
);
return
-
1
;
...
...
@@ -1057,9 +1137,11 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
return
-
1
;
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
;
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
);
l
++
;
if
(
!
copied
)
...
...
@@ -1067,22 +1149,26 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
INCREF_KEY
(
d
->
key
);
}
v
=
PyTuple_GET_ITEM
(
items
,
l
);
if
(
PyTuple_Check
(
v
))
{
if
(
PyTuple_Check
(
v
))
{
/* Handle the special case in __getstate__() for a BTree
with a single bucket. */
d
->
child
=
BTree_newBucket
(
self
);
if
(
!
d
->
child
)
return
-
1
;
if
(
noval
)
{
if
(
noval
)
{
if
(
_set_setstate
(
BUCKET
(
d
->
child
),
v
)
<
0
)
return
-
1
;
}
else
{
else
{
if
(
_bucket_setstate
(
BUCKET
(
d
->
child
),
v
)
<
0
)
return
-
1
;
}
}
else
{
else
{
d
->
child
=
(
Sized
*
)
v
;
Py_INCREF
(
v
);
}
...
...
@@ -1093,7 +1179,8 @@ _BTree_setstate(BTree *self, PyObject *state, int noval)
firstbucket
=
(
PyObject
*
)
self
->
data
->
child
;
if
(
!
PyObject_IsInstance
(
firstbucket
,
(
PyObject
*
)
(
noval
?
&
SetType
:
&
BucketType
)))
{
(
noval
?
&
SetType
:
&
BucketType
)))
{
PyErr_SetString
(
PyExc_TypeError
,
"No firstbucket in non-empty BTree"
);
return
-
1
;
...
...
@@ -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
* be a ghost if persistence is enabled.
*/
assert
(
self
->
firstbucket
->
ob_refcnt
>
1
);
assert
(
Py_REFCNT
(
self
->
firstbucket
)
>
1
);
#endif
self
->
len
=
len
;
...
...
@@ -1149,27 +1236,31 @@ get_bucket_state(PyObject *t)
{
if
(
t
==
Py_None
)
return
Py_None
;
/* an empty BTree */
if
(
!
PyTuple_Check
(
t
))
{
if
(
!
PyTuple_Check
(
t
))
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_resolveConflict: expected tuple or None for state"
);
return
NULL
;
}
if
(
PyTuple_GET_SIZE
(
t
)
==
2
)
{
if
(
PyTuple_GET_SIZE
(
t
)
==
2
)
{
/* A non-degenerate BTree. */
return
merge_error
(
-
1
,
-
1
,
-
1
,
11
);
}
/* We're in the one-bucket case. */
if
(
PyTuple_GET_SIZE
(
t
)
!=
1
)
{
if
(
PyTuple_GET_SIZE
(
t
)
!=
1
)
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_resolveConflict: expected 1- or 2-tuple for state"
);
return
NULL
;
}
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
,
"_p_resolveConflict: expected 1-tuple containing "
"bucket state"
);
...
...
@@ -1177,7 +1268,8 @@ get_bucket_state(PyObject *t)
}
t
=
PyTuple_GET_ITEM
(
t
,
0
);
if
(
!
PyTuple_Check
(
t
))
{
if
(
!
PyTuple_Check
(
t
))
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_resolveConflict: expected tuple for bucket state"
);
return
NULL
;
...
...
@@ -1279,7 +1371,8 @@ BTree__p_resolveConflict(BTree *self, PyObject *args)
*/
static
int
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 */
int
deepest_smaller_is_btree
=
0
;
/* Boolean; if false, it's a bucket */
Bucket
*
pbucket
;
...
...
@@ -1290,34 +1383,41 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
int
copied
=
1
;
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);
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. */
for
(;;)
{
for
(;;)
{
Sized
*
pchild
;
int
pchild_is_btree
;
BTREE_SEARCH
(
i
,
self
,
key
,
goto
Done
);
pchild
=
self
->
data
[
i
].
child
;
pchild_is_btree
=
SameType_Check
(
self
,
pchild
);
if
(
i
)
{
if
(
i
)
{
deepest_smaller
=
self
->
data
[
i
-
1
].
child
;
deepest_smaller_is_btree
=
pchild_is_btree
;
}
if
(
pchild_is_btree
)
{
if
(
self_got_rebound
)
{
if
(
pchild_is_btree
)
{
if
(
self_got_rebound
)
{
PER_UNUSE
(
self
);
}
self
=
BTREE
(
pchild
);
self_got_rebound
=
1
;
PER_USE_OR_RETURN
(
self
,
-
1
);
}
else
{
else
{
pbucket
=
BUCKET
(
pchild
);
break
;
}
...
...
@@ -1327,14 +1427,16 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
i
=
Bucket_findRangeEnd
(
pbucket
,
keyarg
,
low
,
exclude_equal
,
offset
);
if
(
i
<
0
)
goto
Done
;
if
(
i
>
0
)
{
if
(
i
>
0
)
{
Py_INCREF
(
pbucket
);
*
bucket
=
pbucket
;
result
=
1
;
goto
Done
;
}
/* This may be one of the two difficult cases detailed in the comments. */
if
(
low
)
{
if
(
low
)
{
Bucket
*
next
;
UNLESS
(
PER_USE
(
pbucket
))
goto
Done
;
...
...
@@ -1350,19 +1452,25 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
PER_UNUSE
(
pbucket
);
}
/* High-end search: if it's possible to go left, do so. */
else
if
(
deepest_smaller
)
{
if
(
deepest_smaller_is_btree
)
{
UNLESS
(
PER_USE
(
deepest_smaller
))
goto
Done
;
else
if
(
deepest_smaller
)
{
if
(
deepest_smaller_is_btree
)
{
UNLESS
(
PER_USE
(
deepest_smaller
))
goto
Done
;
/* We own the reference this returns. */
pbucket
=
BTree_lastBucket
(
BTREE
(
deepest_smaller
));
PER_UNUSE
(
deepest_smaller
);
if
(
pbucket
==
NULL
)
goto
Done
;
/* error */
if
(
pbucket
==
NULL
)
goto
Done
;
/* error */
}
else
{
else
{
pbucket
=
BUCKET
(
deepest_smaller
);
Py_INCREF
(
pbucket
);
}
UNLESS
(
PER_USE
(
pbucket
))
goto
Done
;
UNLESS
(
PER_USE
(
pbucket
))
goto
Done
;
result
=
1
;
*
bucket
=
pbucket
;
/* transfer ownership to caller */
*
offset
=
pbucket
->
len
-
1
;
...
...
@@ -1371,8 +1479,9 @@ BTree_findRangeEnd(BTree *self, PyObject *keyarg, int low, int exclude_equal,
else
result
=
0
;
/* simply not found */
Done:
if
(
self_got_rebound
)
{
Done:
if
(
self_got_rebound
)
{
PER_UNUSE
(
self
);
}
return
result
;
...
...
@@ -1386,11 +1495,14 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
int
offset
,
rc
;
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 */
...
...
@@ -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
<
0
)
goto
err
;
if
(
rc
<
0
)
goto
err
;
empty_tree
=
0
;
goto
empty
;
}
...
...
@@ -1436,11 +1549,11 @@ BTree_maxminKey(BTree *self, PyObject *args, int min)
return
key
;
empty:
empty:
PyErr_SetString
(
PyExc_ValueError
,
empty_tree
?
"empty tree"
:
"no key satisfies the conditions"
);
err:
err:
PER_UNUSE
(
self
);
if
(
bucket
)
{
...
...
@@ -1483,7 +1596,8 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
int
highoffset
;
PyObject
*
result
;
if
(
args
)
{
if
(
args
)
{
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kw
,
"|OOii"
,
search_keywords
,
&
min
,
&
max
,
...
...
@@ -1492,33 +1606,43 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
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 */
if
(
min
!=
Py_None
)
{
if
(
min
!=
Py_None
)
{
if
((
rc
=
BTree_findRangeEnd
(
self
,
min
,
1
,
excludemin
,
&
lowbucket
,
&
lowoffset
))
<=
0
)
{
if
(
rc
<
0
)
goto
err
;
&
lowbucket
,
&
lowoffset
))
<=
0
)
{
if
(
rc
<
0
)
goto
err
;
goto
empty
;
}
}
else
{
else
{
lowbucket
=
self
->
firstbucket
;
lowoffset
=
0
;
if
(
excludemin
)
{
if
(
excludemin
)
{
int
bucketlen
;
UNLESS
(
PER_USE
(
lowbucket
))
goto
err
;
UNLESS
(
PER_USE
(
lowbucket
))
goto
err
;
bucketlen
=
lowbucket
->
len
;
PER_UNUSE
(
lowbucket
);
if
(
bucketlen
>
1
)
lowoffset
=
1
;
else
if
(
self
->
len
<
2
)
goto
empty
;
else
{
/* move to first item in next bucket */
else
{
/* move to first item in next bucket */
Bucket
*
next
;
UNLESS
(
PER_USE
(
lowbucket
))
goto
err
;
UNLESS
(
PER_USE
(
lowbucket
))
goto
err
;
next
=
lowbucket
->
next
;
PER_UNUSE
(
lowbucket
);
assert
(
next
!=
NULL
);
...
...
@@ -1531,39 +1655,48 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
}
/* Find the high range */
if
(
max
!=
Py_None
)
{
if
(
max
!=
Py_None
)
{
if
((
rc
=
BTree_findRangeEnd
(
self
,
max
,
0
,
excludemax
,
&
highbucket
,
&
highoffset
))
<=
0
)
{
&
highbucket
,
&
highoffset
))
<=
0
)
{
Py_DECREF
(
lowbucket
);
if
(
rc
<
0
)
goto
err
;
if
(
rc
<
0
)
goto
err
;
goto
empty
;
}
}
else
{
else
{
int
bucketlen
;
highbucket
=
BTree_lastBucket
(
self
);
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
;
PER_UNUSE
(
highbucket
);
highoffset
=
bucketlen
-
1
;
if
(
excludemax
)
{
if
(
excludemax
)
{
if
(
highoffset
>
0
)
--
highoffset
;
else
if
(
self
->
len
<
2
)
goto
empty_and_decref_buckets
;
else
{
/* move to last item of preceding bucket */
else
/* move to last item of preceding bucket */
{
int
status
;
assert
(
highbucket
!=
self
->
firstbucket
);
Py_DECREF
(
highbucket
);
status
=
PreviousBucket
(
&
highbucket
,
self
->
firstbucket
);
if
(
status
<
0
)
{
if
(
status
<
0
)
{
Py_DECREF
(
lowbucket
);
goto
err
;
}
assert
(
status
>
0
);
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
;
PER_UNUSE
(
highbucket
);
}
...
...
@@ -1585,22 +1718,27 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
* empty range.
*/
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
last
;
int
cmp
;
/* 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
]);
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
]);
PER_UNUSE
(
highbucket
);
TEST_KEY_SET_OR
(
cmp
,
first
,
last
)
goto
err_and_decref_buckets
;
if
(
cmp
>
0
)
goto
empty_and_decref_buckets
;
TEST_KEY_SET_OR
(
cmp
,
first
,
last
)
goto
err_and_decref_buckets
;
if
(
cmp
>
0
)
goto
empty_and_decref_buckets
;
}
PER_UNUSE
(
self
);
...
...
@@ -1610,19 +1748,19 @@ BTree_rangeSearch(BTree *self, PyObject *args, PyObject *kw, char type)
Py_DECREF
(
highbucket
);
return
result
;
err_and_decref_buckets:
err_and_decref_buckets:
Py_DECREF
(
lowbucket
);
Py_DECREF
(
highbucket
);
err:
err:
PER_UNUSE
(
self
);
return
NULL
;
empty_and_decref_buckets:
empty_and_decref_buckets:
Py_DECREF
(
lowbucket
);
Py_DECREF
(
highbucket
);
empty:
empty:
PER_UNUSE
(
self
);
return
newBTreeItems
(
type
,
0
,
0
,
0
,
0
);
}
...
...
@@ -1663,57 +1801,71 @@ BTree_byValue(BTree *self, PyObject *omin)
int
copied
=
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
);
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'
);
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
)
{
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
);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
PyTuple_SET_ITEM
(
item
,
1
,
o
);
COPY_VALUE
(
v
,
it
.
value
);
NORMALIZE_VALUE
(
v
,
min
);
COPY_VALUE_TO_OBJECT
(
o
,
v
);
DECREF_VALUE
(
v
);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
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
);
item
=
0
;
}
if
(
nextBTreeItems
(
&
it
)
<
0
)
goto
err
;
if
(
nextBTreeItems
(
&
it
)
<
0
)
goto
err
;
}
item
=
PyObject_GetAttr
(
r
,
sort_str
);
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_CallObject
(
item
,
NULL
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_GetAttr
(
r
,
reverse_str
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_CallObject
(
item
,
NULL
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
Py_DECREF
(
item
);
finiSetIteration
(
&
it
);
PER_UNUSE
(
self
);
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
finiSetIteration
(
&
it
);
...
...
@@ -1729,9 +1881,12 @@ BTree_getm(BTree *self, PyObject *args)
{
PyObject
*
key
,
*
d
=
Py_None
,
*
r
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|O"
,
&
key
,
&
d
))
return
NULL
;
if
((
r
=
_BTree_get
(
self
,
key
,
0
)))
return
r
;
UNLESS
(
PyErr_ExceptionMatches
(
PyExc_KeyError
))
return
NULL
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O|O"
,
&
key
,
&
d
))
return
NULL
;
if
((
r
=
_BTree_get
(
self
,
key
,
0
)))
return
r
;
UNLESS
(
PyErr_ExceptionMatches
(
PyExc_KeyError
))
return
NULL
;
PyErr_Clear
();
Py_INCREF
(
d
);
return
d
;
...
...
@@ -1787,9 +1942,11 @@ BTree_pop(BTree *self, PyObject *args)
return
NULL
;
value
=
_BTree_get
(
self
,
key
,
0
);
if
(
value
!=
NULL
)
{
if
(
value
!=
NULL
)
{
/* 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
);
return
NULL
;;
}
...
...
@@ -1802,7 +1959,8 @@ BTree_pop(BTree *self, PyObject *args)
if
(
!
PyErr_ExceptionMatches
(
PyExc_KeyError
))
return
NULL
;
if
(
failobj
!=
NULL
)
{
if
(
failobj
!=
NULL
)
{
/* Clear the KeyError and return the explicit default. */
PyErr_Clear
();
Py_INCREF
(
failobj
);
...
...
@@ -1831,8 +1989,9 @@ BTree_contains(BTree *self, PyObject *key)
PyObject
*
asobj
=
_BTree_get
(
self
,
key
,
1
);
int
result
=
-
1
;
if
(
asobj
!=
NULL
)
{
result
=
PyInt_AsLong
(
asobj
)
?
1
:
0
;
if
(
asobj
!=
NULL
)
{
result
=
INT_AS_LONG
(
asobj
)
?
1
:
0
;
Py_DECREF
(
asobj
);
}
return
result
;
...
...
@@ -1844,10 +2003,12 @@ BTree_addUnique(BTree *self, PyObject *args)
int
grew
;
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
;
return
PyInt_FromLong
(
grew
);
if
((
grew
=
_BTree_set
(
self
,
key
,
v
,
1
,
0
))
<
0
)
return
NULL
;
return
INT_FROM_LONG
(
grew
);
}
/**************************************************************************/
...
...
@@ -1865,7 +2026,8 @@ buildBTreeIter(BTree *self, PyObject *args, PyObject *kw, char kind)
BTreeIter
*
result
=
NULL
;
BTreeItems
*
items
=
(
BTreeItems
*
)
BTree_rangeSearch
(
self
,
args
,
kw
,
kind
);
if
(
items
)
{
if
(
items
)
{
result
=
BTreeIter_new
(
items
);
Py_DECREF
(
items
);
}
...
...
@@ -1912,7 +2074,7 @@ BTree_iteritems(BTree *self, PyObject *args, PyObject *kw)
*/
static
struct
PyMemberDef
BTree_members
[]
=
{
{
"_firstbucket"
,
T_OBJECT
,
offsetof
(
BTree
,
firstbucket
),
RO
},
{
"_firstbucket"
,
T_OBJECT
,
offsetof
(
BTree
,
firstbucket
),
READONLY
},
{
NULL
}
};
...
...
@@ -1993,14 +2155,15 @@ static struct PyMethodDef BTree_methods[] = {
"B.itervalues([min[,max]]) -> an iterator over the values of B"
},
{
"iteritems"
,
(
PyCFunction
)
BTree_iteritems
,
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
,
"Perform sanity check on BTree, and raise exception if flawed."
},
#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_deactivate"
,
(
PyCFunction
)
BTree__p_deactivate
,
METH_KEYWORDS
,
...
...
@@ -2044,8 +2207,8 @@ BTree_traverse(BTree *self, visitproc visit, void *arg)
goto Done; \
}
if
(
self
->
ob_type
==
&
BTreeType
)
assert
(
self
->
ob_type
->
tp_dictoffset
==
0
);
if
(
Py_TYPE
(
self
)
==
&
BTreeType
)
assert
(
Py_TYPE
(
self
)
->
tp_dictoffset
==
0
);
/* Call our base type's traverse function. Because BTrees are
* subclasses of Peristent, there must be one.
...
...
@@ -2076,7 +2239,7 @@ BTree_traverse(BTree *self, visitproc visit, void *arg)
VISIT
(
self
->
firstbucket
);
Done:
Done:
return
err
;
#undef VISIT
...
...
@@ -2119,7 +2282,8 @@ BTree_length_or_nonzero(BTree *self, int nonzero)
return
b
!=
NULL
;
result
=
0
;
while
(
b
)
{
while
(
b
)
{
PER_USE_OR_RETURN
(
b
,
-
1
);
result
+=
b
->
len
;
next
=
b
->
next
;
...
...
@@ -2136,9 +2300,9 @@ BTree_length(BTree *self)
}
static
PyMappingMethods
BTree_as_mapping
=
{
(
lenfunc
)
BTree_length
,
/*mp_length
*/
(
binaryfunc
)
BTree_get
,
/*mp_subscript
*/
(
objobjargproc
)
BTree_setitem
,
/*mp_ass_subscript
*/
(
lenfunc
)
BTree_length
,
/* mp_length
*/
(
binaryfunc
)
BTree_get
,
/* mp_subscript
*/
(
objobjargproc
)
BTree_setitem
,
/* mp_ass_subscript
*/
};
static
PySequenceMethods
BTree_as_sequence
=
{
...
...
@@ -2161,13 +2325,24 @@ BTree_nonzero(BTree *self)
}
static
PyNumberMethods
BTree_as_number_for_nonzero
=
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
(
inquiry
)
BTree_nonzero
};
0
,
/* nb_add */
0
,
/* nb_subtract */
0
,
/* nb_multiply */
#ifndef PY3K
0
,
/* nb_divide */
#endif
0
,
/* nb_remainder */
0
,
/* nb_divmod */
0
,
/* nb_power */
0
,
/* nb_negative */
0
,
/* nb_positive */
0
,
/* nb_absolute */
(
inquiry
)
BTree_nonzero
/* nb_nonzero */
};
static
PyTypeObject
BTreeType
=
{
PyObject_HEAD_INIT
(
NULL
)
/* PyPersist_Type */
0
,
/* ob_size */
MODULE_NAME
MOD_NAME_PREFIX
"BTree"
,
/* tp_name */
PyVarObject_HEAD_INIT
(
NULL
,
0
)
MODULE_NAME
MOD_NAME_PREFIX
"BTree"
,
/* tp_name */
sizeof
(
BTree
),
/* tp_basicsize */
0
,
/* tp_itemsize */
(
destructor
)
BTree_dealloc
,
/* tp_dealloc */
...
...
@@ -2185,7 +2360,8 @@ static PyTypeObject BTreeType = {
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
0
,
/* tp_doc */
(
traverseproc
)
BTree_traverse
,
/* tp_traverse */
...
...
BTrees/BucketTemplate.c
View file @
f108be3a
...
...
@@ -87,19 +87,20 @@ _bucket_get(Bucket *self, PyObject *keyarg, int has_key)
BUCKET_SEARCH
(
i
,
cmp
,
self
,
key
,
goto
Done
);
if
(
has_key
)
r
=
PyInt_FromLong
(
cmp
?
0
:
has_key
);
else
{
if
(
cmp
==
0
)
{
r
=
INT_FROM_LONG
(
cmp
?
0
:
has_key
);
else
{
if
(
cmp
==
0
)
{
COPY_VALUE_TO_OBJECT
(
r
,
self
->
values
[
i
]);
}
else
PyErr_SetObject
(
PyExc_KeyError
,
keyarg
);
}
Done:
Done:
PER_UNUSE
(
self
);
return
r
;
}
static
PyObject
*
...
...
@@ -129,7 +130,8 @@ Bucket_grow(Bucket *self, int newsize, int noval)
KEY_TYPE
*
keys
;
VALUE_TYPE
*
values
;
if
(
self
->
size
)
{
if
(
self
->
size
)
{
if
(
newsize
<
0
)
newsize
=
self
->
size
*
2
;
if
(
newsize
<
0
)
/* int overflow */
...
...
@@ -137,9 +139,11 @@ Bucket_grow(Bucket *self, int newsize, int noval)
UNLESS
(
keys
=
BTree_Realloc
(
self
->
keys
,
sizeof
(
KEY_TYPE
)
*
newsize
))
return
-
1
;
UNLESS
(
noval
)
{
UNLESS
(
noval
)
{
values
=
BTree_Realloc
(
self
->
values
,
sizeof
(
VALUE_TYPE
)
*
newsize
);
if
(
values
==
NULL
)
{
if
(
values
==
NULL
)
{
free
(
keys
);
return
-
1
;
}
...
...
@@ -147,14 +151,17 @@ Bucket_grow(Bucket *self, int newsize, int noval)
}
self
->
keys
=
keys
;
}
else
{
else
{
if
(
newsize
<
0
)
newsize
=
MIN_BUCKET_ALLOC
;
UNLESS
(
self
->
keys
=
BTree_Malloc
(
sizeof
(
KEY_TYPE
)
*
newsize
))
return
-
1
;
UNLESS
(
noval
)
{
UNLESS
(
noval
)
{
self
->
values
=
BTree_Malloc
(
sizeof
(
VALUE_TYPE
)
*
newsize
);
if
(
self
->
values
==
NULL
)
{
if
(
self
->
values
==
NULL
)
{
free
(
self
->
keys
);
self
->
keys
=
NULL
;
return
-
1
;
...
...
@@ -164,7 +171,7 @@ Bucket_grow(Bucket *self, int newsize, int noval)
self
->
size
=
newsize
;
return
0
;
Overflow:
Overflow:
PyErr_NoMemory
();
return
-
1
;
}
...
...
@@ -222,7 +229,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
/* Make room. */
newlen
=
self
->
len
+
n
;
if
(
newlen
>
self
->
size
)
{
if
(
newlen
>
self
->
size
)
{
int
newsize
=
newlen
;
if
(
overallocate
)
/* boost by 25% -- pretty arbitrary */
newsize
+=
newsize
>>
2
;
...
...
@@ -233,7 +241,8 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
/* Copy stuff. */
memcpy
(
self
->
keys
+
self
->
len
,
from
->
keys
+
i
,
n
*
sizeof
(
KEY_TYPE
));
if
(
copyValues
)
{
if
(
copyValues
)
{
assert
(
self
->
values
);
assert
(
from
->
values
);
memcpy
(
self
->
values
+
self
->
len
,
from
->
values
+
i
,
...
...
@@ -246,16 +255,19 @@ bucket_append(Bucket *self, Bucket *from, int i, int n,
{
int
j
;
PyObject
**
p
=
from
->
keys
+
i
;
for
(
j
=
0
;
j
<
n
;
++
j
,
++
p
)
{
for
(
j
=
0
;
j
<
n
;
++
j
,
++
p
)
{
Py_INCREF
(
*
p
);
}
}
#endif
#ifdef VALUE_TYPE_IS_PYOBJECT
if
(
copyValues
)
{
if
(
copyValues
)
{
int
j
;
PyObject
**
p
=
from
->
values
+
i
;
for
(
j
=
0
;
j
<
n
;
++
j
,
++
p
)
{
for
(
j
=
0
;
j
<
n
;
++
j
,
++
p
)
{
Py_INCREF
(
*
p
);
}
}
...
...
@@ -309,28 +321,33 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
int
copied
=
1
;
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
* pile of bucket mutations don't need to be undone.
*/
if
(
v
&&
!
noval
)
{
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
);
if
(
cmp
==
0
)
{
if
(
cmp
==
0
)
{
/* The key exists, at index i. */
if
(
v
)
{
if
(
v
)
{
/* 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
* 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
;
goto
Done
;
}
...
...
@@ -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. */
#ifdef VALUE_SAME
/* short-circuit if no change */
if
(
VALUE_SAME
(
self
->
values
[
i
],
value
))
{
if
(
VALUE_SAME
(
self
->
values
[
i
],
value
))
{
result
=
0
;
goto
Done
;
}
...
...
@@ -360,18 +378,21 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
memmove
(
self
->
keys
+
i
,
self
->
keys
+
i
+
1
,
sizeof
(
KEY_TYPE
)
*
(
self
->
len
-
i
));
if
(
self
->
values
)
{
if
(
self
->
values
)
{
DECREF_VALUE
(
self
->
values
[
i
]);
if
(
i
<
self
->
len
)
memmove
(
self
->
values
+
i
,
self
->
values
+
i
+
1
,
sizeof
(
VALUE_TYPE
)
*
(
self
->
len
-
i
));
}
if
(
!
self
->
len
)
{
if
(
!
self
->
len
)
{
self
->
size
=
0
;
free
(
self
->
keys
);
self
->
keys
=
NULL
;
if
(
self
->
values
)
{
if
(
self
->
values
)
{
free
(
self
->
values
);
self
->
values
=
NULL
;
}
...
...
@@ -385,7 +406,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
}
/* The key doesn't exist, and belongs at index i. */
if
(
!
v
)
{
if
(
!
v
)
{
/* Can't delete a non-existent key. */
PyErr_SetObject
(
PyExc_KeyError
,
keyarg
);
goto
Done
;
...
...
@@ -395,10 +417,12 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
if
(
self
->
len
==
self
->
size
&&
Bucket_grow
(
self
,
-
1
,
noval
)
<
0
)
goto
Done
;
if
(
self
->
len
>
i
)
{
if
(
self
->
len
>
i
)
{
memmove
(
self
->
keys
+
i
+
1
,
self
->
keys
+
i
,
sizeof
(
KEY_TYPE
)
*
(
self
->
len
-
i
));
if
(
self
->
values
)
{
if
(
self
->
values
)
{
memmove
(
self
->
values
+
i
+
1
,
self
->
values
+
i
,
sizeof
(
VALUE_TYPE
)
*
(
self
->
len
-
i
));
}
...
...
@@ -407,7 +431,8 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
COPY_KEY
(
self
->
keys
[
i
],
key
);
INCREF_KEY
(
self
->
keys
[
i
]);
if
(
!
noval
)
{
if
(
!
noval
)
{
COPY_VALUE
(
self
->
values
[
i
],
value
);
INCREF_VALUE
(
self
->
values
[
i
]);
}
...
...
@@ -418,7 +443,7 @@ _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
if
(
PER_CHANGED
(
self
)
>=
0
)
result
=
1
;
Done:
Done:
PER_UNUSE
(
self
);
return
result
;
}
...
...
@@ -462,7 +487,8 @@ update_from_seq(PyObject *map, PyObject *seq)
* want to use items() in those cases too.
*/
if
(
!
PySequence_Check
(
seq
)
||
/* or it "looks like a dict" */
PyObject_HasAttrString
(
seq
,
"iteritems"
))
{
PyObject_HasAttrString
(
seq
,
"iteritems"
))
{
PyObject
*
items
;
items
=
PyObject_GetAttrString
(
seq
,
"items"
);
if
(
items
==
NULL
)
...
...
@@ -478,15 +504,18 @@ update_from_seq(PyObject *map, PyObject *seq)
iter
=
PyObject_GetIter
(
seq
);
if
(
iter
==
NULL
)
goto
err
;
while
(
1
)
{
while
(
1
)
{
o
=
PyIter_Next
(
iter
);
if
(
o
==
NULL
)
{
if
(
o
==
NULL
)
{
if
(
PyErr_Occurred
())
goto
err
;
else
break
;
}
if
(
!
PyTuple_Check
(
o
)
||
PyTuple_GET_SIZE
(
o
)
!=
2
)
{
if
(
!
PyTuple_Check
(
o
)
||
PyTuple_GET_SIZE
(
o
)
!=
2
)
{
Py_DECREF
(
o
);
PyErr_SetString
(
PyExc_TypeError
,
"Sequence must contain 2-item tuples"
);
...
...
@@ -494,7 +523,8 @@ update_from_seq(PyObject *map, PyObject *seq)
}
k
=
PyTuple_GET_ITEM
(
o
,
0
);
v
=
PyTuple_GET_ITEM
(
o
,
1
);
if
(
PyObject_SetItem
(
map
,
k
,
v
)
<
0
)
{
if
(
PyObject_SetItem
(
map
,
k
,
v
)
<
0
)
{
Py_DECREF
(
o
);
goto
err
;
}
...
...
@@ -502,7 +532,7 @@ update_from_seq(PyObject *map, PyObject *seq)
}
err
=
0
;
err:
err:
Py_DECREF
(
iter
);
Py_DECREF
(
seq
);
return
err
;
...
...
@@ -585,12 +615,14 @@ Bucket_deleteNextBucket(Bucket *self)
PER_USE_OR_RETURN
(
self
,
-
1
);
successor
=
self
->
next
;
if
(
successor
)
{
if
(
successor
)
{
Bucket
*
next
;
/* Before: self -> successor -> next
* After: self --------------> next
*/
UNLESS
(
PER_USE
(
successor
))
goto
Done
;
UNLESS
(
PER_USE
(
successor
))
goto
Done
;
next
=
successor
->
next
;
PER_UNUSE
(
successor
);
...
...
@@ -602,7 +634,7 @@ Bucket_deleteNextBucket(Bucket *self)
}
result
=
0
;
Done:
Done:
PER_UNUSE
(
self
);
return
result
;
}
...
...
@@ -653,14 +685,17 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal,
int
copied
=
1
;
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
);
if
(
cmp
==
0
)
{
/* exact match at index i */
if
(
exclude_equal
)
{
if
(
exclude_equal
)
{
/* but we don't want an exact match */
if
(
low
)
++
i
;
...
...
@@ -679,7 +714,7 @@ Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int exclude_equal,
if
(
result
)
*
offset
=
i
;
Done:
Done:
PER_UNUSE
(
self
);
return
result
;
}
...
...
@@ -691,31 +726,36 @@ Bucket_maxminKey(Bucket *self, PyObject *args, int min)
int
rc
,
offset
=
0
;
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
);
UNLESS
(
self
->
len
)
goto
empty
;
UNLESS
(
self
->
len
)
goto
empty
;
/* Find the low range */
if
(
key
)
{
if
((
rc
=
Bucket_findRangeEnd
(
self
,
key
,
min
,
0
,
&
offset
))
<=
0
)
{
if
(
rc
<
0
)
return
NULL
;
if
(
rc
<
0
)
return
NULL
;
empty_bucket
=
0
;
goto
empty
;
}
}
else
if
(
min
)
offset
=
0
;
else
offset
=
self
->
len
-
1
;
else
if
(
min
)
offset
=
0
;
else
offset
=
self
->
len
-
1
;
COPY_KEY_TO_OBJECT
(
key
,
self
->
keys
[
offset
]);
PER_UNUSE
(
self
);
return
key
;
empty:
empty:
PyErr_SetString
(
PyExc_ValueError
,
empty_bucket
?
"empty bucket"
:
"no key satisfies the conditions"
);
...
...
@@ -745,7 +785,8 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
int
excludemax
=
0
;
int
rc
;
if
(
args
)
{
if
(
args
)
{
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kw
,
"|OOii"
,
search_keywords
,
&
min
,
&
max
,
...
...
@@ -754,19 +795,23 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
return
-
1
;
}
UNLESS
(
self
->
len
)
goto
empty
;
UNLESS
(
self
->
len
)
goto
empty
;
/* Find the low range */
if
(
min
!=
Py_None
)
{
if
(
min
!=
Py_None
)
{
rc
=
Bucket_findRangeEnd
(
self
,
min
,
1
,
excludemin
,
low
);
if
(
rc
<
0
)
return
-
1
;
if
(
rc
==
0
)
goto
empty
;
}
else
{
else
{
*
low
=
0
;
if
(
excludemin
)
{
if
(
excludemin
)
{
if
(
self
->
len
<
2
)
goto
empty
;
++*
low
;
...
...
@@ -774,16 +819,19 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
}
/* Find the high range */
if
(
max
!=
Py_None
)
{
if
(
max
!=
Py_None
)
{
rc
=
Bucket_findRangeEnd
(
self
,
max
,
0
,
excludemax
,
high
);
if
(
rc
<
0
)
return
-
1
;
if
(
rc
==
0
)
goto
empty
;
}
else
{
else
{
*
high
=
self
->
len
-
1
;
if
(
excludemax
)
{
if
(
excludemax
)
{
if
(
self
->
len
<
2
)
goto
empty
;
--*
high
;
...
...
@@ -794,7 +842,7 @@ Bucket_rangeSearch(Bucket *self, PyObject *args, PyObject *kw,
if
(
*
low
<=
*
high
)
return
0
;
empty:
empty:
*
low
=
0
;
*
high
=
-
1
;
return
0
;
...
...
@@ -825,7 +873,8 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw)
if
(
r
==
NULL
)
goto
err
;
for
(
i
=
low
;
i
<=
high
;
i
++
)
{
for
(
i
=
low
;
i
<=
high
;
i
++
)
{
COPY_KEY_TO_OBJECT
(
key
,
self
->
keys
[
i
]);
if
(
PyList_SetItem
(
r
,
i
-
low
,
key
)
<
0
)
goto
err
;
...
...
@@ -834,7 +883,7 @@ bucket_keys(Bucket *self, PyObject *args, PyObject *kw)
PER_UNUSE
(
self
);
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
return
NULL
;
...
...
@@ -858,21 +907,25 @@ bucket_values(Bucket *self, PyObject *args, PyObject *kw)
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
++
)
{
COPY_VALUE_TO_OBJECT
(
v
,
self
->
values
[
i
]);
UNLESS
(
v
)
goto
err
;
if
(
PyList_SetItem
(
r
,
i
-
low
,
v
)
<
0
)
goto
err
;
UNLESS
(
v
)
goto
err
;
if
(
PyList_SetItem
(
r
,
i
-
low
,
v
)
<
0
)
goto
err
;
}
PER_UNUSE
(
self
);
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
return
NULL
;
...
...
@@ -896,23 +949,29 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw)
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
++
)
{
UNLESS
(
item
=
PyTuple_New
(
2
))
goto
err
;
UNLESS
(
item
=
PyTuple_New
(
2
))
goto
err
;
COPY_KEY_TO_OBJECT
(
o
,
self
->
keys
[
i
]);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
PyTuple_SET_ITEM
(
item
,
0
,
o
);
COPY_VALUE_TO_OBJECT
(
o
,
self
->
values
[
i
]);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
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
;
}
...
...
@@ -920,7 +979,7 @@ bucket_items(Bucket *self, PyObject *args, PyObject *kw)
PER_UNUSE
(
self
);
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
Py_XDECREF
(
item
);
...
...
@@ -938,51 +997,62 @@ bucket_byValue(Bucket *self, PyObject *omin)
PER_USE_OR_RETURN
(
self
,
NULL
);
COPY_VALUE_FROM_ARG
(
min
,
omin
,
copied
);
UNLESS
(
copied
)
return
NULL
;
UNLESS
(
copied
)
return
NULL
;
for
(
i
=
0
,
l
=
0
;
i
<
self
->
len
;
i
++
)
if
(
TEST_VALUE
(
self
->
values
[
i
],
min
)
>=
0
)
l
++
;
UNLESS
(
r
=
PyList_New
(
l
))
goto
err
;
UNLESS
(
r
=
PyList_New
(
l
))
goto
err
;
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
]);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
PyTuple_SET_ITEM
(
item
,
1
,
o
);
COPY_VALUE
(
v
,
self
->
values
[
i
]);
NORMALIZE_VALUE
(
v
,
min
);
COPY_VALUE_TO_OBJECT
(
o
,
v
);
DECREF_VALUE
(
v
);
UNLESS
(
o
)
goto
err
;
UNLESS
(
o
)
goto
err
;
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
++
;
item
=
0
;
}
item
=
PyObject_GetAttr
(
r
,
sort_str
);
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_CallObject
(
item
,
NULL
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_GetAttr
(
r
,
reverse_str
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
ASSIGN
(
item
,
PyObject_CallObject
(
item
,
NULL
));
UNLESS
(
item
)
goto
err
;
UNLESS
(
item
)
goto
err
;
Py_DECREF
(
item
);
PER_UNUSE
(
self
);
return
r
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
r
);
Py_XDECREF
(
item
);
...
...
@@ -999,7 +1069,8 @@ _bucket_clear(Bucket *self)
*/
self
->
len
=
self
->
size
=
0
;
if
(
self
->
next
)
{
if
(
self
->
next
)
{
Py_DECREF
(
self
->
next
);
self
->
next
=
NULL
;
}
...
...
@@ -1008,7 +1079,8 @@ _bucket_clear(Bucket *self)
when neither key nor value is an object, i.e. II. */
(
void
)
len
;
if
(
self
->
keys
)
{
if
(
self
->
keys
)
{
#ifdef KEY_TYPE_IS_PYOBJECT
int
i
;
for
(
i
=
0
;
i
<
len
;
++
i
)
...
...
@@ -1018,7 +1090,8 @@ _bucket_clear(Bucket *self)
self
->
keys
=
NULL
;
}
if
(
self
->
values
)
{
if
(
self
->
values
)
{
#ifdef VALUE_TYPE_IS_PYOBJECT
int
i
;
for
(
i
=
0
;
i
<
len
;
++
i
)
...
...
@@ -1037,12 +1110,14 @@ bucket__p_deactivate(Bucket *self, PyObject *args, PyObject *keywords)
int
ghostify
=
1
;
PyObject
*
force
=
NULL
;
if
(
args
&&
PyTuple_GET_SIZE
(
args
)
>
0
)
{
if
(
args
&&
PyTuple_GET_SIZE
(
args
)
>
0
)
{
PyErr_SetString
(
PyExc_TypeError
,
"_p_deactivate takes no positional arguments"
);
return
NULL
;
}
if
(
keywords
)
{
if
(
keywords
)
{
int
size
=
PyDict_Size
(
keywords
);
force
=
PyDict_GetItemString
(
keywords
,
"force"
);
if
(
force
)
...
...
@@ -1054,7 +1129,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
;
if
(
!
ghostify
&&
force
)
{
if
(
PyObject_IsTrue
(
force
))
...
...
@@ -1078,7 +1154,8 @@ bucket_clear(Bucket *self, PyObject *args)
{
PER_USE_OR_RETURN
(
self
,
NULL
);
if
(
self
->
len
)
{
if
(
self
->
len
)
{
if
(
_bucket_clear
(
self
)
<
0
)
return
NULL
;
if
(
PER_CHANGED
(
self
)
<
0
)
...
...
@@ -1088,7 +1165,7 @@ bucket_clear(Bucket *self, PyObject *args)
Py_INCREF
(
Py_None
);
return
Py_None
;
err:
err:
PER_UNUSE
(
self
);
return
NULL
;
}
...
...
@@ -1126,7 +1203,8 @@ bucket_getstate(Bucket *self)
len
=
self
->
len
;
if
(
self
->
values
)
{
/* Bucket */
if
(
self
->
values
)
/* Bucket */
{
items
=
PyTuple_New
(
len
*
2
);
if
(
items
==
NULL
)
goto
err
;
...
...
@@ -1143,7 +1221,9 @@ bucket_getstate(Bucket *self)
PyTuple_SET_ITEM
(
items
,
l
,
o
);
l
++
;
}
}
else
{
/* Set */
}
else
/* Set */
{
items
=
PyTuple_New
(
len
);
if
(
items
==
NULL
)
goto
err
;
...
...
@@ -1164,7 +1244,7 @@ bucket_getstate(Bucket *self)
PER_UNUSE
(
self
);
return
state
;
err:
err:
PER_UNUSE
(
self
);
Py_XDECREF
(
items
);
return
NULL
;
...
...
@@ -1355,7 +1435,7 @@ bucket_contains(Bucket *self, PyObject *key)
int
result
=
-
1
;
if
(
asobj
!=
NULL
)
{
result
=
PyInt_AsLong
(
asobj
)
?
1
:
0
;
result
=
INT_AS_LONG
(
asobj
)
?
1
:
0
;
Py_DECREF
(
asobj
);
}
return
result
;
...
...
@@ -1404,12 +1484,13 @@ buildBucketIter(Bucket *self, PyObject *args, PyObject *kw, char kind)
items
=
(
BTreeItems
*
)
newBTreeItems
(
kind
,
self
,
lowoffset
,
self
,
highoffset
);
if
(
items
==
NULL
)
goto
Done
;
if
(
items
==
NULL
)
goto
Done
;
result
=
BTreeIter_new
(
items
);
/* win or lose, we're done */
Py_DECREF
(
items
);
Done:
Done:
PER_UNUSE
(
self
);
return
(
PyObject
*
)
result
;
}
...
...
@@ -1487,7 +1568,7 @@ _bucket__p_resolveConflict(PyObject *ob_type, PyObject *s[3])
else
result
=
bucket_merge
(
b
[
0
],
b
[
1
],
b
[
2
]);
Done:
Done:
Py_XDECREF
(
meth
);
Py_XDECREF
(
a
);
Py_XDECREF
(
b
[
0
]);
...
...
@@ -1505,7 +1586,7 @@ bucket__p_resolveConflict(Bucket *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"OOO"
,
&
s
[
0
],
&
s
[
1
],
&
s
[
2
]))
return
NULL
;
return
_bucket__p_resolveConflict
((
PyObject
*
)
self
->
ob_type
,
s
);
return
_bucket__p_resolveConflict
((
PyObject
*
)
Py_TYPE
(
self
)
,
s
);
}
#endif
...
...
@@ -1580,15 +1661,16 @@ static struct PyMethodDef Bucket_methods[] = {
"B.itervalues([min[,max]]) -> an iterator over the values of B"
},
{
"iteritems"
,
(
PyCFunction
)
Bucket_iteritems
,
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
EXTRA_BUCKET_METHODS
#endif
#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_deactivate"
,
(
PyCFunction
)
bucket__p_deactivate
,
METH_KEYWORDS
,
...
...
@@ -1648,8 +1730,10 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg)
goto
Done
;
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 */
(
void
)
i
;
(
void
)
len
;
#ifdef KEY_TYPE_IS_PYOBJECT
/* Keys are Python objects so need to be traversed. */
for
(
i
=
0
;
i
<
len
;
i
++
)
...
...
@@ -1667,7 +1751,7 @@ bucket_traverse(Bucket *self, visitproc visit, void *arg)
VISIT
(
self
->
next
);
Done:
Done:
return
err
;
#undef VISIT
...
...
@@ -1686,7 +1770,8 @@ static int
Bucket_length
(
Bucket
*
self
)
{
int
r
;
UNLESS
(
PER_USE
(
self
))
return
-
1
;
UNLESS
(
PER_USE
(
self
))
return
-
1
;
r
=
self
->
len
;
PER_UNUSE
(
self
);
return
r
;
...
...
@@ -1720,42 +1805,46 @@ bucket_repr(Bucket *self)
i
=
bucket_items
(
self
,
NULL
,
NULL
);
if
(
!
i
)
{
return
NULL
;
}
r
=
PyObject_Repr
(
i
);
Py_DECREF
(
i
);
if
(
!
r
)
{
if
(
!
r
)
{
return
NULL
;
}
rv
=
PyOS_snprintf
(
repr
,
sizeof
(
repr
),
"%s(%s)"
,
self
->
ob_type
->
tp_name
,
PyString_AS_STRING
(
r
));
if
(
rv
>
0
&&
rv
<
sizeof
(
repr
))
{
"%s(%s)"
,
Py_TYPE
(
self
)
->
tp_name
,
PyBytes_AS_STRING
(
r
));
if
(
rv
>
0
&&
rv
<
sizeof
(
repr
))
{
Py_DECREF
(
r
);
return
PyString
_FromStringAndSize
(
repr
,
strlen
(
repr
));
return
PyBytes
_FromStringAndSize
(
repr
,
strlen
(
repr
));
}
else
{
else
{
/* The static buffer wasn't big enough */
int
size
;
PyObject
*
s
;
/* 3 for the parens and the null byte */
size
=
strlen
(
self
->
ob_type
->
tp_name
)
+
PyString
_GET_SIZE
(
r
)
+
3
;
s
=
PyString
_FromStringAndSize
(
NULL
,
size
);
size
=
strlen
(
Py_TYPE
(
self
)
->
tp_name
)
+
PyBytes
_GET_SIZE
(
r
)
+
3
;
s
=
PyBytes
_FromStringAndSize
(
NULL
,
size
);
if
(
!
s
)
{
Py_DECREF
(
r
);
return
r
;
}
PyOS_snprintf
(
PyString
_AS_STRING
(
s
),
size
,
"%s(%s)"
,
self
->
ob_type
->
tp_name
,
PyString
_AS_STRING
(
r
));
PyOS_snprintf
(
PyBytes
_AS_STRING
(
s
),
size
,
"%s(%s)"
,
Py_TYPE
(
self
)
->
tp_name
,
PyBytes
_AS_STRING
(
r
));
Py_DECREF
(
r
);
return
s
;
}
}
static
PyTypeObject
BucketType
=
{
PyObject_HEAD_INIT
(
NULL
)
/* PyPersist_Type */
0
,
/* ob_size */
MODULE_NAME
MOD_NAME_PREFIX
"Bucket"
,
/* tp_name */
PyVarObject_HEAD_INIT
(
NULL
,
0
)
MODULE_NAME
MOD_NAME_PREFIX
"Bucket"
,
/* tp_name */
sizeof
(
Bucket
),
/* tp_basicsize */
0
,
/* tp_itemsize */
(
destructor
)
bucket_dealloc
,
/* tp_dealloc */
...
...
@@ -1773,7 +1862,8 @@ static PyTypeObject BucketType = {
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
0
,
/* tp_doc */
(
traverseproc
)
bucket_traverse
,
/* tp_traverse */
...
...
@@ -1800,7 +1890,8 @@ nextBucket(SetIteration *i)
{
if
(
i
->
position
>=
0
)
{
UNLESS
(
PER_USE
(
BUCKET
(
i
->
set
)))
return
-
1
;
UNLESS
(
PER_USE
(
BUCKET
(
i
->
set
)))
return
-
1
;
if
(
i
->
position
)
{
...
...
@@ -1825,6 +1916,5 @@ nextBucket(SetIteration *i)
PER_ALLOW_DEACTIVATION
(
BUCKET
(
i
->
set
));
}
return
0
;
}
BTrees/SetTemplate.c
View file @
f108be3a
...
...
@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE
****************************************************************************/
#include "_compat.h"
#define SETTEMPLATE_C "$Id$\n"
...
...
@@ -20,9 +21,11 @@ Set_insert(Bucket *self, PyObject *args)
PyObject
*
key
;
int
i
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
if
(
(
i
=
_bucket_set
(
self
,
key
,
Py_None
,
1
,
1
,
0
))
<
0
)
return
NULL
;
return
PyInt_FromLong
(
i
);
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
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
...
...
@@ -55,7 +58,7 @@ _Set_update(Bucket *self, PyObject *seq)
n
+=
ind
;
}
err:
err:
Py_DECREF
(
iter
);
if
(
ind
<
0
)
return
-
1
;
...
...
@@ -77,7 +80,7 @@ Set_update(Bucket *self, PyObject *args)
return
NULL
;
}
return
PyInt_FromLong
(
n
);
return
INT_FROM_LONG
(
n
);
}
static
PyObject
*
...
...
@@ -85,8 +88,10 @@ Set_remove(Bucket *self, PyObject *args)
{
PyObject
*
key
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
if
(
_bucket_set
(
self
,
key
,
NULL
,
0
,
1
,
0
)
<
0
)
return
NULL
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
if
(
_bucket_set
(
self
,
key
,
NULL
,
0
,
1
,
0
)
<
0
)
return
NULL
;
Py_INCREF
(
Py_None
);
return
Py_None
;
...
...
@@ -109,7 +114,8 @@ _set_setstate(Bucket *self, PyObject *args)
return
-
1
;
}
if
((
l
=
PyTuple_Size
(
items
))
<
0
)
return
-
1
;
if
((
l
=
PyTuple_Size
(
items
))
<
0
)
return
-
1
;
for
(
i
=
self
->
len
;
--
i
>=
0
;
)
{
...
...
@@ -125,7 +131,8 @@ _set_setstate(Bucket *self, PyObject *args)
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
->
size
=
l
;
}
...
...
@@ -134,7 +141,8 @@ _set_setstate(Bucket *self, PyObject *args)
{
k
=
PyTuple_GET_ITEM
(
items
,
i
);
COPY_KEY_FROM_ARG
(
self
->
keys
[
i
],
k
,
copied
);
UNLESS
(
copied
)
return
-
1
;
UNLESS
(
copied
)
return
-
1
;
INCREF_KEY
(
self
->
keys
[
i
]);
}
...
...
@@ -154,13 +162,15 @@ set_setstate(Bucket *self, PyObject *args)
{
int
r
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
args
))
return
NULL
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
args
))
return
NULL
;
PER_PREVENT_DEACTIVATION
(
self
);
r
=
_set_setstate
(
self
,
args
);
PER_UNUSE
(
self
);
if
(
r
<
0
)
return
NULL
;
if
(
r
<
0
)
return
NULL
;
Py_INCREF
(
Py_None
);
return
Py_None
;
}
...
...
@@ -190,7 +200,8 @@ static struct PyMethodDef Set_methods[] = {
"If an argument is given, find the minimum >= the argument"
},
#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_deactivate"
,
(
PyCFunction
)
bucket__p_deactivate
,
METH_KEYWORDS
,
...
...
@@ -235,12 +246,14 @@ set_repr(Bucket *self)
PyObject
*
r
,
*
t
;
if
(
!
format
)
format
=
PyString_FromString
(
MOD_NAME_PREFIX
"Set(%s)"
);
UNLESS
(
t
=
PyTuple_New
(
1
))
return
NULL
;
UNLESS
(
r
=
bucket_keys
(
self
,
NULL
,
NULL
))
goto
err
;
format
=
TEXT_FROM_STRING
(
MOD_NAME_PREFIX
"Set(%s)"
);
UNLESS
(
t
=
PyTuple_New
(
1
))
return
NULL
;
UNLESS
(
r
=
bucket_keys
(
self
,
NULL
,
NULL
))
goto
err
;
PyTuple_SET_ITEM
(
t
,
0
,
r
);
r
=
t
;
ASSIGN
(
r
,
PyString_Format
(
format
,
r
));
ASSIGN
(
r
,
TEXT_FORMAT
(
format
,
r
));
return
r
;
err:
Py_DECREF
(
t
);
...
...
@@ -291,8 +304,7 @@ static PySequenceMethods set_as_sequence = {
};
static
PyTypeObject
SetType
=
{
PyObject_HEAD_INIT
(
NULL
)
/* PyPersist_Type */
0
,
/* ob_size */
PyVarObject_HEAD_INIT
(
NULL
,
0
)
/* PyPersist_Type */
MODULE_NAME
MOD_NAME_PREFIX
"Set"
,
/* tp_name */
sizeof
(
Bucket
),
/* tp_basicsize */
0
,
/* tp_itemsize */
...
...
@@ -311,7 +323,8 @@ static PyTypeObject SetType = {
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
0
,
/* tp_doc */
(
traverseproc
)
bucket_traverse
,
/* tp_traverse */
...
...
@@ -339,7 +352,8 @@ nextSet(SetIteration *i)
if
(
i
->
position
>=
0
)
{
UNLESS
(
PER_USE
(
BUCKET
(
i
->
set
)))
return
-
1
;
UNLESS
(
PER_USE
(
BUCKET
(
i
->
set
)))
return
-
1
;
if
(
i
->
position
)
{
...
...
BTrees/TreeSetTemplate.c
View file @
f108be3a
...
...
@@ -11,6 +11,7 @@
FOR A PARTICULAR PURPOSE
****************************************************************************/
#include "_compat.h"
#define TREESETTEMPLATE_C "$Id$\n"
...
...
@@ -25,7 +26,7 @@ TreeSet_insert(BTree *self, PyObject *args)
i
=
_BTree_set
(
self
,
key
,
Py_None
,
1
,
1
);
if
(
i
<
0
)
return
NULL
;
return
PyInt_FromLong
(
i
);
return
INT_FROM_LONG
(
i
);
}
/* _Set_update and _TreeSet_update are identical except for the
...
...
@@ -42,9 +43,11 @@ _TreeSet_update(BTree *self, PyObject *seq)
if
(
iter
==
NULL
)
return
-
1
;
while
(
1
)
{
while
(
1
)
{
v
=
PyIter_Next
(
iter
);
if
(
v
==
NULL
)
{
if
(
v
==
NULL
)
{
if
(
PyErr_Occurred
())
goto
err
;
else
...
...
@@ -58,7 +61,7 @@ _TreeSet_update(BTree *self, PyObject *seq)
n
+=
ind
;
}
err:
err:
Py_DECREF
(
iter
);
if
(
ind
<
0
)
return
-
1
;
...
...
@@ -74,13 +77,14 @@ TreeSet_update(BTree *self, PyObject *args)
if
(
!
PyArg_ParseTuple
(
args
,
"|O:update"
,
&
seq
))
return
NULL
;
if
(
seq
)
{
if
(
seq
)
{
n
=
_TreeSet_update
(
self
,
seq
);
if
(
n
<
0
)
return
NULL
;
}
return
PyInt_FromLong
(
n
);
return
INT_FROM_LONG
(
n
);
}
...
...
@@ -89,8 +93,10 @@ TreeSet_remove(BTree *self, PyObject *args)
{
PyObject
*
key
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
if
(
_BTree_set
(
self
,
key
,
NULL
,
0
,
1
)
<
0
)
return
NULL
;
UNLESS
(
PyArg_ParseTuple
(
args
,
"O"
,
&
key
))
return
NULL
;
if
(
_BTree_set
(
self
,
key
,
NULL
,
0
,
1
)
<
0
)
return
NULL
;
Py_INCREF
(
Py_None
);
return
Py_None
;
}
...
...
@@ -100,18 +106,21 @@ TreeSet_setstate(BTree *self, PyObject *args)
{
int
r
;
if
(
!
PyArg_ParseTuple
(
args
,
"O"
,
&
args
))
return
NULL
;
if
(
!
PyArg_ParseTuple
(
args
,
"O"
,
&
args
))
return
NULL
;
PER_PREVENT_DEACTIVATION
(
self
);
r
=
_BTree_setstate
(
self
,
args
,
1
);
PER_UNUSE
(
self
);
if
(
r
<
0
)
return
NULL
;
if
(
r
<
0
)
return
NULL
;
Py_INCREF
(
Py_None
);
return
Py_None
;
}
static
struct
PyMethodDef
TreeSet_methods
[]
=
{
static
struct
PyMethodDef
TreeSet_methods
[]
=
{
{
"__getstate__"
,
(
PyCFunction
)
BTree_getstate
,
METH_NOARGS
,
"__getstate__() -> state
\n\n
"
"Return the picklable state of the TreeSet."
},
...
...
@@ -158,7 +167,8 @@ static struct PyMethodDef TreeSet_methods[] = {
"Perform sanity check on TreeSet, and raise exception if flawed."
},
#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_deactivate"
,
(
PyCFunction
)
BTree__p_deactivate
,
METH_KEYWORDS
,
...
...
@@ -198,10 +208,10 @@ TreeSet_init(PyObject *self, PyObject *args, PyObject *kwds)
return
0
;
}
static
PyTypeObject
TreeSetType
=
{
PyObject_HEAD_INIT
(
NULL
)
/* PyPersist_Type */
0
,
/* ob_size */
MODULE_NAME
MOD_NAME_PREFIX
"TreeSet"
,
/* tp_name */
static
PyTypeObject
TreeSetType
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
MODULE_NAME
MOD_NAME_PREFIX
"TreeSet"
,
/* tp_name */
sizeof
(
BTree
),
/* tp_basicsize */
0
,
/* tp_itemsize */
(
destructor
)
BTree_dealloc
,
/* tp_dealloc */
...
...
@@ -219,7 +229,8 @@ static PyTypeObject TreeSetType = {
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
0
,
/* tp_doc */
(
traverseproc
)
BTree_traverse
,
/* tp_traverse */
...
...
BTrees/_compat.h
0 → 100644
View file @
f108be3a
/* Straddle Python 2 / 3 */
#ifndef BTREES__COMPAT_H
#define BTREES__COMPAT_H
#if PY_MAJOR_VERSION >= 3
#ifdef INTERN
#undef INTERN
#endif
#ifdef INT_FROM_LONG
#undef INT_FROM_LONG
#endif
#ifdef INT_CHECK
#undef INT_CHECK
#endif
#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 */
BTrees/_fsBTree.c
View file @
f108be3a
...
...
@@ -40,14 +40,14 @@ typedef unsigned char char6[6];
#define KEYMACROS_H "$Id$\n"
#define KEY_TYPE char2
#undef KEY_TYPE_IS_PYOBJECT
#define KEY_CHECK(K) (Py
String_Check(K) && PyString
_GET_SIZE(K)==2)
#define KEY_CHECK(K) (Py
Bytes_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 DECREF_KEY(KEY)
#define INCREF_KEY(k)
#define COPY_KEY(KEY, E) (*(KEY)=*(E), (KEY)[1]=(E)[1])
#define COPY_KEY_TO_OBJECT(O, K) O=Py
String
_FromStringAndSize((const char*)K,2)
#define COPY_KEY_TO_OBJECT(O, K) O=Py
Bytes
_FromStringAndSize((const char*)K,2)
#define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \
if (KEY_CHECK(ARG)) memcpy(TARGET, Py
String
_AS_STRING(ARG), 2); else { \
if (KEY_CHECK(ARG)) memcpy(TARGET, Py
Bytes
_AS_STRING(ARG), 2); else { \
PyErr_SetString(PyExc_TypeError, "expected two-character string key"); \
(STATUS)=0; }
...
...
@@ -59,10 +59,10 @@ typedef unsigned char char6[6];
#define DECREF_VALUE(k)
#define INCREF_VALUE(k)
#define COPY_VALUE(V, E) (memcpy(V, E, 6))
#define COPY_VALUE_TO_OBJECT(O, K) O=Py
String
_FromStringAndSize((const char*)K,6)
#define COPY_VALUE_TO_OBJECT(O, K) O=Py
Bytes
_FromStringAndSize((const char*)K,6)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
if ((Py
String_Check(ARG) && PyString
_GET_SIZE(ARG)==6)) \
memcpy(TARGET, Py
String
_AS_STRING(ARG), 6); else { \
if ((Py
Bytes_Check(ARG) && PyBytes
_GET_SIZE(ARG)==6)) \
memcpy(TARGET, Py
Bytes
_AS_STRING(ARG), 6); else { \
PyErr_SetString(PyExc_TypeError, "expected six-character string key"); \
(STATUS)=0; }
...
...
@@ -93,11 +93,11 @@ bucket_toString(PyObject *oself)
len
=
self
->
len
;
items
=
Py
String
_FromStringAndSize
(
NULL
,
len
*
8
);
items
=
Py
Bytes
_FromStringAndSize
(
NULL
,
len
*
8
);
if
(
items
==
NULL
)
goto
err
;
memcpy
(
Py
String
_AS_STRING
(
items
),
self
->
keys
,
len
*
2
);
memcpy
(
Py
String
_AS_STRING
(
items
)
+
len
*
2
,
self
->
values
,
len
*
6
);
memcpy
(
Py
Bytes
_AS_STRING
(
items
),
self
->
keys
,
len
*
2
);
memcpy
(
Py
Bytes
_AS_STRING
(
items
)
+
len
*
2
,
self
->
values
,
len
*
6
);
PER_UNUSE
(
self
);
return
items
;
...
...
@@ -116,7 +116,7 @@ bucket_fromString(PyObject *oself, PyObject *state)
KEY_TYPE
*
keys
;
VALUE_TYPE
*
values
;
len
=
Py
String
_Size
(
state
);
len
=
Py
Bytes
_Size
(
state
);
if
(
len
<
0
)
return
NULL
;
...
...
@@ -144,8 +144,8 @@ bucket_fromString(PyObject *oself, PyObject *state)
self
->
size
=
len
;
}
memcpy
(
self
->
keys
,
Py
String
_AS_STRING
(
state
),
len
*
2
);
memcpy
(
self
->
values
,
Py
String
_AS_STRING
(
state
)
+
len
*
2
,
len
*
6
);
memcpy
(
self
->
keys
,
Py
Bytes
_AS_STRING
(
state
),
len
*
2
);
memcpy
(
self
->
values
,
Py
Bytes
_AS_STRING
(
state
)
+
len
*
2
,
len
*
6
);
self
->
len
=
len
;
...
...
BTrees/floatvaluemacros.h
View file @
f108be3a
...
...
@@ -13,7 +13,7 @@
#define COPY_VALUE_TO_OBJECT(O, K) O=PyFloat_FromDouble(K)
#define COPY_VALUE_FROM_ARG(TARGET, ARG, STATUS) \
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 { \
PyErr_SetString(PyExc_TypeError, "expected float or int value"); \
(STATUS)=0; (TARGET)=0; }
...
...
BTrees/intkeymacros.h
View file @
f108be3a
...
...
@@ -8,7 +8,7 @@
#define KEY_CHECK longlong_check
#define COPY_KEY_TO_OBJECT(O, K) O=longlong_as_object(K)
#define COPY_KEY_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 (PyLong_Check(ARG)) { \
PyErr_SetString(PyExc_ValueError, "long integer out of range"); \
...
...
@@ -19,11 +19,11 @@
#else
/* C int as key */
#define KEY_TYPE int
#define KEY_CHECK
PyInt_Check
#define COPY_KEY_TO_OBJECT(O, K) O=
PyInt_FromLong
(K)
#define KEY_CHECK
INT_CHECK
#define COPY_KEY_TO_OBJECT(O, K) O=
INT_FROM_LONG
(K)
#define COPY_KEY_FROM_ARG(TARGET, ARG, STATUS) \
if (
PyInt_Check
(ARG)) { \
long vcopy =
PyInt
_AS_LONG(ARG); \
if (
INT_CHECK
(ARG)) { \
long vcopy =
INT
_AS_LONG(ARG); \
if ((int)vcopy != vcopy) { \
PyErr_SetString(PyExc_TypeError, "integer out of range"); \
(STATUS)=0; (TARGET)=0; \
...
...
BTrees/intvaluemacros.h
View file @
f108be3a
...
...
@@ -7,7 +7,7 @@
#define VALUE_PARSE "L"
#define COPY_VALUE_TO_OBJECT(O, K) O=longlong_as_object(K)
#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 (PyLong_Check(ARG)) { \
PyErr_SetString(PyExc_ValueError, "long integer out of range"); \
...
...
@@ -18,11 +18,11 @@
#else
#define VALUE_TYPE int
#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) \
if (
PyInt_Check
(ARG)) { \
long vcopy =
PyInt
_AS_LONG(ARG); \
if (
INT_CHECK
(ARG)) { \
long vcopy =
INT
_AS_LONG(ARG); \
if ((int)vcopy != vcopy) { \
PyErr_SetString(PyExc_TypeError, "integer out of range"); \
(STATUS)=0; (TARGET)=0; \
...
...
BTrees/objectkeymacros.h
View file @
f108be3a
...
...
@@ -3,6 +3,7 @@
#define KEY_TYPE_IS_PYOBJECT
#include "Python.h"
#include "_compat.h"
static
PyObject
*
object_
;
...
...
@@ -15,12 +16,9 @@ check_argument_cmp(PyObject *arg)
/* arg->ob_type->tp_compare, */
/* ((PyTypeObject *)object_)->ob_type->tp_compare); */
if
(
arg
->
ob_type
->
tp_richcompare
==
NULL
&&
#if PY_MAJOR_VERSION==2 && PY_MINOR_VERSION < 6
arg
->
ob_type
->
tp_compare
==
NULL
#else
arg
->
ob_type
->
tp_compare
==
if
(
Py_TYPE
(
arg
)
->
tp_richcompare
==
NULL
#ifndef PY3K
&&
Py_TYPE
(
arg
)
->
tp_compare
==
((
PyTypeObject
*
)
object_
)
->
ob_type
->
tp_compare
#endif
)
...
...
@@ -31,7 +29,8 @@ check_argument_cmp(PyObject *arg)
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 DECREF_KEY(KEY) Py_DECREF(KEY)
#define COPY_KEY(KEY, E) KEY=(E)
...
...
BTrees/objectvaluemacros.h
View file @
f108be3a
#define VALUEMACROS_H "$Id$\n"
#define VALUE_TYPE 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 INCREF_VALUE(k) Py_INCREF(k)
#define DECREF_VALUE(k) Py_DECREF(k)
...
...
BTrees/py24compat.h
deleted
100644 → 0
View file @
6cb58ca0
/* 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 */
setup.py
View file @
f108be3a
...
...
@@ -100,16 +100,22 @@ is_jython = 'java' in sys.platform
# Jython cannot build the C optimizations, while on PyPy they are
# anti-optimizations (the C extension compatibility layer is known-slow,
# 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
=
[]
else
:
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'
,
'zope.interface'
,
]
]
TESTS_REQUIRE
=
REQUIRES
+
[
'transaction'
]
setup
(
name
=
'BTrees'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment