Exemplo n.º 1
0
/*
** _bucket_get
**
** Search a bucket for a given key.
**
** Arguments
**     self	The bucket
**     keyarg	The key to look for
**     has_key	Boolean; if true, return a true/false result; else return
**              the value associated with the key.
**
** Return
**     If has_key:
**         Returns the Python int 0 if the key is absent, else returns
**         has_key itself as a Python int.  A BTree caller generally passes
**         the depth of the bucket for has_key, so a true result returns
**         the bucket depth then.
**         Note that has_key should be tree when searching set buckets.
**     If not has_key:
**         If the key is present, returns the associated value, and the
**         caller owns the reference.  Else returns NULL and sets KeyError.
**     Whether or not has_key:
**         If a comparison sets an exception, returns NULL.
*/
static PyObject *
_bucket_get(Bucket *self, PyObject *keyarg, int has_key)
{
    int i, cmp;
    KEY_TYPE key;
    PyObject *r = NULL;
    int copied = 1;

    COPY_KEY_FROM_ARG(key, keyarg, copied);
    UNLESS (copied) return NULL;

    PER_USE_OR_RETURN(self, NULL);

    BUCKET_SEARCH(i, cmp, self, key, goto Done);
    if (has_key)
    	r = PyInt_FromLong(cmp ? 0 : has_key);
    else {
        if (cmp == 0) {
            COPY_VALUE_TO_OBJECT(r, self->values[i]);
        }
        else
            PyErr_SetObject(PyExc_KeyError, keyarg);
    }

Done:
  PER_ALLOW_DEACTIVATION(self);
  PER_ACCESSED(self);
  return r;
}
Exemplo n.º 2
0
static PyObject *
bucket_toString(PyObject *oself)
{
  Bucket *self = (Bucket *)oself;
  PyObject *items = NULL;
  int len;

  PER_USE_OR_RETURN(self, NULL);

  len = self->len;

  items = PyString_FromStringAndSize(NULL, len*8);
  if (items == NULL)
    goto err;
  memcpy(PyString_AS_STRING(items),       self->keys,   len*2);
  memcpy(PyString_AS_STRING(items)+len*2, self->values, len*6);
  
  PER_UNUSE(self);
  return items;
  
 err:
  PER_UNUSE(self);
  Py_XDECREF(items);
  return NULL;
}
Exemplo n.º 3
0
/* Search for the bucket immediately preceding *current, in the bucket chain
 * starting at first.  current, *current and first must not be NULL.
 *
 * Return:
 *     1    *current holds the correct bucket; this is a borrowed reference
 *     0    no such bucket exists; *current unaltered
 *    -1    error; *current unaltered
 */
static int
PreviousBucket(Bucket **current, Bucket *first)
{
    Bucket *trailing = NULL;    /* first travels; trailing follows it */
    int result = 0;

    assert(current && *current && first);
    if (first == *current)
        return 0;

    do {
        trailing = first;
	PER_USE_OR_RETURN(first, -1);
        first = first->next;

    	((trailing)->state==cPersistent_STICKY_STATE
     	&&
     	((trailing)->state=cPersistent_UPTODATE_STATE));

    	PER_ACCESSED(trailing);

	if (first == *current) {
	    *current = trailing;
	    result = 1;
	    break;
	}
    } while (first);

    return result;
}
/* Search for the bucket immediately preceding *current, in the bucket chain
 * starting at first.  current, *current and first must not be NULL.
 *
 * Return:
 *     1    *current holds the correct bucket; this is a borrowed reference
 *     0    no such bucket exists; *current unaltered
 *    -1    error; *current unaltered
 */
static int
PreviousBucket(Bucket **current, Bucket *first)
{
    Bucket *trailing = NULL;    /* first travels; trailing follows it */
    int result = 0;

    assert(current && *current && first);
    if (first == *current)
        return 0;

    do {
        trailing = first;
	PER_USE_OR_RETURN(first, -1);
        first = first->next;
        PER_ALLOW_DEACTIVATION(trailing);
	PER_ACCESSED(trailing);

	if (first == *current) {
	    *current = trailing;
	    result = 1;
	    break;
	}
    } while (first);

    return result;
}
Exemplo n.º 5
0
static Py_ssize_t
BTreeItems_length_or_nonzero(BTreeItems *self, int nonzero)
{
    Py_ssize_t r;
    Bucket *b, *next;

    b = self->firstbucket;
    if (b == NULL)
	return 0;

    r = self->last + 1 - self->first;

    if (nonzero && r > 0)
	/* Short-circuit if all we care about is nonempty */
	return 1;

    if (b == self->lastbucket)
	return r;

    Py_INCREF(b);
    PER_USE_OR_RETURN(b, -1);
    while ((next = b->next)) {
	r += b->len;
	if (nonzero && r > 0)
	    /* Short-circuit if all we care about is nonempty */
	    break;

	if (next == self->lastbucket)
	    break; /* we already counted the last bucket */

	Py_INCREF(next);
	PER_UNUSE(b);
	Py_DECREF(b);
	b = next;
	PER_USE_OR_RETURN(b, -1);
    }
    PER_UNUSE(b);
    Py_DECREF(b);

    return r >= 0 ? r : 0;
}
Exemplo n.º 6
0
/*
** BTreeItems_item
**
** Arguments:	self	a BTreeItems structure
**		i	Which item to inspect
**
** Returns:	the BTreeItems_item_BTree of self->kind, i
**		(ie pulls the ith item out)
*/
static PyObject *
BTreeItems_item(BTreeItems *self, Py_ssize_t i)
{
    PyObject *result;

    if (BTreeItems_seek(self, i) < 0) return NULL;

    PER_USE_OR_RETURN(self->currentbucket, NULL);
    result = getBucketEntry(self->currentbucket, self->currentoffset,
                            self->kind);
    PER_UNUSE(self->currentbucket);
    return result;
}
Exemplo n.º 7
0
/*
** BTreeItems_seek
**
** Find the ith position in the BTreeItems.
**
** Arguments:  	self	The BTree
**		i	the index to seek to, in 0 .. len(self)-1, or in
**                      -len(self) .. -1, as for indexing a Python sequence.
**
**
** Returns 0 if successful, -1 on failure to seek (like out-of-bounds).
** Upon successful return, index i is at offset self->currentoffset in bucket
** self->currentbucket.
*/
static int
BTreeItems_seek(BTreeItems *self, Py_ssize_t i)
{
    int delta, pseudoindex, currentoffset;
    Bucket *b, *currentbucket;
    int error;

    pseudoindex = self->pseudoindex;
    currentoffset = self->currentoffset;
    currentbucket = self->currentbucket;
    if (currentbucket == NULL) goto no_match;

    delta = i - pseudoindex;
    while (delta > 0) {         /* move right */
        int max;
        /* Want to move right delta positions; the most we can move right in
         * this bucket is currentbucket->len - currentoffset - 1 positions.
         */
        PER_USE_OR_RETURN(currentbucket, -1);
        max = currentbucket->len - currentoffset - 1;
        b = currentbucket->next;
        PER_UNUSE(currentbucket);
        if (delta <= max) {
            currentoffset += delta;
            pseudoindex += delta;
            if (currentbucket == self->lastbucket
                && currentoffset > self->last) goto no_match;
            break;
        }
        /* Move to start of next bucket. */
        if (currentbucket == self->lastbucket || b == NULL) goto no_match;
        currentbucket = b;
        pseudoindex += max + 1;
        delta -= max + 1;
        currentoffset = 0;
    }
    while (delta < 0) {         /* move left */
        int status;
        /* Want to move left -delta positions; the most we can move left in
         * this bucket is currentoffset positions.
         */
        if ((-delta) <= currentoffset) {
            currentoffset += delta;
            pseudoindex += delta;
            if (currentbucket == self->firstbucket
                && currentoffset < self->first) goto no_match;
            break;
        }
        /* Move to end of previous bucket. */
        if (currentbucket == self->firstbucket) goto no_match;
        status = PreviousBucket(&currentbucket, self->firstbucket);
        if (status == 0)
            goto no_match;
        else if (status < 0)
            return -1;
        pseudoindex -= currentoffset + 1;
        delta += currentoffset + 1;
        PER_USE_OR_RETURN(currentbucket, -1);
        currentoffset = currentbucket->len - 1;
        PER_UNUSE(currentbucket);
    }

    assert(pseudoindex == i);

    /* Alas, the user may have mutated the bucket since the last time we
     * were called, and if they deleted stuff, we may be pointing into
     * trash memory now.
     */
    PER_USE_OR_RETURN(currentbucket, -1);
    error = currentoffset < 0 || currentoffset >= currentbucket->len;
    PER_UNUSE(currentbucket);
    if (error) {
	PyErr_SetString(PyExc_RuntimeError,
	                "the bucket being iterated changed size");
	return -1;
    }

    Py_INCREF(currentbucket);
    Py_DECREF(self->currentbucket);
    self->currentbucket = currentbucket;
    self->currentoffset = currentoffset;
    self->pseudoindex = pseudoindex;
    return 0;

no_match:
    IndexError(i);
    return -1;
}