Commit e9cf0b8b authored by Jim Fulton's avatar Jim Fulton

Merged Jeremy and Tim's changes from the zodb33-devel-branch.

parent 502b3e4f
This diff is collapsed.
......@@ -12,34 +12,20 @@
****************************************************************************/
#include "Python.h"
/* include structmember.h for offsetof */
#include "structmember.h"
#ifdef PERSISTENT
#include "cPersistence.h"
/***************************************************************
The following are macros that ought to be in cPersistence.h */
#ifndef PER_USE
#define PER_USE(O) \
(((O)->state != cPersistent_GHOST_STATE \
|| (cPersistenceCAPI->setstate((PyObject*)(O)) >= 0)) \
? (((O)->state==cPersistent_UPTODATE_STATE) \
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)
#define PER_ACCESSED(O) ((O)->atime=((long)(time(NULL)/3))%65536)
#endif
/***************************************************************/
//#include "persistence/persistenceAPI.h"
#else
#include "ExtensionClass.h"
#define PER_USE_OR_RETURN(self, NULL)
#define PER_ALLOW_DEACTIVATION(self)
#define PER_PREVENT_DEACTIVATION(self)
#define PER_DEL(self)
#define PER_USE(O) 1
#define PER_ACCESSED(O) 1
#define PER_CHANGED(O) 0
#endif
/* So sue me. This pair gets used all over the place, so much so that it
......@@ -53,15 +39,23 @@
PER_ACCESSED(OBJ); \
} while (0)
static PyObject *sort_str, *reverse_str, *items_str, *__setstate___str;
/*
The tp_name slots of the various BTree types contain the fully
qualified names of the types, e.g. zodb.btrees.OOBTree.OOBTree.
The full name is usd to support pickling and because it is not
possible to modify the __module__ slot of a type dynamically. (This
may be a bug in Python 2.2).
*/
#define MODULE_NAME "BTrees._" MOD_NAME_PREFIX "BTree."
static PyObject *sort_str, *reverse_str, *__setstate___str,
*_bucket_type_str;
static PyObject *ConflictError = NULL;
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define ASSIGNC(V,E) (Py_INCREF((E)), PyVar_Assign(&(V),(E)))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define LIST(O) ((PyListObject*)(O))
#define OBJECT(O) ((PyObject*)(O))
#define MIN_BUCKET_ALLOC 16
......@@ -150,7 +144,8 @@ typedef struct BTree_s {
BTreeItem *data;
} BTree;
staticforward PyExtensionClass BTreeType;
static PyTypeObject BTreeType;
static PyTypeObject BucketType;
#define BTREE(O) ((BTree*)(O))
......@@ -254,9 +249,9 @@ IndexError(int i)
{
PyObject *v;
v=PyInt_FromLong(i);
UNLESS (v) {
v=Py_None;
v = PyInt_FromLong(i);
if (!v) {
v = Py_None;
Py_INCREF(v);
}
PyErr_SetObject(PyExc_IndexError, v);
......@@ -286,8 +281,7 @@ PreviousBucket(Bucket **current, Bucket *first)
trailing = first;
PER_USE_OR_RETURN(first, -1);
first = first->next;
PER_ALLOW_DEACTIVATION(trailing);
PER_ACCESSED(trailing);
PER_UNUSE(trailing);
if (first == *current) {
*current = trailing;
......@@ -300,33 +294,45 @@ PreviousBucket(Bucket **current, Bucket *first)
}
static void *
PyMalloc(size_t sz)
BTree_Malloc(size_t sz)
{
void *r;
ASSERT(sz > 0, "non-positive size malloc", NULL);
if ((r = malloc(sz))) return r;
r = malloc(sz);
if (r)
return r;
PyErr_NoMemory();
return NULL;
}
static void *
PyRealloc(void *p, size_t sz)
BTree_Realloc(void *p, size_t sz)
{
void *r;
ASSERT(sz > 0, "non-positive size realloc", NULL);
if (p) r = realloc(p,sz);
else r = malloc(sz);
if (p)
r = realloc(p, sz);
else
r = malloc(sz);
UNLESS (r) PyErr_NoMemory();
UNLESS (r)
PyErr_NoMemory();
return r;
}
/* Shared keyword-argument list for BTree/Bucket
* (iter)?(keys|values|items)
*/
static char *search_keywords[] = {"min", "max",
"excludemin", "excludemax",
0};
#include "BTreeItemsTemplate.c"
#include "BucketTemplate.c"
#include "SetTemplate.c"
......@@ -373,7 +379,7 @@ static char BTree_module_documentation[] =
"\n"
MASTER_ID
BTREEITEMSTEMPLATE_C
"$Id: BTreeModuleTemplate.c,v 1.37 2002/06/25 22:02:27 tim_one Exp $\n"
"$Id: BTreeModuleTemplate.c,v 1.38 2003/11/28 16:44:44 jim Exp $\n"
BTREETEMPLATE_C
BUCKETTEMPLATE_C
KEYMACROS_H
......@@ -385,44 +391,38 @@ VALUEMACROS_H
BTREEITEMSTEMPLATE_C
;
int
init_persist_type(PyTypeObject *type)
{
type->ob_type = &PyType_Type;
type->tp_base = cPersistenceCAPI->pertype;
if (PyType_Ready(type) < 0)
return 0;
return 1;
}
void
INITMODULE (void)
{
PyObject *m, *d, *c;
UNLESS (sort_str=PyString_FromString("sort")) return;
UNLESS (reverse_str=PyString_FromString("reverse")) return;
UNLESS (items_str=PyString_FromString("items")) return;
UNLESS (__setstate___str=PyString_FromString("__setstate__")) return;
UNLESS (PyExtensionClassCAPI=PyCObject_Import("ExtensionClass","CAPI"))
sort_str = PyString_InternFromString("sort");
if (!sort_str)
return;
reverse_str = PyString_InternFromString("reverse");
if (!reverse_str)
return;
__setstate___str = PyString_InternFromString("__setstate__");
if (!__setstate___str)
return;
_bucket_type_str = PyString_InternFromString("_bucket_type");
if (!_bucket_type_str)
return;
#ifdef PERSISTENT
if ((cPersistenceCAPI=PyCObject_Import("cPersistence","CAPI")))
{
BucketType.methods.link=cPersistenceCAPI->methods;
BucketType.tp_getattro=cPersistenceCAPI->getattro;
BucketType.tp_setattro=cPersistenceCAPI->setattro;
SetType.methods.link=cPersistenceCAPI->methods;
SetType.tp_getattro=cPersistenceCAPI->getattro;
SetType.tp_setattro=cPersistenceCAPI->setattro;
BTreeType.methods.link=cPersistenceCAPI->methods;
BTreeType.tp_getattro=cPersistenceCAPI->getattro;
BTreeType.tp_setattro=cPersistenceCAPI->setattro;
TreeSetType.methods.link=cPersistenceCAPI->methods;
TreeSetType.tp_getattro=cPersistenceCAPI->getattro;
TreeSetType.tp_setattro=cPersistenceCAPI->setattro;
}
else return;
/* Grab the ConflictError class */
m = PyImport_ImportModule("ZODB.POSException");
if (m != NULL) {
c = PyObject_GetAttrString(m, "BTreesConflictError");
if (c != NULL)
......@@ -435,31 +435,55 @@ INITMODULE (void)
ConflictError=PyExc_ValueError;
}
#else
BTreeType.tp_getattro=PyExtensionClassCAPI->getattro;
BucketType.tp_getattro=PyExtensionClassCAPI->getattro;
SetType.tp_getattro=PyExtensionClassCAPI->getattro;
TreeSetType.tp_getattro=PyExtensionClassCAPI->getattro;
#endif
/* Initialize the PyPersist_C_API and the type objects. */
cPersistenceCAPI = PyCObject_Import("persistent.cPersistence", "CAPI");
if (cPersistenceCAPI == NULL)
return;
BTreeItemsType.ob_type=&PyType_Type;
BTreeItemsType.ob_type = &PyType_Type;
BTreeIter_Type.ob_type = &PyType_Type;
BTreeIter_Type.tp_getattro = PyObject_GenericGetAttr;
BucketType.tp_new = PyType_GenericNew;
SetType.tp_new = PyType_GenericNew;
BTreeType.tp_new = PyType_GenericNew;
TreeSetType.tp_new = PyType_GenericNew;
if (!init_persist_type(&BucketType))
return;
if (!init_persist_type(&BTreeType))
return;
if (!init_persist_type(&SetType))
return;
if (!init_persist_type(&TreeSetType))
return;
#ifdef INTSET_H
UNLESS(d = PyImport_ImportModule("intSet")) return;
UNLESS(intSetType = PyObject_GetAttrString (d, "intSet")) return;
Py_DECREF (d);
#endif
if (PyDict_SetItem(BTreeType.tp_dict, _bucket_type_str,
(PyObject *)&BucketType) < 0) {
fprintf(stderr, "btree failed\n");
return;
}
if (PyDict_SetItem(TreeSetType.tp_dict, _bucket_type_str,
(PyObject *)&SetType) < 0) {
fprintf(stderr, "bucket failed\n");
return;
}
/* Create the module and add the functions */
m = Py_InitModule4("_" MOD_NAME_PREFIX "BTree", module_methods,
BTree_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
m = Py_InitModule4("_" MOD_NAME_PREFIX "BTree",
module_methods, BTree_module_documentation,
(PyObject *)NULL, PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,MOD_NAME_PREFIX "Bucket", BucketType);
PyExtensionClass_Export(d,MOD_NAME_PREFIX "BTree", BTreeType);
PyExtensionClass_Export(d,MOD_NAME_PREFIX "Set", SetType);
PyExtensionClass_Export(d,MOD_NAME_PREFIX "TreeSet", TreeSetType);
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Bucket",
(PyObject *)&BucketType) < 0)
return;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "BTree",
(PyObject *)&BTreeType) < 0)
return;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "Set",
(PyObject *)&SetType) < 0)
return;
if (PyDict_SetItemString(d, MOD_NAME_PREFIX "TreeSet",
(PyObject *)&TreeSetType) < 0)
return;
}
This diff is collapsed.
This diff is collapsed.
......@@ -14,8 +14,3 @@
# hack to overcome dynamic-linking headache.
from _IIBTree import *
# We don't really want _ names in pickles, so update all of the __module__
# references.
for obj in IIBucket, IIBTree, IISet, IITreeSet:
obj.__module__ = __name__
......@@ -14,8 +14,3 @@
# hack to overcome dynamic-linking headache.
from _IOBTree import *
# We don't really want _ names in pickles, so update all of the __module__
# references.
for obj in IOBucket, IOBTree, IOSet, IOTreeSet:
obj.__module__ = __name__
......@@ -348,6 +348,38 @@ class IIMerge(IMerge):
Note that c1 and c2 must be collections.
"""
class IMergeIntegerKey(IMerge):
"""IMerge-able objects with integer keys.
Concretely, this means the types in IOBTree and IIBTree.
"""
def multiunion(seq):
"""Return union of (zero or more) integer sets, as an integer set.
seq is a sequence of objects each convertible to an integer set.
These objects are convertible to an integer set:
+ An integer, which is added to the union.
+ A Set or TreeSet from the same module (for example, an
IIBTree.TreeSet for IIBTree.multiunion()). The elements of the
set are added to the union.
+ A Bucket or BTree from the same module (for example, an
IOBTree.IOBTree for IOBTree.multiunion()). The keys of the
mapping are added to the union.
The union is returned as a Set from the same module (for example,
IIBTree.multiunion() returns an IIBTree.IISet).
The point to this method is that it can run much faster than
doing a sequence of two-input union() calls. Under the covers,
all the integers in all the inputs are sorted via a single
linear-time radix sort, then duplicates are removed in a second
linear-time pass.
"""
###############################################################
# IMPORTANT NOTE
#
......@@ -359,7 +391,10 @@ class IIMerge(IMerge):
#
################################################################
OOBTree.OOSet.__implements__=ISet
OOBTree.OOTreeSet.__implements__=ITreeSet
OOBTree.OOBucket.__implements__=IDictionaryIsh
OOBTree.OOBTree.__implements__=IBTree
# XXX Need to use the new declaration syntax once it is available
# for Zope 2.
## OOBTree.OOSet.__implements__=ISet
## OOBTree.OOTreeSet.__implements__=ITreeSet
## OOBTree.OOBucket.__implements__=IDictionaryIsh
## OOBTree.OOBTree.__implements__=IBTree
......@@ -12,32 +12,47 @@
#
##############################################################################
import Persistence
import persistent
class Length(Persistence.Persistent):
class Length(persistent.Persistent):
"""BTree lengths are too expensive to compute
Objects that use BTrees need to keep track of lengths themselves.
This class provides an object for doing this.
As a bonus, the object support application-level conflict resolution.
As a bonus, the object support application-level conflict
resolution.
It is tempting to to assign length objects to __len__ attributes
to provide instance-specific __len__ methods. However, this no
longer works as expected, because new-style classes cache
class-defined slot methods (like __len__) in C type slots. Thus,
instance-define slot fillers are ignores.
"""
def __init__(self, v=0): self.value=v
def __init__(self, v=0):
self.value = v
def __getstate__(self): return self.value
def __getstate__(self):
return self.value
def __setstate__(self, v): self.value=v
def __setstate__(self, v):
self.value = v
def set(self, v): self.value=v
def set(self, v):
self.value = v
def _p_resolveConflict(self, old, s1, s2): return s1 + s2 - old
def _p_resolveConflict(self, old, s1, s2):
return s1 + s2 - old
def _p_independent(self):
# My state doesn't depend on or materially effect the state of
# other objects.
return 1
def change(self, delta): self.value = self.value + delta
def change(self, delta):
self.value += delta
def __call__(self, *args): return self.value
def __call__(self, *args):
return self.value
......@@ -12,7 +12,7 @@
****************************************************************************/
#define MERGETEMPLATE_C "$Id: MergeTemplate.c,v 1.16 2003/01/17 17:20:49 tim_one Exp $\n"
#define MERGETEMPLATE_C "$Id: MergeTemplate.c,v 1.17 2003/11/28 16:44:44 jim Exp $\n"
/****************************************************************************
Set operations
......@@ -21,11 +21,11 @@
static int
merge_output(Bucket *r, SetIteration *i, int mapping)
{
if(r->len >= r->size && Bucket_grow(r, -1, ! mapping) < 0) return -1;
if (r->len >= r->size && Bucket_grow(r, -1, !mapping) < 0)
return -1;
COPY_KEY(r->keys[r->len], i->key);
INCREF_KEY(r->keys[r->len]);
if (mapping)
{
if (mapping) {
COPY_VALUE(r->values[r->len], i->value);
INCREF_VALUE(r->values[r->len]);
}
......@@ -33,6 +33,10 @@ merge_output(Bucket *r, SetIteration *i, int mapping)
return 0;
}
/* The "reason" argument is a little integer giving "a reason" for the
* error. In the Zope3 codebase, these are mapped to explanatory strings
* via zodb/btrees/interfaces.py.
*/
static PyObject *
merge_error(int p1, int p2, int p3, int reason)
{
......@@ -40,7 +44,7 @@ merge_error(int p1, int p2, int p3, int reason)
UNLESS (r=Py_BuildValue("iiii", p1, p2, p3, reason)) r=Py_None;
if (ConflictError == NULL) {
ConflictError=PyExc_ValueError;
ConflictError = PyExc_ValueError;
Py_INCREF(ConflictError);
}
PyErr_SetObject(ConflictError, r);
......@@ -52,6 +56,33 @@ merge_error(int p1, int p2, int p3, int reason)
return NULL;
}
/* It's hard to explain "the rules" for bucket_merge, in large part because
* any automatic conflict-resolution scheme is going to be incorrect for
* some endcases of *some* app. The scheme here is pretty conservative,
* and should be OK for most apps. It's easier to explain what the code
* allows than what it forbids:
*
* Leaving things alone: it's OK if both s2 and s3 leave a piece of s1
* alone (don't delete the key, and don't change the value).
*
* Key deletion: a transaction (s2 or s3) can delete a key (from s1), but
* only if the other transaction (of s2 and s3) doesn't delete the same key.
* However, it's not OK for s2 and s3 to, between them, end up deleting all
* the keys. This is a higher-level constraint, due to that the caller of
* bucket_merge() doesn't have enough info to unlink the resulting empty
* bucket from its BTree correctly.
*
* Key insertion: s2 or s3 can add a new key, provided the other transaction
* doesn't insert the same key. It's not OK even if they insert the same
* <key, value> pair.
*
* Mapping value modification: s2 or s3 can modify the value associated
* with a key in s1, provided the other transaction doesn't make a
* modification of the same key to a different value. It's OK if s2 and s3
* both give the same new value to the key (XXX while it's hard to be
* precise about why, this doesn't seem consistent with that it's *not* OK
* for both to add a new key mapping to the same value).
*/
static PyObject *
bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
{
......@@ -60,28 +91,34 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
SetIteration i1 = {0,0,0}, i2 = {0,0,0}, i3 = {0,0,0};
int cmp12, cmp13, cmp23, mapping, set;
if (initSetIteration(&i1, OBJECT(s1), 1) < 0) goto err;
if (initSetIteration(&i2, OBJECT(s2), 1) < 0) goto err;
if (initSetIteration(&i3, OBJECT(s3), 1) < 0) goto err;
if (initSetIteration(&i1, OBJECT(s1), 1) < 0)
goto err;
if (initSetIteration(&i2, OBJECT(s2), 1) < 0)
goto err;
if (initSetIteration(&i3, OBJECT(s3), 1) < 0)
goto err;
mapping = i1.usesValue | i2.usesValue | i3.usesValue;
set = ! mapping;
set = !mapping;
if (mapping)
{
UNLESS(r=BUCKET(PyObject_CallObject(OBJECT(&BucketType), NULL)))
goto err;
}
r = (Bucket *)PyObject_CallObject((PyObject *)&BucketType, NULL);
else
{
UNLESS(r=BUCKET(PyObject_CallObject(OBJECT(&SetType), NULL)))
r = (Bucket *)PyObject_CallObject((PyObject *)&SetType, NULL);
if (r == NULL)
goto err;
}
if (i1.next(&i1) < 0) goto err;
if (i2.next(&i2) < 0) goto err;
if (i3.next(&i3) < 0) goto err;
if (i1.next(&i1) < 0)
goto err;
if (i2.next(&i2) < 0)
goto err;
if (i3.next(&i3) < 0)
goto err;
/* Consult zodb/btrees/interfaces.py for the meaning of the last
* argument passed to merge_error().
*/
/* XXX This isn't passing on errors raised by value comparisons. */
while (i1.position >= 0 && i2.position >= 0 && i3.position >= 0)
{
TEST_KEY_SET_OR(cmp12, i1.key, i2.key) goto err;
......@@ -91,15 +128,15 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (cmp13==0)
{
if (set || (TEST_VALUE(i1.value, i2.value) == 0))
{ /* change in i3 or all same */
{ /* change in i3 value or all same */
if (merge_output(r, &i3, mapping) < 0) goto err;
}
else if (set || (TEST_VALUE(i1.value, i3.value) == 0))
{ /* change in i2 */
{ /* change in i2 value */
if (merge_output(r, &i2, mapping) < 0) goto err;
}
else
{ /* conflicting changes in i2 and i3 */
{ /* conflicting value changes in i2 and i3 */
merge_error(i1.position, i2.position, i3.position, 1);
goto err;
}
......@@ -113,7 +150,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i3.next(&i3) < 0) goto err;
}
else if (set || (TEST_VALUE(i1.value, i2.value) == 0))
{ /* delete i3 */
{ /* deleted in i3 */
if (i1.next(&i1) < 0) goto err;
if (i2.next(&i2) < 0) goto err;
}
......@@ -131,7 +168,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i2.next(&i2) < 0) goto err;
}
else if (set || (TEST_VALUE(i1.value, i3.value) == 0))
{ /* delete i2 */
{ /* deleted in i2 */
if (i1.next(&i1) < 0) goto err;
if (i3.next(&i3) < 0) goto err;
}
......@@ -145,7 +182,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
{ /* Both keys changed */
TEST_KEY_SET_OR(cmp23, i2.key, i3.key) goto err;
if (cmp23==0)
{ /* dualing inserts or deletes */
{ /* dueling inserts or deletes */
merge_error(i1.position, i2.position, i3.position, 4);
goto err;
}
......@@ -168,7 +205,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i3.next(&i3) < 0) goto err;
}
else
{ /* Dueling deletes */
{ /* 1<2 and 1<3: both deleted 1.key */
merge_error(i1.position, i2.position, i3.position, 5);
goto err;
}
......@@ -179,7 +216,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
{ /* New inserts */
TEST_KEY_SET_OR(cmp23, i2.key, i3.key) goto err;
if (cmp23==0)
{ /* dualing inserts */
{ /* dueling inserts */
merge_error(i1.position, i2.position, i3.position, 6);
goto err;
}
......@@ -196,7 +233,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
}
while (i1.position >= 0 && i2.position >= 0)
{ /* deleting i3 */
{ /* remainder of i1 deleted in i3 */
TEST_KEY_SET_OR(cmp12, i1.key, i2.key) goto err;
if (cmp12 > 0)
{ /* insert i2 */
......@@ -209,14 +246,14 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i2.next(&i2) < 0) goto err;
}
else
{ /* Dualing deletes or delete and change */
{ /* Dueling deletes or delete and change */
merge_error(i1.position, i2.position, i3.position, 7);
goto err;
}
}
while (i1.position >= 0 && i3.position >= 0)
{ /* deleting i2 */
{ /* remainder of i1 deleted in i2 */
TEST_KEY_SET_OR(cmp13, i1.key, i3.key) goto err;
if (cmp13 > 0)
{ /* insert i3 */
......@@ -229,7 +266,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
if (i3.next(&i3) < 0) goto err;
}
else
{ /* Dualing deletes or delete and change */
{ /* Dueling deletes or delete and change */
merge_error(i1.position, i2.position, i3.position, 8);
goto err;
}
......@@ -248,7 +285,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
}
while (i3.position >= 0)
{ /* Inserting i2 at end */
{ /* Inserting i3 at end */
if (merge_output(r, &i3, mapping) < 0) goto err;
if (i3.next(&i3) < 0) goto err;
}
......@@ -271,7 +308,7 @@ bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
Py_INCREF(s1->next);
r->next = s1->next;
}
s=bucket_getstate(r, NULL);
s = bucket_getstate(r);
Py_DECREF(r);
return s;
......
......@@ -14,8 +14,3 @@
# hack to overcome dynamic-linking headache.
from _OIBTree import *
# We don't really want _ names in pickles, so update all of the __module__
# references.
for obj in OIBucket, OIBTree, OISet, OITreeSet:
obj.__module__ = __name__
......@@ -14,8 +14,3 @@
# hack to overcome dynamic-linking headache.
from _OOBTree import *
# We don't really want _ names in pickles, so update all of the __module__
# references.
for obj in OOBucket, OOBTree, OOSet, OOTreeSet:
obj.__module__ = __name__
......@@ -16,34 +16,7 @@
Set operations
****************************************************************************/
#define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.29 2002/06/27 22:24:16 tim_one Exp $\n"
#ifdef INTSET_H
static int
nextIntSet(SetIteration *i)
{
if (i->position >= 0)
{
UNLESS(PER_USE(INTSET(i->set))) return -1;
if (i->position < INTSET(i->set)->len)
{
i->key = INTSET(i->set)->data[i->position];
i->position ++;
}
else
{
i->position = -1;
PER_ACCESSED(INTSET(i->set));
}
PER_ALLOW_DEACTIVATION(INTSET(i->set));
}
return 0;
}
#endif
#define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.30 2003/11/28 16:44:44 jim Exp $\n"
#ifdef KEY_CHECK
static int
......@@ -103,7 +76,7 @@ initSetIteration(SetIteration *i, PyObject *s, int useValues)
i->position = -1; /* set to 0 only on normal return */
i->usesValue = 0; /* assume it's a set or that values aren't iterated */
if (ExtensionClassSubclassInstance_Check(s, &BucketType))
if (PyObject_IsInstance(s, (PyObject *)&BucketType))
{
i->set = s;
Py_INCREF(s);
......@@ -116,15 +89,15 @@ initSetIteration(SetIteration *i, PyObject *s, int useValues)
else
i->next = nextSet;
}
else if (ExtensionClassSubclassInstance_Check(s, &SetType))
else if (PyObject_IsInstance(s, (PyObject *)&SetType))
{
i->set = s;
Py_INCREF(s);
i->next = nextSet;
}
else if (ExtensionClassSubclassInstance_Check(s, &BTreeType))
else if (PyObject_IsInstance(s, (PyObject *)&BTreeType))
{
i->set = BTree_rangeSearch(BTREE(s), NULL, 'i');
i->set = BTree_rangeSearch(BTREE(s), NULL, NULL, 'i');
UNLESS(i->set) return -1;
if (useValues)
......@@ -135,20 +108,12 @@ initSetIteration(SetIteration *i, PyObject *s, int useValues)
else
i->next = nextTreeSetItems;
}
else if (ExtensionClassSubclassInstance_Check(s, &TreeSetType))
else if (PyObject_IsInstance(s, (PyObject *)&TreeSetType))
{
i->set = BTree_rangeSearch(BTREE(s), NULL, 'k');
i->set = BTree_rangeSearch(BTREE(s), NULL, NULL, 'k');
UNLESS(i->set) return -1;
i->next = nextTreeSetItems;
}
#ifdef INTSET_H
else if (s->ob_type == (PyTypeObject*)intSetType)
{
i->set = s;
Py_INCREF(s);
i->next = nextIntSet;
}
#endif
#ifdef KEY_CHECK
else if (KEY_CHECK(s))
{
......@@ -244,7 +209,7 @@ set_operation(PyObject *s1, PyObject *s2,
#ifndef MERGE
if (c12 && i1.usesValue && i2.usesValue) goto invalid_set_operation;
#endif
if (! i1.usesValue && i2.usesValue)
if (! i1.usesValue&& i2.usesValue)
{
SetIteration t;
int i;
......@@ -339,6 +304,7 @@ set_operation(PyObject *s1, PyObject *s2,
if(c1 && copyRemaining(r, &i1, merge, w1) < 0) goto err;
if(c2 && copyRemaining(r, &i2, merge, w2) < 0) goto err;
finiSetIteration(&i1);
finiSetIteration(&i2);
......@@ -383,7 +349,7 @@ union_m(PyObject *ignored, PyObject *args)
UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL;
if (o1==Py_None)
if (o1 == Py_None)
{
Py_INCREF(o2);
return o2;
......@@ -552,5 +518,4 @@ Error:
finiSetIteration(&setiter);
return NULL;
}
#endif
......@@ -12,7 +12,7 @@
****************************************************************************/
#define SETTEMPLATE_C "$Id: SetTemplate.c,v 1.16 2002/10/05 00:39:57 gvanrossum Exp $\n"
#define SETTEMPLATE_C "$Id: SetTemplate.c,v 1.17 2003/11/28 16:44:44 jim Exp $\n"
static PyObject *
Set_insert(Bucket *self, PyObject *args)
......@@ -25,36 +25,61 @@ Set_insert(Bucket *self, PyObject *args)
return PyInt_FromLong(i);
}
static PyObject *
Set_update(Bucket *self, PyObject *args)
/* _Set_update and _TreeSet_update are identical except for the
function they call to add the element to the set.
*/
static int
_Set_update(Bucket *self, PyObject *seq)
{
PyObject *seq=0, *o, *t, *v, *tb;
int i, n=0, ind;
int n = -1;
PyObject *iter, *v;
int ind;
UNLESS(PyArg_ParseTuple(args, "|O:update", &seq)) return NULL;
iter = PyObject_GetIter(seq);
if (iter == NULL)
return -1;
if (seq)
{
for (i=0; ; i++)
{
UNLESS (o=PySequence_GetItem(seq, i))
{
PyErr_Fetch(&t, &v, &tb);
if (t != PyExc_IndexError)
{
PyErr_Restore(t, v, tb);
return NULL;
}
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
while (1) {
v = PyIter_Next(iter);
if (v == NULL) {
if (PyErr_Occurred())
goto err;
else
break;
}
ind=_bucket_set(self, o, Py_None, 1, 1, 0);
Py_DECREF(o);
if (ind < 0) return NULL;
ind = _bucket_set(self, v, Py_None, 1, 1, 0);
Py_DECREF(v);
if (ind < 0)
goto err;
else
n += ind;
}
/* n starts out at -1, which is the error return value. If
this point is reached, then there is no error. n must be
incremented to account for the initial value of -1 instead of
0.
*/
n++;
err:
Py_DECREF(iter);
return n;
}
static PyObject *
Set_update(Bucket *self, PyObject *args)
{
PyObject *seq = NULL;
int n = 0;
if (!PyArg_ParseTuple(args, "|O:update", &seq))
return NULL;
if (seq) {
n = _Set_update(self, seq);
if (n < 0)
return NULL;
}
return PyInt_FromLong(n);
......@@ -99,7 +124,7 @@ _set_setstate(Bucket *self, PyObject *args)
if (l > self->size)
{
UNLESS (keys=PyRealloc(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;
}
......@@ -132,8 +157,7 @@ set_setstate(Bucket *self, PyObject *args)
PER_PREVENT_DEACTIVATION(self);
r=_set_setstate(self, args);
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
PER_UNUSE(self);
if (r < 0) return NULL;
Py_INCREF(Py_None);
......@@ -143,51 +167,76 @@ set_setstate(Bucket *self, PyObject *args)
static struct PyMethodDef Set_methods[] = {
{"__getstate__", (PyCFunction) bucket_getstate, METH_VARARGS,
"__getstate__() -- Return the picklable state of the object"},
{"__setstate__", (PyCFunction) set_setstate, METH_VARARGS,
"__setstate__() -- Set the state of the object"},
{"keys", (PyCFunction) bucket_keys, METH_VARARGS,
{"keys", (PyCFunction) bucket_keys, METH_KEYWORDS,
"keys() -- Return the keys"},
{"has_key", (PyCFunction) bucket_has_key, METH_VARARGS,
{"has_key", (PyCFunction) bucket_has_key, METH_O,
"has_key(key) -- Test whether the bucket contains the given key"},
{"clear", (PyCFunction) bucket_clear, METH_VARARGS,
"clear() -- Remove all of the items from the bucket"},
{"maxKey", (PyCFunction) Bucket_maxKey, METH_VARARGS,
"maxKey([key]) -- Find the maximum key\n\n"
"If an argument is given, find the maximum <= the argument"},
{"minKey", (PyCFunction) Bucket_minKey, METH_VARARGS,
"minKey([key]) -- Find the minimum key\n\n"
"If an argument is given, find the minimum >= the argument"},
#ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) bucket__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) bucket__p_deactivate, METH_VARARGS,
{"_p_deactivate", (PyCFunction) bucket__p_deactivate, METH_KEYWORDS,
"_p_deactivate() -- Reinitialize from a newly created copy"},
#endif
{"insert", (PyCFunction)Set_insert, METH_VARARGS,
"insert(id,[ignored]) -- Add a key to the set"},
{"update", (PyCFunction)Set_update, METH_VARARGS,
"update(seq) -- Add the items from the given sequence to the set"},
{"__init__", (PyCFunction)Set_update, METH_VARARGS,
"__init__(seq) -- Initialize with the items from the given sequence"},
{"remove", (PyCFunction)Set_remove, METH_VARARGS,
"remove(id) -- Remove an id from the set"},
{NULL, NULL} /* sentinel */
};
static int
Set_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *v = NULL;
if (!PyArg_ParseTuple(args, "|O:" MOD_NAME_PREFIX "Set", &v))
return -1;
if (v)
return _Set_update((Bucket *)self, v);
else
return 0;
}
static PyObject *
set_repr(Bucket *self)
{
static PyObject *format;
PyObject *r, *t;
UNLESS (format) UNLESS (format=PyString_FromString(MOD_NAME_PREFIX "Set(%s)"))
return NULL;
UNLESS (t=PyTuple_New(1)) return NULL;
UNLESS (r=bucket_keys(self,NULL)) goto err;
PyTuple_SET_ITEM(t,0,r);
r=t;
ASSIGN(r,PyString_Format(format,r));
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;
PyTuple_SET_ITEM(t, 0, r);
r = t;
ASSIGN(r, PyString_Format(format, r));
return r;
err:
Py_DECREF(t);
......@@ -201,8 +250,7 @@ set_length(Bucket *self)
PER_USE_OR_RETURN(self, -1);
r = self->len;
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
PER_UNUSE(self);
return r;
}
......@@ -220,53 +268,65 @@ set_item(Bucket *self, int index)
else
IndexError(index);
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
PER_UNUSE(self);
return r;
}
static PySequenceMethods set_as_sequence = {
(inquiry)set_length, /*sq_length*/
(binaryfunc)0, /*sq_concat*/
(intargfunc)0, /*sq_repeat*/
(intargfunc)set_item, /*sq_item*/
(intintargfunc)0, /*sq_slice*/
(intobjargproc)0, /*sq_ass_item*/
(intintobjargproc)0, /*sq_ass_slice*/
(inquiry)set_length, /* sq_length */
(binaryfunc)0, /* sq_concat */
(intargfunc)0, /* sq_repeat */
(intargfunc)set_item, /* sq_item */
(intintargfunc)0, /* sq_slice */
(intobjargproc)0, /* sq_ass_item */
(intintobjargproc)0, /* sq_ass_slice */
(objobjproc)bucket_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyExtensionClass SetType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
MOD_NAME_PREFIX "Set", /*tp_name*/
sizeof(Bucket), /*tp_basicsize*/
0, /*tp_itemsize*/
/*********** methods ***********************/
(destructor) Bucket_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*obsolete tp_getattr*/
(setattrfunc)0, /*obsolete tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc) set_repr, /*tp_repr*/
0, /*tp_as_number*/
&set_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)0, /*tp_getattro*/
0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"Set implemented as sorted keys",
METHOD_CHAIN(Set_methods),
EXTENSIONCLASS_BASICNEW_FLAG
#ifdef PERSISTENT
| PERSISTENT_TYPE_FLAG
#endif
| EXTENSIONCLASS_NOINSTDICT_FLAG,
static PyTypeObject SetType = {
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */
0, /* ob_size */
MODULE_NAME MOD_NAME_PREFIX "Set", /* tp_name */
sizeof(Bucket), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)bucket_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)set_repr, /* tp_repr */
0, /* tp_as_number */
&set_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
(traverseproc)bucket_traverse, /* tp_traverse */
(inquiry)bucket_tp_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)Bucket_getiter, /* tp_iter */
0, /* tp_iternext */
Set_methods, /* tp_methods */
Bucket_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
Set_init, /* tp_init */
0, /* tp_alloc */
0, /*PyType_GenericNew,*/ /* tp_new */
};
static int
......
......@@ -12,7 +12,7 @@
****************************************************************************/
#define TREESETTEMPLATE_C "$Id: TreeSetTemplate.c,v 1.15 2002/10/05 00:39:57 gvanrossum Exp $\n"
#define TREESETTEMPLATE_C "$Id: TreeSetTemplate.c,v 1.16 2003/11/28 16:44:44 jim Exp $\n"
static PyObject *
TreeSet_insert(BTree *self, PyObject *args)
......@@ -20,41 +20,69 @@ TreeSet_insert(BTree *self, PyObject *args)
PyObject *key;
int i;
UNLESS (PyArg_ParseTuple(args, "O", &key)) return NULL;
if ((i=_BTree_set(self, key, Py_None, 1, 1)) < 0) return NULL;
if (!PyArg_ParseTuple(args, "O:insert", &key))
return NULL;
i = _BTree_set(self, key, Py_None, 1, 1);
if (i < 0)
return NULL;
return PyInt_FromLong(i);
}
static PyObject *
TreeSet_update(BTree *self, PyObject *args)
/* _Set_update and _TreeSet_update are identical except for the
function they call to add the element to the set.
*/
static int
_TreeSet_update(BTree *self, PyObject *seq)
{
PyObject *seq=0, *o, *t, *v, *tb;
int i, n=0, ind;
UNLESS(PyArg_ParseTuple(args, "|O:update", &seq)) return NULL;
if (seq)
{
for (i=0; ; i++)
{
UNLESS (o=PySequence_GetItem(seq, i))
{
PyErr_Fetch(&t, &v, &tb);
if (t != PyExc_IndexError)
{
PyErr_Restore(t, v, tb);
return NULL;
}
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
int n = -1;
PyObject *iter, *v;
int ind;
iter = PyObject_GetIter(seq);
if (iter == NULL)
return -1;
while (1) {
v = PyIter_Next(iter);
if (v == NULL) {
if (PyErr_Occurred())
goto err;
else
break;
}
ind=_BTree_set(self, o, Py_None, 1, 1);
Py_DECREF(o);
if (ind < 0) return NULL;
ind = _BTree_set(self, v, Py_None, 1, 1);
Py_DECREF(v);
if (ind < 0)
goto err;
else
n += ind;
}
/* n starts out at -1, which is the error return value. If
this point is reached, then there is no error. n must be
incremented to account for the initial value of -1 instead of
0.
*/
n++;
err:
Py_DECREF(iter);
return n;
}
static PyObject *
TreeSet_update(BTree *self, PyObject *args)
{
PyObject *seq = NULL;
int n = 0;
if (!PyArg_ParseTuple(args, "|O:update", &seq))
return NULL;
if (seq) {
n = _TreeSet_update(self, seq);
if (n < 0)
return NULL;
}
return PyInt_FromLong(n);
......@@ -81,8 +109,7 @@ TreeSet_setstate(BTree *self, PyObject *args)
PER_PREVENT_DEACTIVATION(self);
r=_BTree_setstate(self, args, 1);
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
PER_UNUSE(self);
if (r < 0) return NULL;
Py_INCREF(Py_None);
......@@ -90,37 +117,54 @@ TreeSet_setstate(BTree *self, PyObject *args)
}
static struct PyMethodDef TreeSet_methods[] = {
{"__getstate__", (PyCFunction) BTree_getstate, METH_VARARGS,
"__getstate__() -- Return the picklable state of the object"},
{"__getstate__", (PyCFunction) BTree_getstate, METH_NOARGS,
"__getstate__() -> state\n\n"
"Return the picklable state of the TreeSet."},
{"__setstate__", (PyCFunction) TreeSet_setstate, METH_VARARGS,
"__setstate__() -- Set the state of the object"},
{"has_key", (PyCFunction) BTree_has_key, METH_VARARGS,
"has_key(key) -- Test whether the bucket contains the given key"},
{"keys", (PyCFunction) BTree_keys, METH_VARARGS,
"keys() -- Return the keys"},
"__setstate__(state)\n\n"
"Set the state of the TreeSet."},
{"has_key", (PyCFunction) BTree_has_key, METH_O,
"has_key(key)\n\n"
"Return true if the TreeSet contains the given key."},
{"keys", (PyCFunction) BTree_keys, METH_KEYWORDS,
"keys([min, max]) -> list of keys\n\n"
"Returns the keys of the TreeSet. If min and max are supplied, only\n"
"keys greater than min and less than max are returned."},
{"maxKey", (PyCFunction) BTree_maxKey, METH_VARARGS,
"maxKey([key]) -- Find the maximum key\n\n"
"If an argument is given, find the maximum <= the argument"},
"maxKey([max]) -> key\n\n"
"Return the largest key in the BTree. If max is specified, return\n"
"the largest key <= max."},
{"minKey", (PyCFunction) BTree_minKey, METH_VARARGS,
"minKey([key]) -- Find the minimum key\n\n"
"If an argument is given, find the minimum >= the argument"},
{"clear", (PyCFunction) BTree_clear, METH_VARARGS,
"clear() -- Remove all of the items from the BTree"},
"minKey([mi]) -> key\n\n"
"Return the smallest key in the BTree. If min is specified, return\n"
"the smallest key >= min."},
{"clear", (PyCFunction) BTree_clear, METH_NOARGS,
"clear()\n\nRemove all of the items from the BTree."},
{"insert", (PyCFunction)TreeSet_insert, METH_VARARGS,
"insert(id,[ignored]) -- Add an id to the set"},
{"update", (PyCFunction)TreeSet_update, METH_VARARGS,
"update(seq) -- Add the items from the given sequence to the set"},
{"__init__", (PyCFunction)TreeSet_update, METH_VARARGS,
"__init__(seq) -- Initialize with the items from the given sequence"},
"update(collection)\n\n Add the items from the given collection."},
{"remove", (PyCFunction)TreeSet_remove, METH_VARARGS,
"remove(id) -- Remove a key from the set"},
{"_check", (PyCFunction) BTree_check, METH_VARARGS,
{"_check", (PyCFunction) BTree_check, METH_NOARGS,
"Perform sanity check on TreeSet, and raise exception if flawed."},
#ifdef PERSISTENT
{"_p_resolveConflict", (PyCFunction) BTree__p_resolveConflict, METH_VARARGS,
"_p_resolveConflict() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) BTree__p_deactivate, METH_VARARGS,
"_p_deactivate() -- Reinitialize from a newly created copy"},
{"_p_deactivate", (PyCFunction) BTree__p_deactivate, METH_KEYWORDS,
"_p_deactivate()\n\nReinitialize from a newly created copy."},
#endif
{NULL, NULL} /* sentinel */
};
......@@ -129,35 +173,72 @@ static PyMappingMethods TreeSet_as_mapping = {
(inquiry)BTree_length, /*mp_length*/
};
static PyExtensionClass TreeSetType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
MOD_NAME_PREFIX "TreeSet", /*tp_name*/
sizeof(BTree), /*tp_basicsize*/
0, /*tp_itemsize*/
/************* methods ********************/
(destructor) BTree_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*/
&BTree_as_number_for_nonzero, /*tp_as_number*/
0, /*tp_as_sequence*/
&TreeSet_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)0,
0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"Set implemented as sorted tree of items",
METHOD_CHAIN(TreeSet_methods),
EXTENSIONCLASS_BASICNEW_FLAG
#ifdef PERSISTENT
| PERSISTENT_TYPE_FLAG
#endif
| EXTENSIONCLASS_NOINSTDICT_FLAG,
static PySequenceMethods TreeSet_as_sequence = {
(inquiry)0, /* sq_length */
(binaryfunc)0, /* sq_concat */
(intargfunc)0, /* sq_repeat */
(intargfunc)0, /* sq_item */
(intintargfunc)0, /* sq_slice */
(intobjargproc)0, /* sq_ass_item */
(intintobjargproc)0, /* sq_ass_slice */
(objobjproc)BTree_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static int
TreeSet_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *v = NULL;
if (!PyArg_ParseTuple(args, "|O:" MOD_NAME_PREFIX "TreeSet", &v))
return -1;
if (v)
return _TreeSet_update((BTree *)self, v);
else
return 0;
}
static PyTypeObject TreeSetType = {
PyObject_HEAD_INIT(NULL) /* PyPersist_Type */
0, /* ob_size */
MODULE_NAME MOD_NAME_PREFIX "TreeSet",/* tp_name */
sizeof(BTree), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)BTree_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
&BTree_as_number_for_nonzero, /* tp_as_number */
&TreeSet_as_sequence, /* tp_as_sequence */
&TreeSet_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
(traverseproc)BTree_traverse, /* tp_traverse */
(inquiry)BTree_tp_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)BTree_getiter, /* tp_iter */
0, /* tp_iternext */
TreeSet_methods, /* tp_methods */
BTree_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
TreeSet_init, /* tp_init */
0, /* tp_alloc */
0, /*PyType_GenericNew,*/ /* tp_new */
};
/* Setup template macros */
#define MASTER_ID "$Id: _IIBTree.c,v 1.7 2002/06/25 02:00:55 tim_one Exp $\n"
#define MASTER_ID "$Id: _IIBTree.c,v 1.8 2003/11/28 16:44:44 jim Exp $\n"
#define PERSISTENT
......@@ -11,8 +11,4 @@
#include "intkeymacros.h"
#include "intvaluemacros.h"
#include "cPersistence.h"
#ifndef EXCLUDE_INTSET_SUPPORT
#include "BTree/intSet.h"
#endif
#include "BTreeModuleTemplate.c"
#define MASTER_ID "$Id: _IOBTree.c,v 1.5 2002/02/21 21:41:17 jeremy Exp $\n"
#define MASTER_ID "$Id: _IOBTree.c,v 1.6 2003/11/28 16:44:44 jim Exp $\n"
#define PERSISTENT
......@@ -10,8 +10,4 @@
#include "intkeymacros.h"
#include "objectvaluemacros.h"
#include "cPersistence.h"
#ifndef EXCLUDE_INTSET_SUPPORT
#include "BTree/intSet.h"
#endif
#include "BTreeModuleTemplate.c"
#define MASTER_ID "$Id: _OIBTree.c,v 1.2 2001/03/27 16:37:42 jim Exp $\n"
#define MASTER_ID "$Id: _OIBTree.c,v 1.3 2003/11/28 16:44:44 jim Exp $\n"
#define PERSISTENT
......
#define MASTER_ID "$Id: _OOBTree.c,v 1.2 2001/03/27 16:37:42 jim Exp $\n"
#define MASTER_ID "$Id: _OOBTree.c,v 1.3 2003/11/28 16:44:44 jim Exp $\n"
#define PERSISTENT
......
import ZODB
try: import intSet
except: pass
else: del intSet
try:
import intSet
except:
pass
else:
del intSet
# Register interfaces
try: import Interface
except ImportError: pass # Don't register interfaces if no scarecrow
try:
import Interface
except ImportError:
pass # Don't register interfaces if no scarecrow
else:
import Interfaces
del Interfaces
......
......@@ -10,10 +10,9 @@
typedef unsigned char char2[2];
typedef unsigned char char6[6];
/* Setup template macros */
#define MASTER_ID "$Id: _fsBTree.c,v 1.7 2003/09/03 17:14:25 kiko Exp $\n"
#define MASTER_ID "$Id: _fsBTree.c,v 1.8 2003/11/28 16:44:44 jim Exp $\n"
#define PERSISTENT
......@@ -24,7 +23,7 @@ typedef unsigned char char6[6];
/*#include "intkeymacros.h"*/
#define KEYMACROS_H "$Id: _fsBTree.c,v 1.7 2003/09/03 17:14:25 kiko Exp $\n"
#define KEYMACROS_H "$Id: _fsBTree.c,v 1.8 2003/11/28 16:44:44 jim Exp $\n"
#define KEY_TYPE char2
#undef KEY_TYPE_IS_PYOBJECT
#define KEY_CHECK(K) (PyString_Check(K) && PyString_GET_SIZE(K)==2)
......@@ -39,11 +38,10 @@ typedef unsigned char char6[6];
(STATUS)=0; }
/*#include "intvaluemacros.h"*/
#define VALUEMACROS_H "$Id: _fsBTree.c,v 1.7 2003/09/03 17:14:25 kiko Exp $\n"
#define VALUEMACROS_H "$Id: _fsBTree.c,v 1.8 2003/11/28 16:44:44 jim Exp $\n"
#define VALUE_TYPE char6
#undef VALUE_TYPE_IS_PYOBJECT
#define TEST_VALUE(K, T) memcmp(K,T,6)
#define DECLARE_VALUE(NAME) VALUE_TYPE NAME
#define DECREF_VALUE(k)
#define INCREF_VALUE(k)
#define COPY_VALUE(V, E) (memcpy(V, E, 6))
......
......@@ -12,7 +12,7 @@
****************************************************************************/
/* Revision information: $Id: sorters.c,v 1.4 2002/06/12 04:17:48 tim_one Exp $ */
/* Revision information: $Id: sorters.c,v 1.5 2003/11/28 16:44:44 jim Exp $ */
/* The only routine here intended to be used outside the file is
size_t sort_int4_nodups(int *p, size_t n)
......
This diff is collapsed.
......@@ -12,9 +12,9 @@
#
##############################################################################
__version__ = '$Id: testBTreesUnicode.py,v 1.7 2002/06/08 19:40:13 tim_one Exp $'
__version__ = '$Id: testBTreesUnicode.py,v 1.8 2003/11/28 16:44:45 jim Exp $'
import unittest,types
import unittest
from BTrees.OOBTree import OOBTree
# When an OOBtree contains unicode strings as keys,
......@@ -43,14 +43,14 @@ class TestBTreesUnicode(unittest.TestCase):
self.tree = OOBTree()
for k, v in self.data:
if isinstance(k, types.StringType):
if isinstance(k, str):
k = unicode(k, 'latin1')
self.tree[k] = v
def testAllKeys(self):
# check every item of the tree
for k, v in self.data:
if isinstance(k, types.StringType):
if isinstance(k, str):
k = unicode(k, encoding)
self.assert_(self.tree.has_key(k))
self.assertEqual(self.tree[k], v)
......@@ -65,7 +65,7 @@ class TestBTreesUnicode(unittest.TestCase):
def testAsciiKeys(self):
# try to access some "plain ASCII" keys in the tree
for k, v in self.data[0], self.data[2]:
self.assert_(isinstance(k, types.StringType))
self.assert_(isinstance(k, str))
self.assertEqual(self.tree[k], v)
def test_suite():
......
......@@ -12,24 +12,25 @@
#
##############################################################################
import os
from unittest import TestCase, TestSuite, makeSuite
from BTrees.OOBTree import OOBTree, OOBucket, OOSet, OOTreeSet
from BTrees.IOBTree import IOBTree, IOBucket, IOSet, IOTreeSet
from BTrees.IIBTree import IIBTree, IIBucket, IISet, IITreeSet
from BTrees.OIBTree import OIBTree, OIBucket, OISet, OITreeSet
from unittest import TestCase, TestSuite, makeSuite
from ZODB.POSException import ConflictError
class Base:
""" Tests common to all types: sets, buckets, and BTrees """
db = None
storage = None
def tearDown(self):
get_transaction().abort()
del self.t
if self.db is not None:
self.db.close()
if self.storage is not None:
self.storage.close()
self.storage.cleanup()
def openDB(self):
......@@ -78,7 +79,7 @@ class MappingBase(Base):
r2 = self.db.open().root()
copy = r2["t"]
list(copy.items()) # ensure it's all loaded
list(copy) # unghostify
self.assertEqual(self.t._p_serial, copy._p_serial)
......@@ -202,7 +203,6 @@ class MappingBase(Base):
test_merge(base, b1, b2, bm, 'merge conflicting inserts',
should_fail=1)
class SetTests(Base):
"Set (as opposed to TreeSet) specific tests."
......@@ -215,13 +215,13 @@ class SetTests(Base):
e2=[7745, 4868, -2548, -2711, -3154]
base = self.t
base=self.t
base.update(l)
b1 = base.__class__(base.keys())
b2 = base.__class__(base.keys())
bm = base.__class__(base.keys())
b1=base.__class__(base)
b2=base.__class__(base)
bm=base.__class__(base)
items = base.keys()
items=base.keys()
return base, b1, b2, bm, e1, e2, items
......@@ -302,28 +302,27 @@ class SetTests(Base):
def test_merge(o1, o2, o3, expect, message='failed to merge', should_fail=0):
s1=o1.__getstate__()
s2=o2.__getstate__()
s3=o3.__getstate__()
expected=expect.__getstate__()
s1 = o1.__getstate__()
s2 = o2.__getstate__()
s3 = o3.__getstate__()
expected = expect.__getstate__()
if expected is None:
expected = ((((),),),)
if should_fail:
try:
merged=o1._p_resolveConflict(s1, s2, s3)
merged = o1._p_resolveConflict(s1, s2, s3)
except ConflictError, err:
pass
else:
assert 0, message
else:
merged=o1._p_resolveConflict(s1, s2, s3)
assert merged==expected, message
merged = o1._p_resolveConflict(s1, s2, s3)
assert merged == expected, message
class BucketTests(MappingBase):
""" Tests common to all buckets """
class BTreeTests(MappingBase):
""" Tests common to all BTrees """
......@@ -593,6 +592,7 @@ class NastyConfict(Base, TestCase):
self.assertRaises(ConflictError, get_transaction().commit)
get_transaction().abort() # horrible things happen w/o this
def testEmptyBucketNoConflict(self):
# Tests that a plain empty bucket (on input) is not viewed as a
# conflict.
......@@ -659,6 +659,60 @@ class NastyConfict(Base, TestCase):
# And the resulting BTree shouldn't have internal damage.
b._check()
def testCantResolveBTreeConflict(self):
# Test that a conflict involving two different changes to
# an internal BTree node is unresolvable. An internal node
# only changes when there are enough additions or deletions
# to a child bucket that the bucket is split or removed.
# It's (almost necessarily) a white-box test, and sensitive to
# implementation details.
b = self.t
for i in range(0, 200, 4):
b[i] = i
# bucket 0 has 15 values: 0, 4 .. 56
# bucket 1 has 15 values: 60, 64 .. 116
# bucket 2 has 20 values: 120, 124 .. 196
state = b.__getstate__()
# Looks like: ((bucket0, 60, bucket1, 120, bucket2), firstbucket)
# If these fail, the *preconditions* for running the test aren't
# satisfied -- the test itself hasn't been run yet.
self.assertEqual(len(state), 2)
self.assertEqual(len(state[0]), 5)
self.assertEqual(state[0][1], 60)
self.assertEqual(state[0][3], 120)
# Set up database connections to provoke conflict.
self.openDB()
r1 = self.db.open().root()
r1["t"] = self.t
get_transaction().commit()
r2 = self.db.open().root()
copy = r2["t"]
# Make sure all of copy is loaded.
list(copy.values())
self.assertEqual(self.t._p_serial, copy._p_serial)
# Now one transaction should add enough keys to cause a split,
# and another should remove all the keys in one bucket.
for k in range(200, 300, 4):
self.t[k] = k
get_transaction().commit()
for k in range(0, 60, 4):
del copy[k]
try:
get_transaction().commit()
except ConflictError, detail:
self.assert_(str(detail).startswith('database conflict error'))
get_transaction().abort()
else:
self.fail("expected ConflictError")
def test_suite():
suite = TestSuite()
for k in (TestIOBTrees, TestOOBTrees, TestOIBTrees, TestIIBTrees,
......@@ -668,3 +722,4 @@ def test_suite():
NastyConfict):
suite.addTest(makeSuite(k))
return suite
This diff is collapsed.
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from BTrees.OOBTree import OOBTree, OOBucket
class B(OOBucket):
pass
class T(OOBTree):
_bucket_type = B
import unittest
class SubclassTest(unittest.TestCase):
def testSubclass(self):
# test that a subclass that defines _bucket_type gets buckets
# of that type
t = T()
# XXX there's no good way to get a bucket at the moment.
# XXX __getstate__() is as good as it gets, but the default
# XXX getstate explicitly includes the pickle of the bucket
# XXX for small trees, so we have to be clever :-(
# make sure there is more than one bucket in the tree
for i in range(1000):
t[i] = i
state = t.__getstate__()
self.assert_(state[0][0].__class__ is B)
def test_suite():
return unittest.makeSuite(SubclassTest)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -25,7 +25,7 @@ register_loop_callback() to register interest. When the mainloop
thread calls loop(), each registered callback will be called with the
socket map as its first argument.
"""
__version__ = '$Revision: 1.10 $'[11:-2]
__version__ = '$Revision: 1.11 $'[11:-2]
import asyncore
import select
......@@ -37,6 +37,16 @@ _loop_lock = thread.allocate_lock()
_looping = None
_loop_callbacks = []
def remove_loop_callback(callback):
"""Remove a callback function registered earlier.
This is useful if loop() was never called.
"""
for i in range(len(_loop_callbacks)):
if _loop_callbacks[i][0] == callback:
del _loop_callbacks[i]
return
def register_loop_callback(callback, args=(), kw=None):
"""Register callback function to be called when mainloop starts
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment