Commit 9671a5bc authored by Jim Fulton's avatar Jim Fulton

got rid of BTree and intSet modules

parent b823b5cb
/***********************************************************
Copyright
Copyright 1997 Digital Creations, L.L.C., 910 Princess Anne
Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
rights reserved.
******************************************************************/
static char BTree_module_documentation[] =
""
"\n$Id: BTree.c,v 1.10 1997/11/13 20:45:51 jim Exp $"
;
#define PERSISTENT
#ifdef PERSISTENT
#include "cPersistence.h"
#else
#include "ExtensionClass.h"
#define PER_USE_OR_RETURN(self, NULL)
#define PER_ALLOW_DEACTIVATION(self)
#define PER_PREVENT_DEACTIVATION(self)
#endif
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define RETURN_NONE Py_INCREF(Py_None); return Py_None
#define LIST(O) ((PyListObject*)(O))
#define OBJECT(O) ((PyObject*)(O))
#define MIN_BUCKET_ALLOC 8
#define MAX_SIZE(N) 32
#ifdef INTKEY
#define KEY_TYPE INTKEY
#define KEY_PARSE "i"
#define TEST_KEY(k) ((k)-ikey)
#define DECREF_KEY(k)
#define ASSIGN_KEY(k,e) (k=e)
#else
#define KEY_TYPE PyObject *
#define KEY_PARSE "O"
#define TEST_KEY(k) PyObject_Compare(k,key)
#define DECREF_KEY(k) Py_DECREF(k)
#define ASSIGN_KEY(k,e) ASSIGN(k,e)
#endif
#ifdef INTVAL
#define VALUE_TYPE INTVAL
#define VALUE_PARSE "i"
#define DECREF_VALUE(k)
#define ASSIGN_VALUE(k,e) (k=e)
#else
#define VALUE_TYPE PyObject *
#define VALUE_PARSE "O"
#define DECREF_VALUE(k) Py_DECREF(k)
#define ASSIGN_VALUE(k,e) ASSIGN(k,e)
#endif
typedef struct ItemStruct {
KEY_TYPE key;
VALUE_TYPE value;
} Item;
typedef struct BTreeItemStruct {
KEY_TYPE key;
PyObject *value;
int count;
} BTreeItem;
typedef struct {
cPersistent_HEAD
int size, len;
Item *data;
} Bucket;
staticforward PyExtensionClass BucketType;
#define BUCKET(O) ((Bucket*)(O))
#define Bucket_Check(O) ((O)->ob_type==(PyTypeObject*)&BucketType)
typedef struct {
cPersistent_HEAD
int size, len;
BTreeItem *data;
int count;
} BTree;
staticforward PyExtensionClass BucketType;
#define BTREE(O) ((BTree*)(O))
#define BTree_Check(O) ((O)->ob_type==(PyTypeObject*)&BTreeType)
/************************************************************************
BTreeItems
*/
typedef struct {
PyObject_HEAD
BTree *data;
int first, len;
char kind;
} BTreeItems;
staticforward PyTypeObject BTreeItemsType;
static PyObject *
newBTreeItems(BTree *data, char kind, int first, int last)
{
BTreeItems *self;
UNLESS(self = PyObject_NEW(BTreeItems, &BTreeItemsType)) return NULL;
Py_INCREF(data);
self->data=data;
self->kind=kind;
self->first=first;
self->len=last-first;
return OBJECT(self);
}
static void
BTreeItems_dealloc(BTreeItems *self)
{
Py_DECREF(self->data);
PyMem_DEL(self);
}
static int
BTreeItems_length( BTreeItems *self)
{
return self->len;
}
static PyObject *
BTreeItems_concat( BTreeItems *self, PyObject *bb)
{
PyErr_SetString(PyExc_TypeError,
"BTreeItems objects do not support concatenation");
return NULL;
}
static PyObject *
BTreeItems_repeat(BTreeItems *self, int n)
{
PyErr_SetString(PyExc_TypeError,
"BTreeItems objects do not support repetition");
return NULL;
}
static PyObject *
BTreeItems_item_BTree(char kind, int i, BTree *btree)
{
int l;
BTreeItem *d;
PyObject *r;
PER_USE_OR_RETURN(btree, NULL);
for(d=btree->data, l=btree->len;
--l >= 0 && i >= d->count;
i -= d->count, d++);
PER_ALLOW_DEACTIVATION(btree);
if(Bucket_Check(d->value))
{
PER_USE_OR_RETURN(d->value, NULL);
switch(kind)
{
case 'k':
#ifdef INTKEY
r=PyInt_FromLong((BUCKET(d->value)->data[i].key));
#else
r=(BUCKET(d->value)->data[i].key);
Py_INCREF(r);
#endif
break;
case 'v':
#ifdef INTVAL
r=PyInt_FromLong((BUCKET(d->value)->data[i].value));
#else
r=(BUCKET(d->value)->data[i].value);
Py_INCREF(r);
#endif
break;
default:
r=Py_BuildValue(KEY_PARSE VALUE_PARSE,
BUCKET(d->value)->data[i].key,
BUCKET(d->value)->data[i].value);
}
PER_ALLOW_DEACTIVATION(BUCKET(d->value));
return r;
}
return BTreeItems_item_BTree(kind, i, BTREE(d->value));
}
static PyObject *
BTreeItems_item(BTreeItems *self, int i)
{
int j, l;
j=i;
l=self->len;
if(j < 0) j += l;
if(j < 0 || j >= l)
{
PyObject *v;
v=PyInt_FromLong(i);
UNLESS(v)
{
v=Py_None;
Py_INCREF(v);
}
PyErr_SetObject(PyExc_IndexError, v);
Py_DECREF(v);
return NULL;
}
i=j+self->first;
return BTreeItems_item_BTree(self->kind, i, self->data);
}
static PyObject *
BTreeItems_slice(BTreeItems *self, int ilow, int ihigh)
{
if(ihigh > self->len) ihigh=self->len;
ilow += self->first;
ihigh += self->first;
return newBTreeItems(self->data, self->kind, ilow, ihigh);
}
static int
BTreeItems_ass_item(BTreeItems *self, int i, PyObject *v)
{
PyErr_SetString(PyExc_TypeError,
"BTreeItems objects do not support item assignment");
return -1;
}
static int
BTreeItems_ass_slice(PyListObject *self, int ilow, int ihigh, PyObject *v)
{
PyErr_SetString(PyExc_TypeError,
"BTreeItems objects do not support slice assignment");
return -1;
}
static PySequenceMethods BTreeItems_as_sequence = {
(inquiry)BTreeItems_length, /*sq_length*/
(binaryfunc)BTreeItems_concat, /*sq_concat*/
(intargfunc)BTreeItems_repeat, /*sq_repeat*/
(intargfunc)BTreeItems_item, /*sq_item*/
(intintargfunc)BTreeItems_slice, /*sq_slice*/
(intobjargproc)BTreeItems_ass_item, /*sq_ass_item*/
(intintobjargproc)BTreeItems_ass_slice, /*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
static PyTypeObject BTreeItemsType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"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*/
0, /*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 */
};
/************************************************************************/
static void *
PyMalloc(size_t sz)
{
void *r;
if(r=malloc(sz)) return r;
PyErr_NoMemory();
return NULL;
}
static void *
PyRealloc(void *p, size_t sz)
{
void *r;
if(r=realloc(p,sz)) return r;
PyErr_NoMemory();
return NULL;
}
static PyObject *
Twople(PyObject *i1, PyObject *i2)
{
PyObject *t;
if(t=PyTuple_New(2))
{
Py_INCREF(i1);
PyTuple_SET_ITEM(t,0,i1);
Py_INCREF(i2);
PyTuple_SET_ITEM(t,1,i2);
}
return t;
}
static int
BTree_ini(BTree *self)
{
PyObject *b;
UNLESS(b=PyObject_CallObject(OBJECT(&BucketType), NULL)) return -1;
#ifndef INTKEY
Py_INCREF(Py_None);
self->data->key=Py_None;
#endif
self->data->value=b;
self->data->count=0;
self->len=1;
self->count=0;
return 0;
}
static int
BTree_init(BTree *self)
{
UNLESS(self->data=PyMalloc(sizeof(BTreeItem)*2)) return -1;
self->size=2;
return BTree_ini(self);
}
static int
bucket_index(Bucket *self, PyObject *key, int less)
{
/*
If less, return the index of the largest key that is less than or
equall to key. Otherwise return the index of the smallest key
that is greater than or equal to key.
*/
int min, max, i, l, cmp;
#ifdef INTKEY
int ikey;
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return -9;
}
ikey=PyInt_AsLong(key);
#endif
PER_USE_OR_RETURN(self, -1);
for(min=0, max=self->len, i=max/2, l=max; i != l; l=i, i=(min+max)/2)
{
cmp=TEST_KEY(self->data[i].key);
if(cmp < 0) min=i;
else if(cmp == 0)
{
PER_ALLOW_DEACTIVATION(self);
return i;
}
else max=i;
}
PER_ALLOW_DEACTIVATION(self);
if(less) return max-1;
if(max==min) return min;
return min+1;
}
static PyObject *
_bucket_get(Bucket *self, PyObject *key, int has_key)
{
int min, max, i, l, cmp;
PyObject *r;
#ifdef INTKEY
int ikey;
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return NULL;
}
ikey=PyInt_AsLong(key);
#endif
PER_USE_OR_RETURN(self, NULL);
for(min=0, max=self->len, i=max/2, l=max; i != l; l=i, i=(min+max)/2)
{
cmp=TEST_KEY(self->data[i].key);
if(cmp < 0) min=i;
else if(cmp == 0)
{
if(has_key) r=PyInt_FromLong(1);
else
{
#ifdef INTVAL
r=PyInt_FromLong(self->data[i].value);
#else
r=self->data[i].value;
Py_INCREF(r);
#endif
}
PER_ALLOW_DEACTIVATION(self);
return r;
}
else max=i;
}
PER_ALLOW_DEACTIVATION(self);
if(has_key) return PyInt_FromLong(0);
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
static PyObject *
bucket_get(Bucket *self, PyObject *key)
{
return _bucket_get(self, key, 0);
}
static PyObject *
bucket_map(Bucket *self, PyObject *args)
{
PyObject *keys, *key, *r;
int l, i, a;
UNLESS(PyArg_ParseTuple(args,"O", &keys)) return NULL;
if((l=PyObject_Length(keys)) < 0) return NULL;
UNLESS(r=PyList_New(0)) return NULL;
for(i=0; i < l; i++)
{
UNLESS(key=PySequence_GetItem(keys,i)) goto err;
ASSIGN(key, _bucket_get(self, key, 0));
if(key)
{
a=PyList_Append(r,key);
Py_DECREF(key);
if(a<0) goto err;
}
else PyErr_Clear();
}
return r;
err:
Py_DECREF(r);
return NULL;
}
static int
BTree_index(BTree *self, PyObject *key, int less)
{
/*
If less, return the index of the largest key that is less than or
equall to key. Otherwise return the index of the smallest key
that is greater than or equal to key.
*/
int min, max, i, cmp;
#ifdef INTKEY
int ikey;
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return -9;
}
ikey=PyInt_AsLong(key);
#endif
PER_USE_OR_RETURN(self, -1);
UNLESS(self->data) if(BTree_init(self) < 0) goto err;
for(min=0, max=self->len, i=max/2; max-min > 1; i=(min+max)/2)
{
cmp=TEST_KEY(self->data[i].key);
if(cmp < 0) min=i;
else if(cmp == 0)
{
min=i;
break;
}
else max=i;
}
if(Bucket_Check(self->data[min].value))
i=bucket_index(BUCKET(self->data[min].value), key, less);
else
i= BTree_index( BTREE(self->data[min].value), key, less);
if(i==-9) goto err;
while(--min >= 0) i+=self->data[min].count;
PER_ALLOW_DEACTIVATION(self);
return i;
err:
PER_ALLOW_DEACTIVATION(self);
return -9;
}
static PyObject *
_BTree_get(BTree *self, PyObject *key, int has_key)
{
int min, max, i, cmp;
PyObject *r;
#ifdef INTKEY
int ikey;
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return NULL;
}
ikey=PyInt_AsLong(key);
#endif
PER_USE_OR_RETURN(self, NULL);
UNLESS(self->data) if(BTree_init(self) < 0) goto err;
for(min=0, max=self->len, i=max/2; max-min > 1; i=(min+max)/2)
{
cmp=TEST_KEY(self->data[i].key);
if(cmp < 0) min=i;
else if(cmp == 0)
{
min=i;
break;
}
else max=i;
}
if(Bucket_Check(self->data[min].value))
r=_bucket_get(BUCKET(self->data[min].value), key, has_key);
else
r=_BTree_get( BTREE(self->data[min].value), key, has_key);
PER_ALLOW_DEACTIVATION(self);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static PyObject *
BTree_get(BTree *self, PyObject *key)
{
return _BTree_get(self, key, 0);
}
static PyObject *
BTree_map(BTree *self, PyObject *args)
{
PyObject *keys, *key, *r;
int l, i, a;
UNLESS(PyArg_ParseTuple(args,"O", &keys)) return NULL;
if((l=PyObject_Length(keys)) < 0) return NULL;
UNLESS(r=PyList_New(0)) return NULL;
for(i=0; i < l; i++)
{
UNLESS(key=PySequence_GetItem(keys,i)) goto err;
ASSIGN(key, _BTree_get(self, key, 0));
if(key)
{
a=PyList_Append(r,key);
Py_DECREF(key);
if(a<0) goto err;
}
else PyErr_Clear();
}
return r;
err:
Py_DECREF(r);
return NULL;
}
static int
_bucket_set(Bucket *self, PyObject *key, PyObject *v)
{
int min, max, i, l, cmp;
Item *d;
#ifdef INTKEY
int ikey;
#endif
#ifdef INTVAL
int iv;
#endif
#ifdef INTKEY
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __setitem__ expected integer value");
return -1;
}
ikey=PyInt_AsLong(key);
#endif
#ifdef INTVAL
UNLESS(!v || PyInt_Check(v))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return -1;
}
iv=PyInt_AsLong(v);
#endif
PER_USE_OR_RETURN(self, -1);
for(min=0, max=l=self->len, i=max/2; i != l; l=i, i=(min+max)/2)
{
if((cmp=TEST_KEY(self->data[i].key)) < 0) min=i;
else if(cmp==0)
{
if(v)
{
Py_INCREF(v);
#ifdef INTVAL
self->data[i].value=iv;
#else
ASSIGN(self->data[i].value, v);
#endif
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
return 0;
}
else
{
self->len--;
d=self->data+i;
DECREF_KEY(d->key);
DECREF_VALUE(d->value);
if(i < self->len) memmove(d,d+1,sizeof(Item)*(self->len-i));
else if(! self->len)
{
self->size=0;
free(self->data);
self->data=NULL;
}
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
return 1;
}
}
else max=i;
}
if(!v)
{
PyErr_SetObject(PyExc_KeyError, key);
goto err;
}
if(self->len==self->size)
{
if(self->data)
{
UNLESS(d=PyRealloc(self->data, sizeof(Item)*self->size*2)) goto err;
self->data=d;
self->size*=2;
}
else
{
UNLESS(self->data=PyMalloc(sizeof(Item)*MIN_BUCKET_ALLOC)) goto err;
self->size=MIN_BUCKET_ALLOC;
}
}
if(max != i) i++;
d=self->data+i;
if(self->len > i) memmove(d+1,d,sizeof(Item)*(self->len-i));
#ifdef INTKEY
d->key=ikey;
#else
d->key=key;
Py_INCREF(key);
#endif
#ifdef INTVAL
d->value=iv;
#else
d->value=v;
Py_INCREF(v);
#endif
self->len++;
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
return 1;
err:
PER_ALLOW_DEACTIVATION(self);
return -1;
}
static int
bucket_setitem(Bucket *self, PyObject *key, PyObject *v)
{
if(_bucket_set(self,key,v) < 0) return -1;
return 0;
}
static int
bucket_split(Bucket *self, int index, Bucket *next)
{
if(index < 0 || index >= self->len) index=self->len/2;
UNLESS(next->data=PyMalloc(sizeof(Item)*(self->len-index))) return -1;
next->len=self->len-index;
next->size=next->len;
memcpy(next->data, self->data+index, sizeof(Item)*next->size);
self->len=index;
return 0;
}
static int
BTree_count(BTree *self)
{
int i, c=0;
BTreeItem *d;
for(i=self->len, d=self->data; --i >= 0; d++)
c += d->count;
return c;
}
static int
BTree_split(BTree *self, int index, BTree *next)
{
if(index < 0 || index >= self->len) index=self->len/2;
UNLESS(next->data=PyMalloc(sizeof(BTreeItem)*(self->len-index)))
return -1;
next->len=self->len-index;
next->size=next->len;
memcpy(next->data, self->data+index, sizeof(BTreeItem)*next->size);
if((next->count=BTree_count(next)) < 0) return -1;
self->len = index;
self->count -= next->count;
return 0;
}
static int
BTree_clone(BTree *self)
{
/* We've grown really big without anybody splitting us.
We should split ourselves.
*/
BTree *n1=0, *n2=0;
BTreeItem *d=0;
int count;
/* Create two BTrees to hold ourselves after split */
UNLESS(n1=BTREE(PyObject_CallObject(OBJECT(self->ob_type), NULL))) return -1;
UNLESS(n2=BTREE(PyObject_CallObject(OBJECT(self->ob_type), NULL))) goto err;
/* Create a new data buffer to hold two BTrees */
UNLESS(d=PyMalloc(sizeof(BTreeItem)*2)) goto err;
count=self->count;
/* Split ourself */
if(BTree_split(self,-1,n2) < 0) goto err;
/* Move our data to new BTree */
n1->size=self->size;
n1->len=self->len;
n1->count=self->count;
n1->data=self->data;
/* Initialize our data to hold split data */
self->data=d;
Py_INCREF(Py_None);
#ifndef INTKEY
self->data->key=Py_None;
#endif
self->len=2;
self->size=2;
self->data->value=OBJECT(n1);
self->data->count=n1->count;
#ifndef INTKEY
Py_INCREF(n2->data->key);
#endif
self->data[1].key=n2->data->key;
self->data[1].value=OBJECT(n2);
self->data[1].count=n2->count;
self->count=count;
return 0;
err:
Py_XDECREF(n1);
Py_XDECREF(n2);
free(d);
return -1;
}
static int
BTree_grow(BTree *self, int index)
{
int i;
PyObject *v, *e=0;
BTreeItem *d;
if(self->len == self->size)
{
UNLESS(d=PyRealloc(self->data, sizeof(BTreeItem)*self->size*2))
return -1;
self->data=d;
self->size *= 2;
}
d=self->data+index;
v=d->value;
UNLESS(e=PyObject_CallObject(OBJECT(v->ob_type), NULL)) return -1;
PER_USE_OR_RETURN(v, -1);
if(Bucket_Check(v))
{
i=bucket_split(BUCKET(v), -1, BUCKET(e));
d->count=BUCKET(v)->len;
}
else
{
i=BTree_split( BTREE(v), -1, BTREE(e));
d->count=BTREE(v)->count;
}
PER_ALLOW_DEACTIVATION(BUCKET(v));
if(i < 0)
{
Py_DECREF(e);
return -1;
}
index++;
d++;
if(self->len > index)
memmove(d+1, d, sizeof(BTreeItem)*(self->len-index));
if(Bucket_Check(v))
{
d->key=BUCKET(e)->data->key;
d->count=BUCKET(e)->len;
}
else
{
d->key=BTREE(e)->data->key;
d->count=BTREE(e)->count;
}
#ifndef INTKEY
Py_INCREF(d->key);
#endif
d->value=e;
self->len++;
if(self->len >= MAX_SIZE(self) * 2) return BTree_clone(self);
return 0;
}
static int
_BTree_set(BTree *self, PyObject *key, PyObject *value)
{
int i, min, max, cmp, grew;
BTreeItem *d;
#ifdef INTKEY
int ikey;
#endif
#ifdef INTVAL
int iv;
#endif
#ifdef INTKEY
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __setitem__ expected integer value");
return -1;
}
ikey=PyInt_AsLong(key);
#endif
#ifdef INTVAL
UNLESS(!value || PyInt_Check(value))
{
PyErr_SetString(PyExc_TypeError,
"Bucket __getitem__ expected integer key");
return -1;
}
iv=PyInt_AsLong(value);
#endif
PER_USE_OR_RETURN(self, -1);
UNLESS(self->data) if(BTree_init(self) < 0) goto err;
for(min=0, max=self->len, i=max/2; max-min > 1; i=(max+min)/2)
{
d=self->data+i;
cmp=TEST_KEY(d->key);
if(cmp < 0) min=i;
else if(cmp==0)
{
min=i;
break;
}
else max=i;
}
d=self->data+min;
if(Bucket_Check(d->value))
grew=_bucket_set(BUCKET(d->value), key, value);
else
grew= _BTree_set( BTREE(d->value), key, value);
if(grew < 0) goto err;
if(grew)
{
if(value) /* got bigger */
{
d->count++;
self->count++;
if(BUCKET(d->value)->len > MAX_SIZE(self) &&
BTree_grow(self,min) < 0) goto err;
}
else /* got smaller */
{
d->count--;
self->count--;
if(! d->count)
{
self->len--;
Py_DECREF(d->value);
DECREF_KEY(d->key);
if(min < self->len)
memmove(d, d+1, (self->len-min)*sizeof(BTreeItem));
}
}
if(PER_CHANGED(self) < 0) goto err;
}
PER_ALLOW_DEACTIVATION(self);
return grew;
err:
PER_ALLOW_DEACTIVATION(self);
return -1;
}
static int
BTree_setitem(BTree *self, PyObject *key, PyObject *v)
{
if(_BTree_set(self,key,v) < 0) return -1;
return 0;
}
static PyObject *
bucket_keys(Bucket *self, PyObject *args)
{
PyObject *r=0, *key;
int i;
PER_USE_OR_RETURN(self, NULL);
UNLESS(r=PyList_New(self->len)) goto err;
for(i=self->len; --i >= 0; )
{
#ifdef INTKEY
UNLESS(key=PyInt_FromLong(self->data[i].key)) goto err;
#else
key=self->data[i].key;
Py_INCREF(key);
#endif
if(PyList_SetItem(r, i, key) < 0) goto err;
}
PER_ALLOW_DEACTIVATION(self);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(r);
return NULL;
}
static PyObject *
bucket_values(Bucket *self, PyObject *args)
{
PyObject *r=0, *v;
int i;
PER_USE_OR_RETURN(self, NULL);
UNLESS(r=PyList_New(self->len)) goto err;
for(i=self->len; --i >= 0; )
{
#ifdef INTVAL
UNLESS(v=PyInt_FromLong(self->data[i].value)) goto err;
#else
v=self->data[i].value;
Py_INCREF(v);
#endif
if(PyList_SetItem(r, i, v) < 0) goto err;
}
PER_ALLOW_DEACTIVATION(self);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(r);
return NULL;
}
static PyObject *
bucket_items(Bucket *self, PyObject *args)
{
PyObject *r, *item;
int i;
PER_USE_OR_RETURN(self, NULL);
UNLESS(r=PyList_New(self->len)) goto err;
for(i=self->len; --i >= 0; )
{
UNLESS(item=Py_BuildValue(KEY_PARSE VALUE_PARSE,
self->data[i].key,self->data[i].value))
goto err;
if(PyList_SetItem(r, i, item) < 0) goto err;
}
PER_ALLOW_DEACTIVATION(self);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(r);
return NULL;
}
#ifdef PERSISTENT
static PyObject *
bucket__p___reinit__(Bucket *self, PyObject *args)
{
int i;
/* Note that this implementation is broken, in that it doesn't
account for subclass needs. */
for(i=self->len; --i >= 0; )
{
DECREF_KEY(self->data[i].key);
DECREF_VALUE(self->data[i].value);
}
self->len=0;
Py_INCREF(Py_None);
return Py_None;
}
#endif
static PyObject *
bucket_clear(Bucket *self, PyObject *args)
{
int i;
PER_USE_OR_RETURN(self, NULL);
for(i=self->len; --i >= 0; )
{
DECREF_KEY(self->data[i].key);
DECREF_VALUE(self->data[i].value);
}
self->len=0;
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
RETURN_NONE;
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static int
_BTree_clear(BTree *self)
{
int i;
UNLESS(self->data) return 0;
for(i=self->len; --i >= 0; )
{
DECREF_KEY(self->data[i].key);
Py_DECREF(self->data[i].value);
}
i=BTree_ini(self);
return i;
}
#ifdef PERSISTENT
static PyObject *
BTree__p___reinit__(BTree *self, PyObject *args)
{
/* Note that this implementation is broken, in that it doesn't
account for subclass needs. */
if(_BTree_clear(self) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
#endif
static PyObject *
BTree_clear(BTree *self, PyObject *args)
{
PER_USE_OR_RETURN(self, NULL);
if(_BTree_clear(self) < 0) goto err;
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
RETURN_NONE;
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static PyObject *
bucket_getstate(Bucket *self, PyObject *args)
{
PyObject *r, *keys=0, *values=0;
int i, l;
#ifdef INTKEY
int v;
char *c;
#else
#ifdef INTVAL
int v;
char *c;
#endif
#endif
PER_USE_OR_RETURN(self, NULL);
l=self->len;
#ifdef INTKEY
UNLESS(keys=PyString_FromStringAndSize(NULL,l*sizeof(int))) goto err;
UNLESS(c=PyString_AsString(keys)) goto err;
for(i=0; i < l; i++)
{
v=self->data[i].key;
*c++ = (int)( v & 0xff);
*c++ = (int)((v >> 8) & 0xff);
*c++ = (int)((v >> 16) & 0xff);
*c++ = (int)((v >> 24) & 0xff);
}
#else
UNLESS(keys=PyTuple_New(self->len)) goto err;
for(i=0; i<l; i++)
{
r=self->data[i].key;
Py_INCREF(r);
PyTuple_SET_ITEM(keys,i,r);
}
#endif
#ifdef INTVAL
UNLESS(values=PyString_FromStringAndSize(NULL,l*sizeof(int))) goto err;
UNLESS(c=PyString_AsString(values)) goto err;
for(i=0; i < l; i++)
{
v=self->data[i].value;
*c++ = (int)( v & 0xff);
*c++ = (int)((v >> 8) & 0xff);
*c++ = (int)((v >> 16) & 0xff);
*c++ = (int)((v >> 24) & 0xff);
}
#else
UNLESS(values=PyTuple_New(self->len)) goto err;
for(i=0; i<l; i++)
{
r=self->data[i].value;
Py_INCREF(r);
PyTuple_SET_ITEM(values,i,r);
}
#endif
PER_ALLOW_DEACTIVATION(self);
r=Py_BuildValue("OO",keys,values);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
Py_XDECREF(keys);
Py_XDECREF(values);
return NULL;
}
static PyObject *
bucket_setstate(Bucket *self, PyObject *args)
{
PyObject *r, *keys=0, *values=0;
int i, l, v;
Item *d;
#ifdef INTKEY
char *ck;
#endif
#ifdef INTVAL
char *cv;
#endif
PER_PREVENT_DEACTIVATION(self);
UNLESS(PyArg_ParseTuple(args,"O",&r)) goto err;
UNLESS(PyArg_ParseTuple(r,"OO",&keys,&values)) goto err;
if((l=PyObject_Length(keys)) < 0) goto err;
#ifdef INTKEY
l/=4;
UNLESS(ck=PyString_AsString(keys)) goto err;
#endif
if((v=PyObject_Length(values)) < 0) goto err;
#ifdef INTVAL
v/=4;
UNLESS(cv=PyString_AsString(values)) goto err;
#endif
if(l!=v)
{
PyErr_SetString(PyExc_ValueError,
"number of keys differs from number of values");
goto err;
}
if(l > self->size)
if(self->data)
{
UNLESS(d=PyRealloc(self->data, sizeof(Item)*l)) goto err;
self->data=d;
self->size=l;
}
else
{
UNLESS(d=PyMalloc(sizeof(Item)*l)) goto err;
self->data=d;
self->size=l;
}
else d=self->data;
#ifdef INTKEY
for(i=l; --i >= 0; d++)
{
v = ((int)(unsigned char)*ck++) ;
v |= ((int)(unsigned char)*ck++) << 8;
v |= ((int)(unsigned char)*ck++) << 16;
v |= ((int)(unsigned char)*ck++) << 24;
d->key=v;
}
#else
for(i=0; i<l; i++, d++)
{
UNLESS(r=PySequence_GetItem(keys,i)) goto err;
if(i < self->len) Py_DECREF(d->key);
d->key=r;
}
#endif
d=self->data;
#ifdef INTVAL
for(i=l; --i >= 0; d++)
{
v = ((int)(unsigned char)*cv++) ;
v |= ((int)(unsigned char)*cv++) << 8;
v |= ((int)(unsigned char)*cv++) << 16;
v |= ((int)(unsigned char)*cv++) << 24;
d->value=v;
}
#else
for(i=0; i<l; i++, d++)
{
UNLESS(r=PySequence_GetItem(values,i)) goto err;
if(i < self->len) Py_DECREF(d->value);
d->value=r;
}
#endif
self->len=l;
PER_ALLOW_DEACTIVATION(self);
Py_INCREF(Py_None);
return Py_None;
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static PyObject *
bucket_has_key(Bucket *self, PyObject *args)
{
PyObject *key;
UNLESS(PyArg_ParseTuple(args,"O",&key)) return NULL;
return _bucket_get(self, key, 1);
}
static struct PyMethodDef Bucket_methods[] = {
{"__getstate__", (PyCFunction)bucket_getstate, METH_VARARGS,
"__getstate__() -- Return the picklable state of the object"},
{"__setstate__", (PyCFunction)bucket_setstate, METH_VARARGS,
"__setstate__() -- Set the state of the object"},
{"keys", (PyCFunction)bucket_keys, METH_VARARGS,
"keys() -- Return the keys"},
{"has_key", (PyCFunction)bucket_has_key, METH_VARARGS,
"has_key(key) -- Test whether the bucket contains the given key"},
{"values", (PyCFunction)bucket_values, METH_VARARGS,
"values() -- Return the values"},
{"items", (PyCFunction)bucket_items, METH_VARARGS,
"items() -- Return the items"},
{"clear", (PyCFunction)bucket_clear, METH_VARARGS,
"clear() -- Remove all of the items from the bucket"},
{"map", (PyCFunction)bucket_map, METH_VARARGS,
"map(keys) -- map a sorted sequence of keys into values\n\n"
"Invalid keys are skipped"},
#ifdef PERSISTENT
{"_p___reinit__", (PyCFunction)bucket__p___reinit__, METH_VARARGS,
"_p___reinit__() -- Reinitialize from a newly created copy"},
#endif
{NULL, NULL} /* sentinel */
};
static PyObject *
BTree_getstate(BTree *self, PyObject *args)
{
PyObject *r=0, *item;
int i;
PER_USE_OR_RETURN(self, NULL);
UNLESS(r=PyTuple_New(self->len)) goto err;
for(i=self->len; --i >= 0; )
{
UNLESS(item=Py_BuildValue(KEY_PARSE "Oi",
self->data[i].key, self->data[i].value,
self->data[i].count))
goto err;
PyTuple_SET_ITEM(r,i,item);
}
PER_ALLOW_DEACTIVATION(self);
return r;
err:
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(r);
return NULL;
}
static PyObject *
BTree_setstate(BTree *self, PyObject *args)
{
PyObject *state, *v=0;
BTreeItem *d;
int l, i;
UNLESS(PyArg_ParseTuple(args,"O",&state)) return NULL;
if((l=PyTuple_Size(state))<0) return NULL;
PER_PREVENT_DEACTIVATION(self);
if(l>self->size)
{
if(self->data)
{
UNLESS(d=PyRealloc(self->data, sizeof(BTreeItem)*l)) goto err;
self->data=d;
self->size=l;
}
else
{
UNLESS(self->data=PyMalloc(sizeof(BTreeItem)*l)) goto err;
self->size=l;
}
}
for(i=self->len, d=self->data; --i >= 0; d++)
{
DECREF_KEY(d->key);
Py_DECREF(d->value);
}
for(self->len=0, self->count=0, i=0, d=self->data; i < l;
i++, d++, self->len++)
{
UNLESS(PyArg_ParseTuple(PyTuple_GET_ITEM(state,i),
KEY_PARSE "Oi",
&(d->key), &(d->value), &(d->count)))
goto err;
#ifndef INTKEY
Py_INCREF(d->key);
#endif
Py_INCREF(d->value);
self->count+=d->count;
}
PER_ALLOW_DEACTIVATION(self);
Py_INCREF(Py_None);
return Py_None;
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static PyObject *
BTree_elements(BTree *self, PyObject *args, char type)
{
PyObject *f=0, *l=0;
int fi, li;
UNLESS(PyArg_ParseTuple(args,"|OO",&f, &l)) return NULL;
PER_USE_OR_RETURN(self, NULL);
if(f && f != Py_None)
{
fi=BTree_index(self, f, 0);
if(fi==-9) goto err;
}
else fi=0;
if(l)
{
li=BTree_index(self, l, 1);
if(li==-9) goto err;
li++;
}
else li=self->count;
PER_ALLOW_DEACTIVATION(self);
return newBTreeItems(self,type,fi,li);
err:
PER_ALLOW_DEACTIVATION(self);
return NULL;
}
static PyObject *
BTree_keys(BTree *self, PyObject *args)
{
return BTree_elements(self,args,'k');
}
static PyObject *
BTree_values(BTree *self, PyObject *args)
{
return BTree_elements(self,args,'v');
}
static PyObject *
BTree_items(BTree *self, PyObject *args)
{
return BTree_elements(self,args,'i');
}
static PyObject *
BTree_has_key(BTree *self, PyObject *args)
{
PyObject *key;
UNLESS(PyArg_ParseTuple(args,"O",&key)) return NULL;
return _BTree_get(self, key, 1);
}
static struct PyMethodDef BTree_methods[] = {
{"__getstate__", (PyCFunction)BTree_getstate, METH_VARARGS,
"__getstate__() -- Return the picklable state of the object"},
{"__setstate__", (PyCFunction)BTree_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"},
{"values", (PyCFunction)BTree_values, METH_VARARGS,
"values() -- Return the values"},
{"items", (PyCFunction)BTree_items, METH_VARARGS,
"items() -- Return the items"},
{"clear", (PyCFunction)BTree_clear, METH_VARARGS,
"clear() -- Remove all of the items from the BTree"},
{"map", (PyCFunction)BTree_map, METH_VARARGS,
"map(keys) -- map a sorted sequence of keys into values\n\n"
"Invalid keys are skipped"},
#ifdef PERSISTENT
{"_p___reinit__", (PyCFunction)BTree__p___reinit__, METH_VARARGS,
"_p___reinit__() -- Reinitialize from a newly created copy"},
#endif
{NULL, NULL} /* sentinel */
};
static void
Bucket_dealloc(Bucket *self)
{
int i;
for(i=self->len; --i >= 0; )
{
DECREF_KEY(self->data[i].key);
DECREF_VALUE(self->data[i].value);
}
free(self->data);
PyMem_DEL(self);
}
static void
BTree_dealloc(BTree *self)
{
int i;
for(i=self->len; --i >= 0; )
{
DECREF_KEY(self->data[i].key);
Py_DECREF(self->data[i].value);
}
free(self->data);
PyMem_DEL(self);
}
/* Code to access Bucket objects as mappings */
static int
Bucket_length( Bucket *self)
{
int r;
PER_USE_OR_RETURN(self, -1);
r=self->len;
PER_ALLOW_DEACTIVATION(self);
return r;
}
static PyMappingMethods Bucket_as_mapping = {
(inquiry)Bucket_length, /*mp_length*/
(binaryfunc)bucket_get, /*mp_subscript*/
(objobjargproc)bucket_setitem, /*mp_ass_subscript*/
};
static int
BTree_length( BTree *self)
{
int r;
PER_USE_OR_RETURN(self, -1);
r=self->count;
PER_ALLOW_DEACTIVATION(self);
return r;
}
static PyMappingMethods BTree_as_mapping = {
(inquiry)BTree_length, /*mp_length*/
(binaryfunc)BTree_get, /*mp_subscript*/
(objobjargproc)BTree_setitem, /*mp_ass_subscript*/
};
static PyObject *
bucket_repr(Bucket *self)
{
static PyObject *format;
PyObject *r, *t;
UNLESS(format) UNLESS(format=PyString_FromString("Bucket(%s)")) return NULL;
UNLESS(t=PyTuple_New(1)) return NULL;
UNLESS(r=bucket_items(self,NULL)) goto err;
PyTuple_SET_ITEM(t,0,r);
r=t;
ASSIGN(r,PyString_Format(format,r));
return r;
err:
Py_DECREF(t);
return NULL;
}
static PyExtensionClass BucketType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Bucket", /*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)bucket_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&Bucket_as_mapping, /*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,
"Mapping type implemented as sorted list of items",
METHOD_CHAIN(Bucket_methods),
};
static PyExtensionClass BTreeType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"BTree", /*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*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&BTree_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,
"Mapping type implemented as sorted list of items",
METHOD_CHAIN(BTree_methods),
};
static struct PyMethodDef module_methods[] = {
{NULL, NULL} /* sentinel */
};
void
#ifdef INTKEY
#ifdef INTVAL
initIIBTree()
#define MODNAME "IIBTree"
#else
initIOBTree()
#define MODNAME "IOBTree"
#endif
#else
#ifdef INTVAL
initOIBTree()
#define MODNAME "OIBTree"
#else
initBTree()
#define MODNAME "BTree"
#endif
#endif
{
PyObject *m, *d;
char *rev="$Revision: 1.10 $";
UNLESS(PyExtensionClassCAPI=PyCObject_Import("ExtensionClass","CAPI"))
return;
#ifdef PERSISTENT
if(cPersistenceCAPI=PyCObject_Import("cPersistence","CAPI"))
{
static PyMethodChain mb, mn;
mb.methods=BucketType.methods.methods;
BucketType.methods.methods=cPersistenceCAPI->methods->methods;
BucketType.methods.link=&mb;
BucketType.tp_getattro=cPersistenceCAPI->getattro;
BucketType.tp_setattro=cPersistenceCAPI->setattro;
mn.methods=BTreeType.methods.methods;
BTreeType.methods.methods=cPersistenceCAPI->methods->methods;
BTreeType.methods.link=&mn;
BTreeType.tp_getattro=cPersistenceCAPI->getattro;
BTreeType.tp_setattro=cPersistenceCAPI->setattro;
}
else return;
#else
BucketType.tp_getattro=PyExtensionClassCAPI->getattro;
BTreeType.tp_getattro=PyExtensionClassCAPI->getattro;
#endif
/* Create the module and add the functions */
m = Py_InitModule4(MODNAME, module_methods,
BTree_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"Bucket",BucketType);
PyExtensionClass_Export(d,"BTree",BTreeType);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
#include "dcprotect.h"
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module BTree");
}
/*
PER_USE_OR_RETURN(self, NULL);
PER_ALLOW_DEACTIVATION(self);
*/
/*****************************************************************************
Revision Log:
$Log: BTree.c,v $
Revision 1.10 1997/11/13 20:45:51 jim
Fixed some bad return values.
Revision 1.9 1997/11/13 20:38:35 jim
added dcprotect
Revision 1.8 1997/11/03 15:17:53 jim
Fixed stupid bug in has_key methods.
Revision 1.7 1997/10/30 20:58:43 jim
Upped bucket sizes.
Revision 1.6 1997/10/10 18:21:45 jim
Fixed bug in range queries.
Revision 1.5 1997/10/01 02:47:06 jim
Fixed bug in setstate that allocates too much memory.
Revision 1.4 1997/09/17 17:20:32 jim
Fixed bug in deleting members from BTree.
Revision 1.3 1997/09/12 18:35:45 jim
Fixed bug leading to random core dumps.
Revision 1.2 1997/09/10 17:24:47 jim
*** empty log message ***
Revision 1.1 1997/09/08 18:42:21 jim
initial BTree
$Revision 1.1 1997/02/24 23:25:42 jim
$initial
$
*****************************************************************************/
/* $Id: IIBTree.c,v 1.4 1997/10/10 18:23:37 jim Exp $ */
#define INTKEY int
#define INTVAL int
static char *needed_to_make_release_happy="$Id: IIBTree.c,v 1.4 1997/10/10 18:23:37 jim Exp $";
#include "BTree.c"
/* $Id: IOBTree.c,v 1.4 1997/10/10 18:24:11 jim Exp $ */
static char *needed_to_make_release_happy=
"$Id: IOBTree.c,v 1.4 1997/10/10 18:24:11 jim Exp $";
#define INTKEY int
#include "BTree.c"
/* $Id: OIBTree.c,v 1.4 1997/10/10 18:24:35 jim Exp $ */
static char *needed_to_make_release_happy=
"$Id: OIBTree.c,v 1.4 1997/10/10 18:24:35 jim Exp $";
#define INTVAL int
#include "BTree.c"
/***********************************************************
Copyright
Copyright 1997 Digital Creations, L.L.C., 910 Princess Anne
Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
rights reserved. Copyright in this software is owned by DCLC,
unless otherwise indicated. Permission to use, copy and
distribute this software is hereby granted, provided that the
above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear. Note that
any product, process or technology described in this software
may be the subject of other Intellectual Property rights
reserved by Digital Creations, L.C. and are not licensed
hereunder.
Trademarks
Digital Creations & DCLC, are trademarks of Digital Creations, L.C..
All other trademarks are owned by their respective companies.
No Warranty
The software is provided "as is" without warranty of any kind,
either express or implied, including, but not limited to, the
implied warranties of merchantability, fitness for a particular
purpose, or non-infringement. This software could include
technical inaccuracies or typographical errors. Changes are
periodically made to the software; these changes will be
incorporated in new editions of the software. DCLC may make
improvements and/or changes in this software at any time
without notice.
Limitation Of Liability
In no event will DCLC be liable for direct, indirect, special,
incidental, economic, cover, or consequential damages arising
out of the use of or inability to use this software even if
advised of the possibility of such damages. Some states do not
allow the exclusion or limitation of implied warranties or
limitation of liability for incidental or consequential
damages, so the above limitation or exclusion may not apply to
you.
If you have questions regarding this software,
contact:
Digital Creations L.L.C.
info@digicool.com
(540) 371-6909
******************************************************************/
static char Trie_module_documentation[] =
""
"\n$Id: Trie.c,v 1.13 1997/09/10 17:27:14 jim Exp $"
;
#define PERSISTENT 1
/* Note that I haven't put ifdefs everywhere they apply yet. */
#ifdef PERSISTENT
# include "cPersistence.h"
#else
# include "ExtensionClass.h"
# define PER_PREVENT_DEACTIVATION(SELF)
# define PER_ALLOW_DEACTIVATION(SELF)
# define PER_CHANGED(O) 0
# define PER_USE_OR_RETURN(O,R)
#endif
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define PyOb(O) ((PyObject*)(O))
#define LIST(O) ((PyListObject*)(O))
#define STRING(O) ((PyStringObject*)(O))
#define PyList_SIZE(O) (((PyListObject*)(O))->ob_size)
static PyObject *py___class__, *py_Trief;
/* Declarations for objects of type Trie */
typedef struct {
#ifdef PERSISTENT
cPersistent_HEAD
#endif
int min;
PyObject *bins;
PyObject *value;
} TrieObject;
staticforward PyExtensionClass TrieType;
/* ---------------------------------------------------------------- */
#ifdef PERSISTENT
static PyObject *
PER_RETURN(TrieObject *self, PyObject *r)
{
PER_ALLOW_DEACTIVATION(self);
return r;
}
static int
PER_INT_RETURN(TrieObject *self, int r)
{
PER_ALLOW_DEACTIVATION(self);
return r;
}
#else
#define PER_RETURN(SELF,R) R
#define PER_INT_RETURN(SELF,R) R
#endif
static PyObject *
Trie___setstate__(TrieObject *self, PyObject *args)
{
PyObject *state;
UNLESS(PyArg_ParseTuple(args, "O", &state)) return NULL;
PER_PREVENT_DEACTIVATION(self);
if(state != Py_None)
{
self->value=NULL;
UNLESS(PyArg_ParseTuple(state, "iO|O", &(self->min), &(self->bins),
&(self->value)))
return PER_RETURN(self, NULL);
if(self->min < 0)
{
self->value=self->bins;
self->bins=NULL;
}
Py_XINCREF(self->value);
Py_XINCREF(self->bins);
}
Py_INCREF(Py_None);
return PER_RETURN(self, Py_None);
}
static PyObject *
Trie___getstate__(TrieObject *self, PyObject *args)
{
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
PER_USE_OR_RETURN(self, NULL);
if(self->value)
if(self->bins)
return PER_RETURN(self,
Py_BuildValue("(iOO)",
self->min, self->bins, self->value));
else
return PER_RETURN(self, Py_BuildValue("(iO)", -1, self->value));
else
if(self->bins)
return PER_RETURN(self, Py_BuildValue("(iO)", self->min, self->bins));
Py_INCREF(Py_None);
return PER_RETURN(self, Py_None);
}
#ifdef PERSISTENT
static PyObject *
Trie__p___reinit__(TrieObject *self, PyObject *args)
{
/* Note that this implementation is broken, in that it doesn't
account for subclass needs. */
Py_XDECREF(self->bins);
Py_XDECREF(self->value);
self->bins=NULL;
self->value=NULL;
self->min=0;
self->state=cPersistent_GHOST_STATE;
/*printf("r");*/
Py_INCREF(Py_None);
return Py_None;
}
#endif
typedef struct {
char *data;
int size;
} keybuf;
static PyObject *
getiork(TrieObject *self, PyObject * r, keybuf *buf, int l, int dokeys)
{
int i;
PyObject *item=0;
PER_USE_OR_RETURN(self, NULL);
if(self->value)
{
if(dokeys)
{
UNLESS(item=PyString_FromStringAndSize(buf->data,l))
return PER_RETURN(self, NULL);
}
else
UNLESS(item=Py_BuildValue("(s#O)",buf->data,l,self->value))
return PER_RETURN(self, NULL);
i=PyList_Append(r,item);
Py_DECREF(item);
if(i < 0) return PER_RETURN(self, NULL);
}
if(l==buf->size)
{
buf->size *= 2;
UNLESS(buf->data=realloc(buf->data, buf->size))
return PER_RETURN(self, PyErr_NoMemory());
}
if(self->bins)
{
PyObject *bin;
int s, l1, ibin;
for(ibin=0, l1=l+1, s=PyList_SIZE(self->bins); ibin < s; ibin++)
{
bin=PyList_GET_ITEM(LIST(self->bins), ibin);
if(bin->ob_type==self->ob_type)
{
buf->data[l]=self->min+ibin;
UNLESS(getiork((TrieObject*)bin,r,buf,l1,dokeys))
return PER_RETURN(self, NULL);
}
else if(PyTuple_Check(bin))
{
buf->data[l]=self->min+ibin;
UNLESS(item=PyString_FromStringAndSize(buf->data,l1))
return PER_RETURN(self, NULL);
ASSIGN(item,PySequence_Concat(item,PyTuple_GET_ITEM(bin,0)));
if(! dokeys && item)
ASSIGN(item, Py_BuildValue("OO",item,PyTuple_GET_ITEM(bin,1)));
UNLESS(item) return PER_RETURN(self, NULL);
i=PyList_Append(r,item);
Py_DECREF(item);
if(i < 0) return PER_RETURN(self, NULL);
}
}
}
return PER_RETURN(self, r);
}
static PyObject *
iork(TrieObject *self, int dokeys)
{
PyObject *r=0;
keybuf buf;
buf.size=32;
UNLESS(buf.data=(char*)malloc(buf.size)) return PyErr_NoMemory();
UNLESS(r=PyList_New(0)) goto err;
UNLESS(getiork(self, r, &buf, 0, dokeys)) goto err;
free(buf.data);
return r;
err:
free(buf.data);
Py_XDECREF(r);
return NULL;
}
static PyObject *
Trie_keys(TrieObject *self, PyObject *args)
{
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
return iork(self,1);
}
static PyObject *
Trie_cvalues(TrieObject *self, PyObject *r)
{
PER_USE_OR_RETURN(self, NULL);
if(self->value)
if(PyList_Append(r,self->value) < 0) return PER_RETURN(self, NULL);
if(self->bins)
{
PyObject *bin;
int i, s=0;
for(i=0, s=PyList_SIZE(self->bins); i < s; i++)
{
bin=PyList_GET_ITEM(LIST(self->bins), i);
if(bin->ob_type==self->ob_type)
{
UNLESS(Trie_cvalues((TrieObject*)bin,r))
return PER_RETURN(self, NULL);
}
else if(PyTuple_Check(bin))
if(PyList_Append(r,PyTuple_GET_ITEM(bin,1)) < 0)
return PER_RETURN(self, NULL);
}
}
return PER_RETURN(self, r);
}
static PyObject *
Trie_values(TrieObject *self, PyObject *args)
{
PyObject *r;
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
UNLESS(r=PyList_New(0)) return NULL;
UNLESS(Trie_cvalues(self,r))
{
Py_DECREF(r);
r=NULL;
}
return r;
}
static PyObject *
Trie_items(TrieObject *self, PyObject *args)
{
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
return iork(self,0);
}
static int
Trie_cclear(TrieObject *self)
{
#ifdef PERSISTENT
int changed=0;
#endif
PER_USE_OR_RETURN(self, -1);
if(self->value)
{
Py_DECREF(self->value);
self->value=NULL;
#ifdef PERSISTENT
changed=1;
#endif
}
if(self->bins)
{
PyObject *bin;
int i, s=0;
for(i=0, s=PyList_SIZE(self->bins); i < s; i++)
{
bin=PyList_GET_ITEM(LIST(self->bins), i);
if(bin->ob_type==self->ob_type)
{
if(Trie_cclear((TrieObject*)bin) < 0)
return PER_INT_RETURN(self, -1);
}
else
{
Py_INCREF(Py_None);
if(PyList_SetItem(self->bins, i, Py_None) < 0)
return PER_INT_RETURN(self, -1);
#ifdef PERSISTENT
changed=1;
#endif
}
}
}
#ifdef PERSISTENT
if(changed && PER_CHANGED(self) < 0) return PER_INT_RETURN(self, -1);
#endif
return PER_INT_RETURN(self, 0);
}
static PyObject *
Trie_clear(TrieObject *self, PyObject *args)
{
UNLESS(PyArg_ParseTuple(args, "")) return NULL;
if(Trie_cclear(self) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef Trie_methods[] = {
{"__getstate__", (PyCFunction)Trie___getstate__, METH_VARARGS,
"__getstate__() -- Get the persistent state of the trie"},
{"__setstate__", (PyCFunction)Trie___setstate__, METH_VARARGS,
"__setstate__(v) -- Set the persistent state of the trie"},
#ifdef PERSISTENT
{"_p___reinit__", (PyCFunction)Trie__p___reinit__, METH_VARARGS,
"_p___reinit__() -- Reinitialize from a newly created copy"},
#endif
{"keys", (PyCFunction)Trie_keys, METH_VARARGS,
"keys() -- Get the keys of the trie"},
{"values", (PyCFunction)Trie_values, METH_VARARGS,
"values() -- Get the values of the trie"},
{"items", (PyCFunction)Trie_items, METH_VARARGS,
"items() -- Get the items of the trie"},
{"clear", (PyCFunction)Trie_clear, METH_VARARGS,
"clear() -- Remove the items from the trie"},
{NULL, NULL} /* sentinel */
};
static PyObject *
NotFoundError(PyObject *key)
{
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
static PyObject *
Trie_cget(TrieObject *self, char *word, PyObject *oword)
{
int c;
PyObject *bins, *bin;
PyTypeObject *typ;
PyObject *key;
PER_USE_OR_RETURN(self, NULL);
typ=self->ob_type;
Py_INCREF(self);
while(c=*word++)
{
if(! (bins=self->bins) || c < self->min) goto not_found;
c-=self->min;
if(c >= PyList_SIZE(bins)) goto not_found;
bin=PyList_GET_ITEM(LIST(bins), c);
Py_INCREF(bin);
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(self);
if(bin->ob_type != typ)
{
if(PyTuple_Check(bin) &&
PyString_Check((key=PyTuple_GET_ITEM(bin,0))) &&
strcmp(word,PyString_AS_STRING(STRING(key)))==0
)
ASSIGN(bin,PySequence_GetItem(bin,1));
else
ASSIGN(bin,NotFoundError(oword));
return bin;
}
self=(TrieObject *)bin;
PER_USE_OR_RETURN(self, NULL);
}
if(! self->value)
{
Py_DECREF(self);
return PER_RETURN(self, NotFoundError(oword));
}
bin=self->value;
Py_INCREF(bin);
Py_DECREF(self);
return PER_RETURN(self, bin);
not_found:
PER_ALLOW_DEACTIVATION(self);
Py_DECREF(self);
return NotFoundError(oword);
}
static int
Trie_cset(TrieObject *self, char *word, PyObject *v, PyObject *oword)
{
PyObject *bin=0;
int c, r, max;
#ifdef PERSISTENT
int ch=0;
#endif
PER_USE_OR_RETURN(self, -1);
c=*word++;
if(! c)
{
if(!v && !self->value)
{
NotFoundError(oword);
goto err;
}
Py_XINCREF(v);
ASSIGN(self->value, v);
#ifdef PERSISTENT
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
#endif
return 0;
}
if(!v &&
(!self->bins || c < self->min || c-self->min >= PyList_SIZE(self->bins))
)
{
NotFoundError(oword);
goto err;
}
if(! self->bins)
{
UNLESS(self->bins=PyList_New(1)) goto err;
self->min=c;
#ifdef PERSISTENT
ch=1;
#endif
}
else if(c < self->min)
while(c < self->min)
{
if(PyList_Insert(self->bins,0,Py_None) < 0) goto err;
self->min--;
#ifdef PERSISTENT
ch=1;
#endif
}
else
{
max=PyList_SIZE(self->bins)-1+self->min;
if(c > max)
while(c > max)
{
if(PyList_Append(self->bins,Py_None) < 0) goto err;
max++;
#ifdef PERSISTENT
ch=1;
#endif
}
}
c-=self->min;
bin=PyList_GET_ITEM(LIST(self->bins), c);
if(!bin || bin->ob_type != self->ob_type)
{
PyObject *key;
if(!v)
if(bin && PyTuple_Check(bin) && (key=PyTuple_GET_ITEM(bin,0)) &&
PyString_Check(key) &&
strcmp(word,PyString_AS_STRING(STRING(key))) == 0
)
{
Py_INCREF(Py_None);
bin=Py_None;
}
else
{
NotFoundError(oword);
goto err;
}
else
{
if(bin && PyTuple_Check(bin) && (key=PyTuple_GET_ITEM(bin,0)) &&
PyString_Check(key) &&
strcmp(word,PyString_AS_STRING(STRING(key))) != 0
)
{
PyObject *o;
o=PyTuple_GET_ITEM(bin,1);
UNLESS(bin=PyObject_GetAttr(PyOb(self),py___class__)) goto err;
UNLESS_ASSIGN(bin,PyObject_CallObject(bin,NULL)) goto err;
if(Trie_cset((TrieObject*)bin,
PyString_AS_STRING(STRING(key)),o, oword) < 0 ||
Trie_cset((TrieObject*)bin,word,v,oword) < 0
) goto err;
}
else
UNLESS(bin=Py_BuildValue("sO",word,v)) goto err;
}
r=PyList_SetItem(self->bins, c, bin);
#ifdef PERSISTENT
if(PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
#endif
return r;
}
r=Trie_cset((TrieObject*)bin,word,v,oword);
#ifdef PERSISTENT
if(ch && PER_CHANGED(self) < 0) goto err;
PER_ALLOW_DEACTIVATION(self);
#endif
return r;
err:
Py_XDECREF(bin);
PER_ALLOW_DEACTIVATION(self);
return -1;
}
static int
Trie_length(TrieObject *self)
{
int i, li, l=0;
PyObject *bin;
PER_USE_OR_RETURN(self, -1);
if(self->bins)
for(i=PyList_SIZE(self->bins); --i >= 0; )
{
bin=PyList_GET_ITEM(LIST(self->bins), i);
if(bin->ob_type==self->ob_type)
{
li=Trie_length((TrieObject*)bin);
if(li < 0) return PER_INT_RETURN(self, li);
l+=li;
}
else if(PyTuple_Check(bin)) l++;
}
if(self->value) l++;
return PER_INT_RETURN(self, l);
}
static PyObject *
Trie_subscript(TrieObject *self, PyObject *key)
{
char *word;
if(PyString_Check(key))
{
UNLESS(word=PyString_AsString(key)) return NULL;
return Trie_cget(self,word,key);
}
PyErr_SetString(PyExc_TypeError, "Only string keys are allowed for tries.");
return NULL;
}
static int
Trie_ass_sub(TrieObject *self, PyObject *key, PyObject *v)
{
char *word;
if(PyString_Check(key))
{
UNLESS(word=PyString_AsString(key)) return -1;
return Trie_cset((TrieObject*)self,word,v,key);
}
PyErr_SetString(PyExc_TypeError, "Only string keys are allowed for tries.");
return -1;
}
static PyMappingMethods Trie_as_mapping = {
(inquiry)Trie_length, /*mp_length*/
(binaryfunc)Trie_subscript, /*mp_subscript*/
(objobjargproc)Trie_ass_sub, /*mp_ass_subscript*/
};
static void
Trie_dealloc(TrieObject *self)
{
Py_XDECREF(self->bins);
Py_XDECREF(self->value);
PER_DEL(self);
PyMem_DEL(self);
/*printf("d");*/
}
static PyObject *
Trie_getattr(TrieObject *self, PyObject *name)
{
return Py_FindAttr(PyOb(self), name);
}
static PyObject *
Trie_repr(TrieObject *self)
{
PyObject *r;
UNLESS(r=iork(self,0)) return NULL;
ASSIGN(r,PyString_Format(py_Trief,r));
return r;
}
static int
Trie_compare(TrieObject *v, TrieObject *w)
{
if(v > w) return -1;
return w > v;
}
static PyExtensionClass TrieType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Trie", /*tp_name*/
sizeof(TrieObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Trie_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*obsolete tp_getattr*/
(setattrfunc)0, /*obsolete tp_setattr*/
(cmpfunc)Trie_compare, /*tp_compare*/
(reprfunc)Trie_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&Trie_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)Trie_getattr, /*tp_getattro*/
0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"",
METHOD_CHAIN(Trie_methods),
};
/* End of code for Trie objects */
/* -------------------------------------------------------- */
/* List of methods defined in the module */
static PyObject *
spam(PyObject *self, PyObject *args)
{
PyObject *d, *v;
int i,s,j;
d=PySequence_GetItem(args,0);
s=PyTuple_Size(args);
for(j=10000; --j >= 0; )
for(i=s; --i > 0; )
{
v=PyObject_GetItem(d,PyTuple_GET_ITEM(args,i));
Py_XDECREF(v);
}
return d;
}
static struct PyMethodDef Triem_methods[] = {
{"spam", (PyCFunction)spam, 1, ""},
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
/* Initialization function for the module (*must* be called initTrie) */
void
initTrie()
{
PyObject *m, *d;
char *rev="$Revision: 1.13 $";
UNLESS(ExtensionClassImported) return;
#ifdef PERSISTENT
if(cPersistenceCAPI=PyCObject_Import("cPersistence","CAPI"))
{
static PyMethodChain m;
m.methods=TrieType.methods.methods;
TrieType.methods.methods=cPersistenceCAPI->methods->methods;
TrieType.methods.link=&m;
TrieType.tp_getattro=cPersistenceCAPI->getattro;
TrieType.tp_setattro=cPersistenceCAPI->setattro;
}
else return;
#endif
/* Create the module and add the functions */
m = Py_InitModule4("Trie", Triem_methods,
Trie_module_documentation,
PyOb(NULL),PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyExtensionClass_Export(d, "Trie", TrieType);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
py___class__=PyString_FromString("__class__");
py_Trief=PyString_FromString("Trie(%s)");
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module Trie");
}
/*****************************************************************************
Revision Log:
$Log: Trie.c,v $
Revision 1.13 1997/09/10 17:27:14 jim
Fixed doc string.
Revision 1.12 1997/07/18 14:43:24 jim
Added cPersistent, PER_DEL invocation to destructor.
Fixed memory leaks in cset.
Revision 1.11 1997/07/17 14:50:57 jim
Got rid of some unreferenced vars.
Revision 1.10 1997/06/06 19:36:36 jim
Fixed major bug in (de)activation control logic.
Revision 1.9 1997/05/19 17:49:35 jim
Added logic to disable deactivation during methods. This sort of
logic will be needed for any C-based persistent object.
Revision 1.8 1997/05/08 21:09:49 jim
Added clear method.
Revision 1.7 1997/04/22 00:13:58 jim
Changed to use new cPersistent header.
Revision 1.6 1997/04/03 15:53:48 jim
Fixed bug in reinitialization code.
Revision 1.5 1997/03/20 19:30:04 jim
Major rewrite to use more efficient data structure. In particular,
try to avoid one-element tries by storing partial-key/value tuples
instead of sub-tries.
Revision 1.4 1997/03/17 23:23:09 jim
Fixed reinit bug.
Revision 1.3 1997/03/17 23:17:30 jim
Added reinit method. Need something better than this.
Fixed dealloc bug.
Revision 1.2 1997/03/17 21:29:39 jim
Moved external imports before module initialization to give
better error handling.
Revision 1.1 1997/03/14 23:20:28 jim
initial
*****************************************************************************/
#include "Python.h"
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
static PyObject *next_word();
static void WordSequence_reset();
static PyObject *default_wordletters;
static PyObject *string_lower;
typedef struct
{
PyObject_HEAD
PyObject *text, *synstop, *wordletters;
char *ctext, *here, *end, *cwordletters;
int index;
} WordSequence;
staticforward PyTypeObject WordSequenceType;
static WordSequence *
newWordSequence(PyObject *text, PyObject *synstop, PyObject *wordletters)
{
WordSequence *self;
PyObject *t;
PyObject *lower_text;
UNLESS(self = PyObject_NEW(WordSequence, &WordSequenceType))
{
return NULL;
}
self->synstop = synstop;
Py_XINCREF(self->synstop);
if (wordletters == NULL) wordletters=default_wordletters;
Py_INCREF(wordletters);
self->wordletters = wordletters;
self->cwordletters = PyString_AsString(self->wordletters);
UNLESS(t = PyTuple_New(1))
{
return NULL;
}
Py_INCREF(text);
PyTuple_SET_ITEM((PyTupleObject *)t, 0, text);
UNLESS(lower_text = PyObject_CallObject(string_lower, t))
{
Py_DECREF(t);
return NULL;
}
Py_DECREF(t);
self->text = lower_text;
self->ctext = self->here = PyString_AsString(lower_text);
self->end = self->here + PyString_Size(lower_text);
self->index = -1;
return self;
}
static void
WordSequence_dealloc(WordSequence *self)
{
Py_XDECREF(self->text);
Py_XDECREF(self->synstop);
Py_XDECREF(self->wordletters);
PyMem_DEL(self);
}
static int
WordSequence_length(WordSequence *self)
{
PyObject *res;
WordSequence_reset(self);
while (PyString_Check(res = next_word(self)))
{
Py_DECREF(res);
self->index++;
}
if (res == NULL)
{
return -1;
}
return self->index + 1;
}
static PyObject *
WordSequence_concat(WordSequence *self, PyObject *other)
{
PyErr_SetString(PyExc_TypeError, "Cannot concatenate WordSequences.");
return NULL;
}
static PyObject *
WordSequence_repeat(WordSequence *self, long n)
{
PyErr_SetString(PyExc_TypeError, "Cannot repeat WordSequences.");
return NULL;
}
static PyObject *
check_synstop(WordSequence *self, PyObject *word)
{
PyObject *value;
char *cword;
int len;
cword = PyString_AsString(word);
len = PyString_Size(word) - 1;
for (len = PyString_Size(word);
(--len >= 0) && !memchr("abcdefghijklmnopqrstuvwxyz", cword[len], 26);
);
if (len < 0)
{
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(word);
if (self->synstop == NULL) return word;
while ((value = PyObject_GetItem(self->synstop, word)) &&
PyString_Check(value))
{
ASSIGN(word,value);
}
if (value == NULL)
{
PyErr_Clear();
return word;
}
return value; /* Which must be None! */
}
#define MAX_WORD 256
static PyObject *
next_word(WordSequence *self)
{
char wbuf[MAX_WORD];
char *p, *end, *here, *b;
int size = PyString_Size(self->wordletters), i = 0;
PyObject *pyword, *res;
here=self->here;
end=self->end;
b=wbuf;
while (here < end)
{
/* skip hyphens */
if ((i > 0) && (*here == '-'))
{
while ((*++here <= ' ') && (here < end));
continue;
}
/* Check to see if this character is part of a word */
if (memchr(self->cwordletters, *here, size))
{
if(i++ < MAX_WORD) *b++ = *here;
}
else if (i != 0)
{
if(i >= MAX_WORD)
{
/* Ridiculously long word! */
i=0;
b=wbuf;
here++;
continue;
}
/* Check for and skip a phone number (I know it's lame :) */
if(i == 8 &&
wbuf[0] >= '0' && wbuf[0] <= '9' &&
wbuf[1] >= '0' && wbuf[1] <= '9' &&
wbuf[2] >= '0' && wbuf[2] <= '9' &&
wbuf[3] == '-' &&
wbuf[4] >= '0' && wbuf[4] <= '9' &&
wbuf[5] >= '0' && wbuf[5] <= '9' &&
wbuf[6] >= '0' && wbuf[6] <= '9' &&
wbuf[7] >= '0' && wbuf[7] <= '9')
{
i=0;
b=wbuf;
here++;
continue;
}
UNLESS(pyword = PyString_FromStringAndSize(wbuf, i))
{
self->here=here;
return NULL;
}
/* We've found the end of a word */
UNLESS(res = check_synstop(self, pyword))
{
self->here=here;
Py_DECREF(pyword);
return NULL;
}
if (res != Py_None)
{
self->here=here;
Py_DECREF(pyword);
return res;
}
/* The word is a stopword, so ignore it */
Py_DECREF(res);
Py_DECREF(pyword);
i = 0;
b=wbuf;
}
here++;
}
self->here=here;
/* We've reached the end of the string */
if (i == 0)
{
/* No words */
Py_INCREF(Py_None);
return Py_None;
}
UNLESS(pyword = PyString_FromStringAndSize(wbuf, i))
{
return NULL;
}
res = check_synstop(self, pyword);
Py_DECREF(pyword);
return res;
}
static void
WordSequence_reset(WordSequence *self)
{
self->here = self->ctext;
self->index = -1;
}
static PyObject *
WordSequence_item(WordSequence *self, int i)
{
PyObject *word = NULL;
if (i <= self->index)
{
WordSequence_reset(self);
}
while(self->index < i)
{
Py_XDECREF(word);
UNLESS(word = next_word(self))
{
return NULL;
}
if (word == Py_None)
{
Py_DECREF(word);
PyErr_SetString(PyExc_IndexError, "WordSequence index out of range");
return NULL;
}
self->index++;
}
return word;
}
static PyObject *
WordSequence_slice(WordSequence *self, int i, int j)
{
PyErr_SetString(PyExc_TypeError, "Cannot slice WordSequences.");
return NULL;
}
static PySequenceMethods WordSequence_as_sequence = {
(inquiry)WordSequence_length, /*sq_length*/
(binaryfunc)WordSequence_concat, /*sq_concat*/
(intargfunc)WordSequence_repeat, /*sq_repeat*/
(intargfunc)WordSequence_item, /*sq_item*/
(intintargfunc)WordSequence_slice, /*sq_slice*/
(intobjargproc)0, /*sq_ass_item*/
(intintobjargproc)0, /*sq_ass_slice*/
};
static int
next_word_pos(WordSequence *self, char **start, char **end)
{
int size = PyString_Size(self->wordletters), res = -1;
PyObject *pyword = NULL, *synstop = NULL;
char *tmp_ptr;
*start = *end = NULL;
while (self->here < self->end)
{
/* skip hyphens */
if ((*start != NULL) && (*self->here == '-'))
{
/* If this isn't a valid hyphenated region, we'll want
* to know where the end of the word is later.
*/
*end = self->here;
tmp_ptr = *end = self->here;
while ((*(++tmp_ptr) <= ' ') && (tmp_ptr < self->end));
if ((tmp_ptr < self->end) && (tmp_ptr - self->here) > 1)
{
self->here = tmp_ptr;
}
}
/* Check to see if this character is part of a word */
if (memchr(self->cwordletters, *self->here, size))
{
/* The character is part of a word. If we don't have
* a start position for the word, this must be the
* first character; save a pointer to it if so.
*/
if (*start == NULL)
{
*start = self->here;
}
if (*end != NULL)
{
/* This must be valid hyphenated word, so reset the end */
*end = NULL;
}
}
else if (*start != NULL)
{
/* We've found the end of a word */
/* See if we already have an end for the word */
if (*end == NULL)
{
*end = self->here;
}
UNLESS(pyword = PyString_FromStringAndSize(*start, *end - *start))
{
return -1;
}
UNLESS(synstop = check_synstop(self, pyword))
{
res = -1;
goto finally;
}
if (synstop != Py_None)
{
/* We've found a word. Set the end and return */
*end = self->here;
res = 1;
goto finally;
}
/* The word is a stopword, so ignore it */
*start = NULL;
Py_DECREF(synstop);
Py_DECREF(pyword);
}
self->here++;
}
/* We've reached the end of the string */
if (*start == NULL)
{
/* No words */
res = 0;
goto finally;
}
*end = self->here;
UNLESS(pyword = PyString_FromStringAndSize(*start, *end - *start))
{
goto finally;
}
UNLESS(synstop = check_synstop(self, pyword))
{
res = -1;
goto finally;
}
if (synstop != Py_None)
{
res = 1;
goto finally;
}
res = 0;
finally:
Py_XDECREF(pyword);
Py_XDECREF(synstop);
return res;
}
static PyObject *
WordSequence_pos(WordSequence *self, PyObject *args)
{
char *start, *end;
int res, i;
UNLESS(PyArg_Parse(args, "i", &i))
{
return NULL;
}
if (i <= self->index)
{
WordSequence_reset(self);
}
while(self->index < i)
{
res = next_word_pos(self, &start, &end);
if (res > 0)
{
self->index++;
continue;
}
if (res == 0)
{
PyErr_SetString(PyExc_IndexError, "WordSequence index out of range");
}
return NULL;
}
return Py_BuildValue("(ii)", start - self->ctext, end - self->ctext);
}
static struct PyMethodDef WordSequence_methods[] = {
{ "pos", (PyCFunction)WordSequence_pos, 0, "" },
{ NULL, NULL } /* sentinel */
};
static PyObject *
WordSequence_getattr(WordSequence *self, char *name)
{
return Py_FindMethod(WordSequence_methods, (PyObject *)self, name);
}
static char WordSequenceType__doc__[] = "";
static PyTypeObject WordSequenceType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"WordSequence", /*tp_name*/
sizeof(WordSequence), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)WordSequence_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)WordSequence_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
&WordSequence_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
WordSequenceType__doc__ /* Documentation string */
};
static PyObject *
get_WordSequence(PyObject *self, PyObject *args)
{
PyObject *text = NULL, *doc, *synstop = NULL, *wordletters = NULL,
*res = NULL;
UNLESS(PyArg_ParseTuple(args, "O|OO", &doc, &synstop, &wordletters))
{
goto finally;
}
UNLESS(text = PyObject_Str(doc))
{
goto finally;
}
if (wordletters && !PyString_Check(wordletters))
{
PyErr_SetString(PyExc_TypeError, "Thirst argument to WordSequence "
"must be string");
goto finally;
}
res = (PyObject *)newWordSequence(text, synstop, wordletters);
finally:
Py_XDECREF(text);
return res;
}
static struct PyMethodDef WordSequence_module_methods[] = {
{ "WordSequence", (PyCFunction)get_WordSequence, 1, "" },
{ NULL, NULL }
};
static char WordSequence_module_documentation[] =
"Parse source strings into sequences of words\n"
"\n"
"for use in an inverted index\n"
"\n"
"$Id: WordSequence.c,v 1.9 1997/07/31 22:31:58 jim Exp $\n"
;
void
initWordSequence()
{
PyObject *m, *string;
UNLESS(default_wordletters=
PyString_FromString("abcdefghijklmnopqrstuvwxyz0123456789/"))
{
return;
}
/* Create the module and add the functions */
m = Py_InitModule4("WordSequence", WordSequence_module_methods,
WordSequence_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
string = PyImport_ImportModule("string");
string_lower = PyObject_GetAttrString(string, "lower");
Py_INCREF(string_lower);
Py_DECREF(string);
if (PyErr_Occurred())
{
Py_FatalError("can't initialize module WordSequence");
}
}
/***********************************************************
Copyright
Copyright 1997 Digital Creations, L.L.C., 910 Princess Anne
Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
rights reserved.
******************************************************************/
static char intSet_module_documentation[] =
""
"\n$Id: intSet.c,v 1.5 1997/11/13 20:47:13 jim Exp $"
;
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <time.h>
#include "cPersistence.h"
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define RETURN_NONE Py_INCREF(Py_None); return Py_None
#define MIN_INTSET_ALLOC 8
#define INTSET_DATA_TYPE int
#define INTSET_DATA_FLAG "l"
typedef struct {
cPersistent_HEAD
int size, len;
INTSET_DATA_TYPE *data;
} intSet;
staticforward PyExtensionClass intSetType;
#define OBJECT(O) ((PyObject*)(O))
#define INTSET(O) ((intSet*)(O))
static PyObject *
_PER_RETURN(intSet *self, PyObject *r)
{
PER_ALLOW_DEACTIVATION(self);
return r;
}
static int
_PER_INT_RETURN(intSet *self, int r)
{
PER_ALLOW_DEACTIVATION(self);
return r;
}
/* We want to be sticky most of the time */
#define PER_RETURN(O,R) R
#define PER_INT_RETURN(O,R) R
#undef PER_ALLOW_DEACTIVATION
#define PER_ALLOW_DEACTIVATION(O)
static PyObject *
intSet_has_key(intSet *self, PyObject *args)
{
int min, max, i, l;
INTSET_DATA_TYPE k, key;
UNLESS(PyArg_ParseTuple(args,INTSET_DATA_FLAG,&key)) return NULL;
PER_USE_OR_RETURN(self, NULL);
for(min=0, max=self->len, i=max/2, l=max; i != l; l=i, i=(min+max)/2)
{
k=self->data[i];
if(k == key) return PER_RETURN(self, PyInt_FromLong(1));
if(k > key) max=i;
else min=i;
}
return PER_RETURN(self, PyInt_FromLong(0));
}
static int
intSet_grow(intSet *self, int l)
{
int g;
INTSET_DATA_TYPE *data;
if(self->data)
{
g=self->size*2;
if(g < l) g=l;
UNLESS(data=realloc(self->data, sizeof(INTSET_DATA_TYPE)*g))
{
PyErr_NoMemory();
return -1;
}
self->data=data;
self->size=g;
}
else
{
g=l < MIN_INTSET_ALLOC ? MIN_INTSET_ALLOC : l;
UNLESS(self->data=malloc(sizeof(INTSET_DATA_TYPE)*g))
{
PyErr_NoMemory();
return -1;
}
self->size=g;
}
return 0;
}
static INTSET_DATA_TYPE
intSet_modify(intSet *self, INTSET_DATA_TYPE ikey, int add)
{
int min, max, i, l;
INTSET_DATA_TYPE *data, k;
PER_USE_OR_RETURN(self, -1);
data=self->data;
for(min=0, max=self->len, i=max/2, l=max; i != l; l=i, i=(min+max)/2)
{
k=data[i];
if(k == ikey)
{
if(! add)
{
data+=i;
self->len--;
if(i < (self->len))
memmove(data, data+1, (self->len-i)*sizeof(INTSET_DATA_TYPE));
if(PER_CHANGED(self) < 0) return PER_INT_RETURN(self, -1);
}
return PER_INT_RETURN(self, 0);
}
if(k > ikey) max=i;
else min=i;
}
if(!add) return PER_INT_RETURN(self, 0);
if(self->len >= self->size && intSet_grow(self,self->len+1) < 0)
return PER_INT_RETURN(self, -1);
if(max != i) i++;
data=self->data+i;
if(self->len > i)
memmove(data+1,data,(self->len-i)*sizeof(INTSET_DATA_TYPE));
*data=ikey;
self->len++;
if(PER_CHANGED(self) < 0) return PER_INT_RETURN(self, -1);
return PER_INT_RETURN(self, ikey);
}
static PyObject *
intSet_insert(intSet *self, PyObject *args)
{
INTSET_DATA_TYPE key;
UNLESS(PyArg_ParseTuple(args,INTSET_DATA_FLAG,&key)) return NULL;
if(intSet_modify(self, key, 1) < 0) return NULL;
RETURN_NONE;
}
static PyObject *
intSet_remove(intSet *self, PyObject *args)
{
INTSET_DATA_TYPE key;
UNLESS(PyArg_ParseTuple(args,INTSET_DATA_FLAG,&key)) return NULL;
if(intSet_modify(self, key, 0) < 0) return NULL;
RETURN_NONE;
}
static PyObject *
intSet_clear(intSet *self, PyObject *args)
{
self->len=0;
if(PER_CHANGED(self) < 0) return PER_RETURN(self, NULL);
RETURN_NONE;
}
static PyObject *
intSet___getstate__(intSet *self, PyObject *args)
{
PyObject *r=0;
int i, l;
char *c;
INTSET_DATA_TYPE *d;
PER_USE_OR_RETURN(self, NULL);
l=self->len;
UNLESS(r=PyString_FromStringAndSize(NULL,l*4)) goto err;
UNLESS(c=PyString_AsString(r)) goto err;
d=self->data;
for(i=0; i < l; i++, *d++)
{
*c++ = (int)( *d & 0xff);
*c++ = (int)((*d >> 8) & 0xff);
*c++ = (int)((*d >> 16) & 0xff);
*c++ = (int)((*d >> 24) & 0xff);
}
return PER_RETURN(self, r);
err:
Py_DECREF(r);
return PER_RETURN(self, NULL);
}
static PyObject *
intSet___setstate__(intSet *self, PyObject *args)
{
PyObject *data;
int i, l, v;
char *c;
INTSET_DATA_TYPE k;
PER_PREVENT_DEACTIVATION(self);
UNLESS(PyArg_ParseTuple(args,"O",&data)) return PER_RETURN(self, NULL);
UNLESS(c=PyString_AsString(data)) return PER_RETURN(self, NULL);
if((l=PyString_Size(data)) < 0) return PER_RETURN(self, NULL);
l/=4;
intSet_clear(self, NULL);
if(l > self->size && intSet_grow(self,l) < 0)
return PER_RETURN(self, NULL);
PyErr_Clear();
for(i=0; i < l; i++)
{
v = ((int)(unsigned char)*c++) ;
v |= ((int)(unsigned char)*c++) << 8;
v |= ((int)(unsigned char)*c++) << 16;
v |= ((int)(unsigned char)*c++) << 24;
self->data[i]=v;
}
self->len=l;
Py_INCREF(Py_None);
return PER_RETURN(self, Py_None);
}
static PyObject *
intSet_set_operation(intSet *self, PyObject *other,
int cpysrc, int cpyboth, int cpyoth)
{
intSet *r=0, *o;
int i, l, io, lo, ir;
INTSET_DATA_TYPE *d, *od, v, vo, dif;
if(other->ob_type != self->ob_type)
{
PyErr_SetString(PyExc_TypeError,
"intSet set operations require same-type operands");
return NULL;
}
o=INTSET(other);
PER_USE_OR_RETURN(self, NULL);
PER_USE_OR_RETURN(other, NULL);
od=o->data;
d=self->data;
UNLESS(r=INTSET(PyObject_CallObject(OBJECT(self->ob_type), NULL)))
goto err;
for(i=0, l=self->len, io=0, lo=o->len; i < l && io < lo; )
{
v=d[i];
vo=od[io];
if(v < vo)
{
if(cpysrc)
{
if(r->len >= r->size && intSet_grow(r,0) < 0) goto err;
r->data[r->len]=v;
r->len++;
}
i++;
}
else if(v==vo)
{
if(cpyboth)
{
if(r->len >= r->size && intSet_grow(r,0) < 0) goto err;
r->data[r->len]=v;
r->len++;
}
i++;
io++;
}
else
{
if(cpyoth)
{
if(r->len >= r->size && intSet_grow(r,0) < 0) goto err;
r->data[r->len]=vo;
r->len++;
}
io++;
}
}
if(cpysrc && i < l)
{
l-=i;
if(r->len+l > r->size && intSet_grow(r,r->len+l) < 0) goto err;
memcpy(r->data+r->len, d+i, l*sizeof(INTSET_DATA_TYPE));
r->len += l;
}
else if(cpyoth && io < lo)
{
lo-=io;
if(r->len+lo > r->size && intSet_grow(r,r->len+lo) < 0) goto err;
memcpy(r->data+r->len, od+io, lo*sizeof(INTSET_DATA_TYPE));
r->len += lo;
}
return OBJECT(r);
err:
PER_ALLOW_DEACTIVATION(self);
PER_ALLOW_DEACTIVATION(o);
Py_DECREF(r);
return NULL;
}
static PyObject *
intSet_add(intSet *self, PyObject *other)
{
return intSet_set_operation(self,other,1,1,1);
}
static PyObject *
intSet_union(intSet *self, PyObject *args)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O",&other)) return NULL;
return intSet_set_operation(self,other,1,1,1);
}
static PyObject *
intSet_intersection(intSet *self, PyObject *args)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O",&other)) return NULL;
return intSet_set_operation(self,other,0,1,0);
}
static PyObject *
intSet_difference(intSet *self, PyObject *args)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O",&other)) return NULL;
return intSet_set_operation(self,other,1,0,0);
}
static PyObject *
intSet__p___reinit__(intSet *self, PyObject *args)
{
/* Note that this implementation is broken, in that it doesn't
account for subclass needs. */
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef intSet_methods[] = {
{"has_key", (PyCFunction)intSet_has_key, METH_VARARGS,
"has_key(id) -- Test whether the set has the given id"},
{"insert", (PyCFunction)intSet_insert, METH_VARARGS,
"insert(id,[ignored]) -- Add an id to the set"},
{"remove", (PyCFunction)intSet_remove, METH_VARARGS,
"remove(id) -- Remove an id from the set"},
{"clear", (PyCFunction)intSet_clear, METH_VARARGS,
"clear() -- Remove all of the ids from the set"},
{"union", (PyCFunction)intSet_union, METH_VARARGS,
"union(other) -- Return the union of the set with another set"},
{"intersection", (PyCFunction)intSet_intersection, METH_VARARGS,
"intersection(other) -- "
"Return the intersection of the set with another set"},
{"difference", (PyCFunction)intSet_difference, METH_VARARGS,
"difference(other) -- Return the difference of the set with another set"
},
{"__getstate__", (PyCFunction)intSet___getstate__, METH_VARARGS,
"__getstate__() -- get the persistent state"},
{"__setstate__", (PyCFunction)intSet___setstate__, METH_VARARGS,
"__setstate__() -- set the persistent state"},
{"_p___reinit__", (PyCFunction)intSet__p___reinit__, METH_VARARGS,
"_p___reinit__(oid,jar,copy) -- Reinitialize from a newly created copy"},
{NULL, NULL} /* sentinel */
};
static void
intSet_dealloc(intSet *self)
{
free(self->data);
PER_DEL(self);
PyMem_DEL(self);
}
static PyObject *
intSet_getattr(intSet *self, PyObject *name)
{
return Py_FindAttr((PyObject *)self, name);
}
/* Code to handle accessing intSet objects as sequence objects */
static int
intSet_length(intSet *self)
{
PER_USE_OR_RETURN(self,-1);
return PER_INT_RETURN(self,self->len);
}
static PyObject *
intSet_repeat(intSet *self, int n)
{
PyErr_SetString(PyExc_TypeError,
"intSet objects do not support repetition");
return NULL;
}
static PyObject *
intSet_item(intSet *self, int i)
{
PyObject *e;
PER_USE_OR_RETURN(self,NULL);
if(i >= 0 && i < self->len)
return PER_RETURN(self,PyInt_FromLong(self->data[i]));
UNLESS(e=PyInt_FromLong(i)) goto err;
PyErr_SetObject(PyExc_IndexError, e);
Py_DECREF(e);
err:
PER_ALLOW_DEACTIVATION(self)
return NULL;
}
static PyObject *
intSet_slice(intSet *self, int ilow, int ihigh)
{
PyErr_SetString(PyExc_TypeError,
"intSet objects do not support slicing");
return NULL;
}
static int
intSet_ass_item(intSet *self, int i, PyObject *v)
{
PyErr_SetString(PyExc_TypeError,
"intSet objects do not support item assignment");
return -1;
}
static int
intSet_ass_slice(PyListObject *self, int ilow, int ihigh, PyObject *v)
{
PyErr_SetString(PyExc_TypeError,
"intSet objects do not support slice assignment");
return -1;
}
static PySequenceMethods intSet_as_sequence = {
(inquiry)intSet_length, /*sq_length*/
(binaryfunc)intSet_add, /*sq_concat*/
(intargfunc)intSet_repeat, /*sq_repeat*/
(intargfunc)intSet_item, /*sq_item*/
(intintargfunc)intSet_slice, /*sq_slice*/
(intobjargproc)intSet_ass_item, /*sq_ass_item*/
(intintobjargproc)intSet_ass_slice, /*sq_ass_slice*/
};
static PyExtensionClass intSetType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"intSet", /*tp_name*/
sizeof(intSet), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)intSet_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*/
0, /*tp_as_number*/
&intSet_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)intSet_getattr, /*tp_getattro*/
0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"A set of integers",
METHOD_CHAIN(intSet_methods),
};
static struct PyMethodDef module_methods[] = {
{NULL, NULL} /* sentinel */
};
void
initintSet()
{
PyObject *m, *d;
char *rev="$Revision: 1.5 $";
UNLESS(ExtensionClassImported) return;
if(cPersistenceCAPI=PyCObject_Import("cPersistence","CAPI"))
{
static PyMethodChain m;
m.methods=intSetType.methods.methods;
intSetType.methods.methods=cPersistenceCAPI->methods->methods;
intSetType.methods.link=&m;
intSetType.tp_getattro=cPersistenceCAPI->getattro;
intSetType.tp_setattro=cPersistenceCAPI->setattro;
}
else return;
/* Create the module and add the functions */
m = Py_InitModule4("intSet", module_methods,
intSet_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"intSet",intSetType);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
#include "dcprotect.h"
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module intSet");
}
/**************************************************************************
Revision Log:
$Log: intSet.c,v $
Revision 1.5 1997/11/13 20:47:13 jim
Fixed some bad return values.
Revision 1.4 1997/11/13 20:38:39 jim
added dcprotect
Revision 1.3 1997/10/01 02:45:58 jim
Minor reformat.
Revision 1.2 1997/09/08 18:41:59 jim
Added logic to save data in binary form.
Revision 1.1 1997/08/05 14:55:22 jim
*** empty log message ***
**************************************************************************/
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