Commit f3824a9e authored by Tim Peters's avatar Tim Peters

Reworked _bucket_set():

+ Documented the arguments.
+ Used BUCKET_SEARCH.
+ Vastly reduced nesting.
+ Changed the "*changed" argument to get set true whenever PER_CHANGED
  is called, i.e. whenever the bucket mutates.  The purpose of *changed
  wasn't documented, and its only use was in the BTree set routine, which
  is known to have at least one bug.  So it wasn't clear what the purpose
  of *changed was.  What it did do is get set true if and only if the
  key was found in the bucket and its value was replaced, and I couldn't
  imagine a plausible reason for why the BTree set routine could care
  about that alone (all other calls to _bucket_set pass NULL, so there
  were no other clues).
+ Fixed all places where error returns didn't finish the persistence
  dance.
parent 6413dc84
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
****************************************************************************/ ****************************************************************************/
#define BUCKETTEMPLATE_C "$Id: BucketTemplate.c,v 1.36 2002/06/08 19:46:18 tim_one Exp $\n" #define BUCKETTEMPLATE_C "$Id: BucketTemplate.c,v 1.37 2002/06/09 02:50:14 tim_one Exp $\n"
/* Use BUCKET_SEARCH to find the index at which a key belongs. /* Use BUCKET_SEARCH to find the index at which a key belongs.
* INDEX An int lvalue to hold the index i such that KEY belongs at * INDEX An int lvalue to hold the index i such that KEY belongs at
...@@ -168,144 +168,147 @@ Overflow: ...@@ -168,144 +168,147 @@ Overflow:
} }
/* /*
** _bucket_set ** _bucket_set: Assign a value to a key in a bucket, delete a key+value
** pair, or just insert a key.
** **
** Assign a value into a bucket ** Arguments
** ** self The bucket
** Arguments: self The bucket ** keyarg The key to look for
** key The key of the object to insert ** v The value to associate with key; NULL means delete the key.
** v The value of the object to insert ** If NULL, it's an error (KeyError) if the key isn't present.
** unique Inserting a unique key ** Note that if this is a set bucket, and you want to insert
** a new set element, v must be non-NULL although its exact
** value will be ignored. Passing Py_None is good for this.
** unique Boolean; when true, don't replace the value if the key is
** already present.
** noval Boolean; when true, operate on keys only (ignore values)
** changed ignored on input
** **
** Returns: -1 on error ** Return
** 0 on success with a replacement ** -1 on error
** 1 on success with a new value (growth) ** 0 on success and the # of bucket entries didn't change
** 1 on success and the # of bucket entries did change
** *changed If non-NULL, set to 1 on any mutation of the bucket.
*/ */
static int static int
_bucket_set(Bucket *self, PyObject *keyarg, PyObject *v, _bucket_set(Bucket *self, PyObject *keyarg, PyObject *v,
int unique, int noval, int *changed) int unique, int noval, int *changed)
{ {
int min, max, i, l, cmp, copied=1; int i, cmp;
KEY_TYPE key; KEY_TYPE key;
int result = -1; /* until proven innocent */
int copied = 1;
COPY_KEY_FROM_ARG(key, keyarg, copied); COPY_KEY_FROM_ARG(key, keyarg, copied);
UNLESS(copied) return -1; UNLESS(copied) return -1;
PER_USE_OR_RETURN(self, -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) BUCKET_SEARCH(i, cmp, self, key, goto Done);
{ if (cmp == 0) {
TEST_KEY_SET_OR(cmp, self->keys[i], key) goto err;
if (cmp < 0) min=i;
else if (cmp==0)
{
if (v) /* Assign value to key */
{
if (! unique && ! noval && self->values)
{
VALUE_TYPE value; VALUE_TYPE value;
/* The key exists, at index i. */
COPY_VALUE_FROM_ARG(value, v, copied); if (v) {
UNLESS(copied) return -1; /* The key exists at index i, and there's a new value.
* If unique, we're not supposed to replace it. If noval, or this
* is a set bucket (self->values is NULL), there's nothing to do.
*/
if (unique || noval || self->values == NULL) {
result = 0;
goto Done;
}
/* The key exists at index i, and we need to replace the value. */
COPY_VALUE_FROM_ARG(value, v, copied);
UNLESS(copied) goto Done;
#ifdef VALUE_SAME #ifdef VALUE_SAME
if (VALUE_SAME(self->values[i], value)) /* short-circuit if no change */
{ /* short-circuit if no change */ if (VALUE_SAME(self->values[i], value)) {
PER_ALLOW_DEACTIVATION(self); result = 0;
PER_ACCESSED(self); goto Done;
return 0;
} }
#endif #endif
if (changed) *changed=1; if (changed)
*changed = 1;
DECREF_VALUE(self->values[i]); DECREF_VALUE(self->values[i]);
COPY_VALUE(self->values[i], value); COPY_VALUE(self->values[i], value);
INCREF_VALUE(self->values[i]); INCREF_VALUE(self->values[i]);
if (PER_CHANGED(self) < 0) goto err; if (PER_CHANGED(self) >= 0)
result = 0;
goto Done;
} }
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
return 0;
}
else /* There's no value so remove the item */
{
self->len--;
/* The key exists at index i, and should be deleted. */
DECREF_KEY(self->keys[i]); DECREF_KEY(self->keys[i]);
self->len--;
if (i < self->len) if (i < self->len)
memmove(self->keys+i, self->keys+i+1, memmove(self->keys + i, self->keys + i+1,
sizeof(KEY_TYPE)*(self->len-i)); sizeof(KEY_TYPE)*(self->len - i));
if (self->values && ! noval) if (self->values) {
{
DECREF_VALUE(self->values[i]); DECREF_VALUE(self->values[i]);
if (i < self->len) if (i < self->len)
memmove(self->values+i, self->values+i+1, memmove(self->values + i, self->values + i+1,
sizeof(VALUE_TYPE)*(self->len-i)); sizeof(VALUE_TYPE)*(self->len - i));
} }
if (! self->len) if (! self->len) {
{ self->size = 0;
self->size=0;
free(self->keys); free(self->keys);
self->keys=NULL; self->keys = NULL;
if (self->values) if (self->values) {
{
free(self->values); free(self->values);
self->values=NULL; self->values = NULL;
} }
} }
if (PER_CHANGED(self) < 0) goto err; if (changed)
PER_ALLOW_DEACTIVATION(self); *changed = 1;
PER_ACCESSED(self); if (PER_CHANGED(self) >= 0)
return 1; result = 1;
} goto Done;
}
else max=i;
} }
if (!v) /* The key doesn't exist, and belongs at index i. */
{ if (!v) {
/* Can't delete a non-existent key. */
PyErr_SetObject(PyExc_KeyError, keyarg); PyErr_SetObject(PyExc_KeyError, keyarg);
goto err; goto Done;
} }
if (self->len==self->size && Bucket_grow(self, -1, noval) < 0) goto err; /* The key doesn't exist and should be inserted at index i. */
if (self->len == self->size && Bucket_grow(self, -1, noval) < 0)
goto Done;
if (max != i) i++; if (self->len > i) {
memmove(self->keys + i+1, self->keys + i,
if (self->len > i) sizeof(KEY_TYPE)*(self->len - i));
{ if (self->values) {
memmove(self->keys+i+1, self->keys+i, memmove(self->values + i+1, self->values + i,
sizeof(KEY_TYPE)*(self->len-i)); sizeof(VALUE_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); COPY_KEY(self->keys[i], key);
INCREF_KEY(self->keys[i]); INCREF_KEY(self->keys[i]);
UNLESS (noval) if (! noval) {
{
COPY_VALUE_FROM_ARG(self->values[i], v, copied); COPY_VALUE_FROM_ARG(self->values[i], v, copied);
UNLESS(copied) return -1; UNLESS(copied) return -1;
INCREF_VALUE(self->values[i]); INCREF_VALUE(self->values[i]);
} }
self->len++; self->len++;
if (changed)
*changed = 1;
if (PER_CHANGED(self) >= 0)
result = 1;
if (PER_CHANGED(self) < 0) goto err; Done:
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
return 1;
err:
PER_ALLOW_DEACTIVATION(self); PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self); PER_ACCESSED(self);
return -1; return result;
} }
/* /*
......
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