/***************************************************************************** Copyright (c) 2001 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 ****************************************************************************/ #define BUCKETTEMPLATE_C "$Id: BucketTemplate.c,v 1.22 2001/12/20 20:16:53 andreasjung Exp $\n" /* ** _bucket_get ** ** Get the bucket item with the matching key ** ** Arguments: self The bucket ** key The key to match against ** has_key Just return object "1" if key found, object "0" if not ** ** Returns: object matching object or 0/1 object */ static PyObject * _bucket_get(Bucket *self, PyObject *keyarg, int has_key) { int min, max, i, l, cmp, copied=1; PyObject *r; KEY_TYPE key; COPY_KEY_FROM_ARG(key, keyarg, copied); UNLESS (copied) 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) { cmp=TEST_KEY(self->keys[i], key); if (PyErr_Occurred()) goto err; if (cmp < 0) min=i; else if (cmp == 0) { if (has_key) r=PyInt_FromLong(has_key); else { COPY_VALUE_TO_OBJECT(r, self->values[i]); } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return r; } else max=i; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); if (has_key) return PyInt_FromLong(0); PyErr_SetObject(PyExc_KeyError, keyarg); err: return NULL; } static PyObject * bucket_getitem(Bucket *self, PyObject *key) { return _bucket_get(self, key, 0); } static int Bucket_grow(Bucket *self, int noval) { KEY_TYPE *keys; VALUE_TYPE *values; if (self->size) { UNLESS (keys=PyRealloc(self->keys, sizeof(KEY_TYPE)*self->size*2)) return -1; UNLESS (noval) { UNLESS (values=PyRealloc(self->values, sizeof(VALUE_TYPE)*self->size*2)) return -1; self->values=values; } self->keys=keys; self->size*=2; } else { UNLESS (self->keys=PyMalloc(sizeof(KEY_TYPE)*MIN_BUCKET_ALLOC)) return -1; UNLESS (noval || (self->values=PyMalloc(sizeof(VALUE_TYPE)*MIN_BUCKET_ALLOC)) ) return -1; self->size=MIN_BUCKET_ALLOC; } return 0; } /* ** _bucket_set ** ** Assign a value into a bucket ** ** Arguments: self The bucket ** key The key of the object to insert ** v The value of the object to insert ** unique Inserting a unique key ** ** Returns: -1 on error ** 0 on success with a replacement ** 1 on success with a new value (growth) */ static int _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, int unique, int noval, int *changed) { int min, max, i, l, cmp, copied=1; KEY_TYPE key; COPY_KEY_FROM_ARG(key, keyarg, copied); UNLESS(copied) return -1; 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->keys[i], key)) < 0) min=i; else if (cmp==0) { if (v) /* Assign value to key */ { if (! unique && ! noval && self->values) { VALUE_TYPE value; COPY_VALUE_FROM_ARG(value, v, copied); UNLESS(copied) return -1; #ifdef VALUE_SAME if (VALUE_SAME(self->values[i], value)) { /* short-circuit if no change */ PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 0; } #endif if (changed) *changed=1; DECREF_VALUE(self->values[i]); COPY_VALUE(self->values[i], value); INCREF_VALUE(self->values[i]); if (PER_CHANGED(self) < 0) goto err; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 0; } else /* There's no value so remove the item */ { self->len--; DECREF_KEY(self->keys[i]); if (i < self->len) memmove(self->keys+i, self->keys+i+1, sizeof(KEY_TYPE)*(self->len-i)); if (self->values && ! noval) { DECREF_VALUE(self->values[i]); if (i < self->len) memmove(self->values+i, self->values+i+1, sizeof(VALUE_TYPE)*(self->len-i)); } if (! self->len) { self->size=0; free(self->keys); self->keys=NULL; if (self->values) { free(self->values); self->values=NULL; } } if (PER_CHANGED(self) < 0) goto err; PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 1; } } else max=i; } if (!v) { PyErr_SetObject(PyExc_KeyError, keyarg); goto err; } if (self->len==self->size && Bucket_grow(self, noval) < 0) goto err; if (max != i) i++; if (self->len > i) { memmove(self->keys+i+1, self->keys+i, sizeof(KEY_TYPE)*(self->len-i)); UNLESS (noval) memmove(self->values+i+1, self->values+i, sizeof(VALUE_TYPE)*(self->len-i)); } COPY_KEY(self->keys[i], key); INCREF_KEY(self->keys[i]); UNLESS (noval) { COPY_VALUE_FROM_ARG(self->values[i], v, copied); UNLESS(copied) return -1; INCREF_VALUE(self->values[i]); } self->len++; if (PER_CHANGED(self) < 0) goto err; PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 1; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return -1; } /* ** bucket_setitem ** ** wrapper for _bucket_setitem (eliminates +1 return code) ** ** Arguments: self The bucket ** key The key to insert under ** v The value to insert ** ** Returns 0 on success ** -1 on failure */ static int bucket_setitem(Bucket *self, PyObject *key, PyObject *v) { if (_bucket_set(self, key, v, 0, 0, 0) < 0) return -1; return 0; } /** ** Mapping_update() ** ** Accepts a sequence of 2-tuples or any object with an items() ** method that returns a sequence of 2-tuples. ** */ static PyObject * Mapping_update(PyObject *self, PyObject *args) { PyObject *seq=0, *o, *t, *v, *tb, *k, *items = NULL; int i, ind; UNLESS(PyArg_ParseTuple(args, "|O:update", &seq)) return NULL; if (!seq) { Py_INCREF(Py_None); return Py_None; } if (!PySequence_Check(seq)) { items = PyObject_GetAttr(seq, items_str); UNLESS(items) return NULL; ASSIGN(items, PyObject_CallObject(items, NULL)); UNLESS(items) return NULL; /* items is DECREFed on exit, seq is not */ seq = items; } for (i=0; ; i++) { o = PySequence_GetItem(seq, i); UNLESS (o) { PyErr_Fetch(&t, &v, &tb); if (t != PyExc_IndexError) { PyErr_Restore(t, v, tb); goto err; } Py_XDECREF(t); Py_XDECREF(v); Py_XDECREF(tb); break; } ind = PyArg_ParseTuple(o, "OO;items must be 2-item tuples", &k, &v); if (ind) ind = PyObject_SetItem(self, k, v); else ind = -1; Py_DECREF(o); if (ind < 0) goto err; } Py_XDECREF(items); Py_INCREF(Py_None); return Py_None; err: Py_XDECREF(items); return NULL; } /* ** bucket_split ** ** Splits one bucket into two ** ** Arguments: self The bucket ** index the index of the key to split at (O.O.B use midpoint) ** next the new bucket to split into ** ** Returns: 0 on success ** -1 on failure */ static int bucket_split(Bucket *self, int index, Bucket *next) { int next_size; ASSERT(self->len > 1, "split of empty bucket", -1); if (index < 0 || index >= self->len) index=self->len/2; next_size=self->len-index; UNLESS (next->keys=PyMalloc(sizeof(KEY_TYPE)*next_size)) return -1; memcpy(next->keys, self->keys+index, sizeof(KEY_TYPE)*next_size); if (self->values) { UNLESS (next->values=PyMalloc(sizeof(VALUE_TYPE)*next_size)) return -1; memcpy(next->values, self->values+index, sizeof(VALUE_TYPE)*next_size); } next->size = next_size; next->len= next_size; self->len=index; next->next = self->next; Py_INCREF(next); self->next = next; PER_CHANGED(self); return 0; } static int Bucket_nextBucket(Bucket *self, Bucket **r) { PER_USE_OR_RETURN(self, -1); *r=self->next; Py_XINCREF(*r); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 0; } static int Bucket_deleteNextBucket(Bucket *self) { PER_USE_OR_RETURN(self, -1); if (self->next) { Bucket *n; if (Bucket_nextBucket(self->next, &n) < 0) goto err; ASSIGNB(self->next, n); PER_CHANGED(self); } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 0; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return -1; } /* Bucket_findRangeEnd -- Find the index of a range endpoint (possibly) contained in a bucket. Arguments: self The bucket key the key to match against low end flag offset The output offset If low, return bucket and index of the smallest item >= key, otherwise return bucket and index of the largest item <= key. Return: 0 -- Not found, 1 -- found, -1 -- error. */ static int Bucket_findRangeEnd(Bucket *self, PyObject *keyarg, int low, int *offset) { int min, max, i, l, cmp, copied=1; KEY_TYPE key; COPY_KEY_FROM_ARG(key, keyarg, copied); UNLESS (copied) return -1; 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->keys[i], key); if (cmp < 0) min=i; else if (cmp == 0) { PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); *offset=i; return 1; } else max=i; } /* OK, no matches, pick max or min, depending on whether we want an upper or low end. */ if (low) { if (max == self->len) i=0; else { i=1; *offset=max; } } else { if (max == 0) i=0; else { i=1; *offset=min; } } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return i; } static PyObject * Bucket_maxminKey(Bucket *self, PyObject *args, int min) { PyObject *key=0; int rc, offset; if (args && ! PyArg_ParseTuple(args, "|O", &key)) return NULL; PER_USE_OR_RETURN(self, NULL); UNLESS (self->len) goto empty; /* Find the low range */ if (key) { if ((rc = Bucket_findRangeEnd(self, key, min, &offset)) <= 0) { if (rc < 0) return NULL; goto empty; } } else if (min) offset = 0; else offset = self->len -1; COPY_KEY_TO_OBJECT(key, self->keys[offset]); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return key; empty: PyErr_SetString(PyExc_ValueError, "empty bucket"); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return NULL; } static PyObject * Bucket_minKey(Bucket *self, PyObject *args) { return Bucket_maxminKey(self, args, 1); } static PyObject * Bucket_maxKey(Bucket *self, PyObject *args) { return Bucket_maxminKey(self, args, 0); } static int Bucket_rangeSearch(Bucket *self, PyObject *args, int *low, int *high) { PyObject *f=0, *l=0; int rc; if (args && ! PyArg_ParseTuple(args,"|OO",&f, &l)) return -1; UNLESS (self->len) goto empty; /* Find the low range */ if (f && f != Py_None) { UNLESS (rc = Bucket_findRangeEnd(self, f, 1, low)) { if (rc < 0) return -1; goto empty; } } else *low = 0; /* Find the high range */ if (l && l != Py_None) { UNLESS (rc = Bucket_findRangeEnd(self, l, 0, high)) { if (rc < 0) return -1; goto empty; } } else *high=self->len - 1; return 0; empty: *low=0; *high=-1; return 0; } /* ** bucket_keys ** ** Generate a list of all keys in the bucket ** ** Arguments: self The Bucket ** args (unused) ** ** Returns: list of bucket keys */ static PyObject * bucket_keys(Bucket *self, PyObject *args) { PyObject *r=0, *key; int i, low, high; PER_USE_OR_RETURN(self, NULL); if (Bucket_rangeSearch(self, args, &low, &high) < 0) goto err; UNLESS (r=PyList_New(high-low+1)) goto err; for (i=low; i <= high; i++) { COPY_KEY_TO_OBJECT(key, self->keys[i]); if (PyList_SetItem(r, i-low , key) < 0) goto err; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return r; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_XDECREF(r); return NULL; } /* ** bucket_values ** ** Generate a list of all values in the bucket ** ** Arguments: self The Bucket ** args (unused) ** ** Returns list of values */ static PyObject * bucket_values(Bucket *self, PyObject *args) { PyObject *r=0, *v; int i, low, high; PER_USE_OR_RETURN(self, NULL); if (Bucket_rangeSearch(self, args, &low, &high) < 0) goto err; UNLESS (r=PyList_New(high-low+1)) goto err; for (i=low; i <= high; i++) { COPY_VALUE_TO_OBJECT(v, self->values[i]); UNLESS (v) goto err; if (PyList_SetItem(r, i-low, v) < 0) goto err; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return r; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_XDECREF(r); return NULL; } /* ** bucket_items ** ** Returns a list of all items in a bucket ** ** Arguments: self The Bucket ** args (unused) ** ** Returns: list of all items in the bucket */ static PyObject * bucket_items(Bucket *self, PyObject *args) { PyObject *r=0, *o=0, *item=0; int i, low, high; PER_USE_OR_RETURN(self, NULL); if (Bucket_rangeSearch(self, args, &low, &high) < 0) goto err; UNLESS (r=PyList_New(high-low+1)) goto err; for (i=low; i <= high; i++) { UNLESS (item = PyTuple_New(2)) goto err; COPY_KEY_TO_OBJECT(o, self->keys[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(item, 0, o); COPY_VALUE_TO_OBJECT(o, self->values[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(item, 1, o); if (PyList_SetItem(r, i, item) < 0) goto err; item = 0; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return r; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_XDECREF(r); Py_XDECREF(item); return NULL; } static PyObject * bucket_byValue(Bucket *self, PyObject *args) { PyObject *r=0, *o=0, *item=0, *omin; VALUE_TYPE min; VALUE_TYPE v; int i, l, copied=1; PER_USE_OR_RETURN(self, NULL); UNLESS (PyArg_ParseTuple(args, "O", &omin)) return NULL; COPY_VALUE_FROM_ARG(min, omin, copied); UNLESS(copied) return NULL; for (i=0, l=0; i < self->len; i++) if (TEST_VALUE(self->values[i], min) >= 0) l++; UNLESS (r=PyList_New(l)) goto err; for (i=0, l=0; i < self->len; i++) { if (TEST_VALUE(self->values[i], min) < 0) continue; UNLESS (item = PyTuple_New(2)) goto err; COPY_KEY_TO_OBJECT(o, self->keys[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(item, 1, o); COPY_VALUE(v, self->values[i]); NORMALIZE_VALUE(v, min); COPY_VALUE_TO_OBJECT(o, v); DECREF_VALUE(v); UNLESS (o) goto err; PyTuple_SET_ITEM(item, 0, o); if (PyList_SetItem(r, l, item) < 0) goto err; l++; item = 0; } item=PyObject_GetAttr(r,sort_str); UNLESS (item) goto err; ASSIGN(item, PyObject_CallObject(item, NULL)); UNLESS (item) goto err; ASSIGN(item, PyObject_GetAttr(r, reverse_str)); UNLESS (item) goto err; ASSIGN(item, PyObject_CallObject(item, NULL)); UNLESS (item) goto err; Py_DECREF(item); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return r; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_XDECREF(r); Py_XDECREF(item); return NULL; } static int _bucket_clear(Bucket *self) { int i; if (self->next) { Py_DECREF(self->next); self->next=0; } for (i=self->len; --i >= 0; ) { DECREF_KEY(self->keys[i]); if (self->values) { DECREF_VALUE(self->values[i]); } } self->len=0; if (self->values) { free(self->values); self->values=0; } if (self->keys) { free(self->keys); self->keys=0; } self->size=0; return 0; } #ifdef PERSISTENT static PyObject * bucket__p_deactivate(Bucket *self, PyObject *args) { if (self->state==cPersistent_UPTODATE_STATE && self->jar) { if (_bucket_clear(self) < 0) return NULL; self->state=cPersistent_GHOST_STATE; } Py_INCREF(Py_None); return Py_None; } #endif static PyObject * bucket_clear(Bucket *self, PyObject *args) { PER_USE_OR_RETURN(self, NULL); if (self->len) { if (_bucket_clear(self) < 0) return NULL; if (PER_CHANGED(self) < 0) goto err; } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_INCREF(Py_None); return Py_None; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return NULL; } static PyObject * bucket_getstate(Bucket *self, PyObject *args) { PyObject *o=0, *items=0; int i, len, l; if (args && ! PyArg_ParseTuple(args, "")) return NULL; PER_USE_OR_RETURN(self, NULL); len=self->len; if (self->values) { /* Bucket */ UNLESS (items=PyTuple_New(len*2)) goto err; for (i=0, l=0; i < len; i++) { COPY_KEY_TO_OBJECT(o, self->keys[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(items, l, o); l++; COPY_VALUE_TO_OBJECT(o, self->values[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(items, l, o); l++; } } else { /* Set */ UNLESS (items=PyTuple_New(len)) goto err; for (i=0; i < len; i++) { COPY_KEY_TO_OBJECT(o, self->keys[i]); UNLESS (o) goto err; PyTuple_SET_ITEM(items, i, o); } } if (self->next) ASSIGN(items, Py_BuildValue("OO", items, self->next)); else ASSIGN(items, Py_BuildValue("(O)", items)); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return items; err: PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); Py_XDECREF(items); return NULL; } static int _bucket_setstate(Bucket *self, PyObject *args) { PyObject *k, *v, *items; Bucket *next=0; int i, l, len, copied=1; KEY_TYPE *keys; VALUE_TYPE *values; UNLESS (PyArg_ParseTuple(args, "O|O", &items, &next)) return -1; if ((len=PyTuple_Size(items)) < 0) return -1; len /= 2; for (i=self->len; --i >= 0; ) { DECREF_KEY(self->keys[i]); DECREF_VALUE(self->values[i]); } self->len=0; if (self->next) { Py_DECREF(self->next); self->next=0; } if (len > self->size) { UNLESS (keys=PyRealloc(self->keys, sizeof(KEY_TYPE)*len)) return -1; UNLESS (values=PyRealloc(self->values, sizeof(VALUE_TYPE)*len)) return -1; self->keys=keys; self->values=values; self->size=len; } for (i=0, l=0; i<len; i++) { k=PyTuple_GET_ITEM(items, l); l++; v=PyTuple_GET_ITEM(items, l); l++; COPY_KEY_FROM_ARG(self->keys[i], k, copied); UNLESS (copied) return -1; COPY_VALUE_FROM_ARG(self->values[i], v, copied); UNLESS (copied) return -1; INCREF_KEY(self->keys[i]); INCREF_VALUE(self->values[i]); } self->len=len; if (next) { self->next=next; Py_INCREF(next); } PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); return 0; } static PyObject * bucket_setstate(Bucket *self, PyObject *args) { int r; UNLESS (PyArg_ParseTuple(args, "O", &args)) return NULL; PER_PREVENT_DEACTIVATION(self); r=_bucket_setstate(self, args); PER_ALLOW_DEACTIVATION(self); PER_ACCESSED(self); if (r < 0) return NULL; Py_INCREF(Py_None); return Py_None; } /* ** bucket_has_key ** */ 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); } /* ** bucket_getm ** */ static PyObject * bucket_getm(Bucket *self, PyObject *args) { PyObject *key, *d=Py_None, *r; UNLESS (PyArg_ParseTuple(args, "O|O", &key, &d)) return NULL; if ((r=_bucket_get(self, key, 0))) return r; UNLESS (PyErr_ExceptionMatches(PyExc_KeyError)) return NULL; PyErr_Clear(); Py_INCREF(d); return d; } #ifdef PERSISTENT static PyObject *merge_error(int p1, int p2, int p3, int reason); static PyObject *bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3); static PyObject * _bucket__p_resolveConflict(PyObject *ob_type, PyObject *s[3]) { PyObject *r=0, *a; Bucket *b[3]; int i; for (i=0; i < 3; i++) { if ((b[i]=(Bucket*)PyObject_CallObject(OBJECT(ob_type), NULL))) { if ((s[i] == Py_None)) /* None is equivalent to empty, for BTrees */ continue; ASSIGN(r, PyObject_GetAttr(OBJECT(b[i]), __setstate___str)); if ((a=PyTuple_New(1))) { if (r) { PyTuple_SET_ITEM(a, 0, s[i]); Py_INCREF(s[i]); ASSIGN(r, PyObject_CallObject(r, a)); } Py_DECREF(a); if (r) continue; } } Py_XDECREF(r); while (--i >= 0) { Py_DECREF(b[i]); } return NULL; } Py_DECREF(r); r=NULL; if (b[0]->next != b[1]->next || b[0]->next != b[2]->next) { merge_error(-1, -1, -1, -1); goto err; } r=bucket_merge(b[0], b[1], b[2]); err: Py_DECREF(b[0]); Py_DECREF(b[1]); Py_DECREF(b[2]); if (r == NULL) { PyObject *error; PyObject *value; PyObject *traceback; PyErr_Fetch(&error, &value, &traceback); Py_INCREF(ConflictError); Py_XDECREF(error); PyErr_Restore(ConflictError, value, traceback); } return r; } static PyObject * bucket__p_resolveConflict(Bucket *self, PyObject *args) { PyObject *s[3]; UNLESS(PyArg_ParseTuple(args, "OOO", &s[0], &s[1], &s[2])) return NULL; return _bucket__p_resolveConflict(OBJECT(self->ob_type), s); } #endif 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([min, max]) -- Return the keys"}, {"has_key", (PyCFunction) bucket_has_key, METH_VARARGS, "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"}, {"update", (PyCFunction) Mapping_update, METH_VARARGS, "update(collection) -- Add the items from the given collection"}, {"__init__", (PyCFunction) Mapping_update, METH_VARARGS, "__init__(collection) -- Initialize with items from the given collection"}, {"maxKey", (PyCFunction) Bucket_maxKey, METH_VARARGS, "maxKey([key]) -- Fine the maximum key\n\n" "If an argument is given, find the maximum <= the argument"}, {"minKey", (PyCFunction) Bucket_minKey, METH_VARARGS, "minKey([key]) -- Fine the minimum key\n\n" "If an argument is given, find the minimum >= the argument"}, {"values", (PyCFunction) bucket_values, METH_VARARGS, "values([min, max]) -- Return the values"}, {"items", (PyCFunction) bucket_items, METH_VARARGS, "items([min, max])) -- Return the items"}, {"byValue", (PyCFunction) bucket_byValue, METH_VARARGS, "byValue(min) -- " "Return value-keys with values >= min and reverse sorted by values" }, {"get", (PyCFunction) bucket_getm, METH_VARARGS, "get(key[,default]) -- Look up a value\n\n" "Return the default (or None) if the key is not found." }, #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() -- Reinitialize from a newly created copy"}, #endif {NULL, NULL} /* sentinel */ }; static void Bucket_dealloc(Bucket *self) { _bucket_clear(self); PER_DEL(self); Py_DECREF(self->ob_type); 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); PER_ACCESSED(self); return r; } static PyMappingMethods Bucket_as_mapping = { (inquiry)Bucket_length, /*mp_length*/ (binaryfunc)bucket_getitem, /*mp_subscript*/ (objobjargproc)bucket_setitem, /*mp_ass_subscript*/ }; static PyObject * bucket_repr(Bucket *self) { static PyObject *format; PyObject *r, *t; UNLESS (format) UNLESS (format=PyString_FromString(MOD_NAME_PREFIX "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*/ MOD_NAME_PREFIX "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), EXTENSIONCLASS_BASICNEW_FLAG #ifdef PERSISTENT | PERSISTENT_TYPE_FLAG #endif | EXTENSIONCLASS_NOINSTDICT_FLAG, }; static int nextBucket(SetIteration *i) { if (i->position >= 0) { UNLESS(PER_USE(BUCKET(i->set))) return -1; if (i->position) { DECREF_KEY(i->key); DECREF_VALUE(i->value); } if (i->position < BUCKET(i->set)->len) { COPY_KEY(i->key, BUCKET(i->set)->keys[i->position]); INCREF_KEY(i->key); COPY_VALUE(i->value, BUCKET(i->set)->values[i->position]); INCREF_VALUE(i->value); i->position ++; } else { i->position = -1; PER_ACCESSED(BUCKET(i->set)); } PER_ALLOW_DEACTIVATION(BUCKET(i->set)); } return 0; }