[asterisk-commits] rizzo: branch rizzo/astobj2 r47223 - in
/team/rizzo/astobj2: include/asterisk...
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Mon Nov 6 08:49:45 MST 2006
Author: rizzo
Date: Mon Nov 6 09:49:44 2006
New Revision: 47223
URL: http://svn.digium.com/view/asterisk?rev=47223&view=rev
Log:
improved method for iterators, and related documentation.
This works much better than the previous one.
Modified:
team/rizzo/astobj2/include/asterisk/astobj2.h
team/rizzo/astobj2/main/astobj2.c
Modified: team/rizzo/astobj2/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/include/asterisk/astobj2.h?rev=47223&r1=47222&r2=47223&view=diff
==============================================================================
--- team/rizzo/astobj2/include/asterisk/astobj2.h (original)
+++ team/rizzo/astobj2/include/asterisk/astobj2.h Mon Nov 6 09:49:44 2006
@@ -329,11 +329,9 @@
* We allocate space for a struct astobj_container, struct container
* and the buckets[] array.
*
- * \param astobj_hash_fn Pointer to a function computing a hash value.
- * \param astobj_cmp_fn Pointer to a function comparating key-value
+ * \param my_hash_fn Pointer to a function computing a hash value.
+ * \param my_cmp_fn Pointer to a function comparating key-value
* with a string. (can be NULL)
- * \param astobj_dump_fn Pointer to a function dumping the objects value.
- * used for debug. (can be NULL)
* \return A pointer to a struct container.
*
* destructor is set implicitly.
@@ -342,13 +340,7 @@
astobj2_hash_fn hash_fn, astobj2_callback_fn cmp_fn);
/*!
- * Check if a container is empty.
- *
- * This function return 0 if the container is empty
- * otherwise return a non zero value.
- *
- * \param c The container to investigate.
- * \return Zero if the container is empty.
+ * Returns the number of elements in a container.
*/
int astobj2_container_count(struct container *c);
@@ -474,18 +466,21 @@
*/
/*!
+ * You are not supposed to know the internals of an iterator!
* We would like the iterator to be opaque, unfortunately
* its size needs to be known if we want to store it around
* without too much trouble.
+ * It contains a pointer to the container, the bucket where the current
+ * object is, and the version number of the current object. How this is
+ * used, you will find in the implementation of astobj2_iterator_next()
+ * A freshly-initialized iterator has bucket=0, version = 0.
*/
struct astobj2_iterator {
struct container *c; /* the container */
int bucket; /* current bucket */
- int pos; /* current position in bucket */
- struct astobj2 *cur; /* current object, NULL at start */
+ uint version; /* container version when the object was created */
};
-
void astobj2_iterator_init(struct container *c, struct astobj2_iterator *i);
void *astobj2_iterator_next(struct astobj2_iterator *a);
Modified: team/rizzo/astobj2/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/astobj2.c?rev=47223&r1=47222&r2=47223&view=diff
==============================================================================
--- team/rizzo/astobj2/main/astobj2.c (original)
+++ team/rizzo/astobj2/main/astobj2.c Mon Nov 6 09:49:44 2006
@@ -155,11 +155,27 @@
struct bucket_list *tail;
};
+/*!
+ * A container; stores the hash and callback functions, information on
+ * the size, the hash bucket heads, and a version number, starting at 0
+ * (for a newly created, empty container)
+ * and incremented every time an object is inserted or deleted.
+ * The assumption is that an object is never moved in a container,
+ * but removed and readded with the new number.
+ * The version number is especially useful when implementing iterators.
+ * In fact, we can associate a unique, monotonically increasing number to
+ * each object, which means that, within an iterator, we can store the
+ * version number of the current object, and easily look for the next one,
+ * which is the next one in the list with a higher number.
+ * Since all objects have a version >0, we can use 0 as a marker for
+ * 'we need the first object in the bucket'.
+ */
struct container {
astobj2_hash_fn hash_fn;
astobj2_callback_fn cmp_fn;
int n_buckets;
int elements; /* number of elements in the container */
+ uint version; /* please read above */
struct bucket buckets[0]; /* variable size */
};
@@ -190,6 +206,7 @@
/* init */
c->elements = 0;
+ c->version = 1; /* 0 is a reserved value here */
c->n_buckets = n_buckets;
c->hash_fn = hash_fn ? hash_fn : hash_zero;
c->cmp_fn = cmp_fn;
@@ -212,6 +229,7 @@
*/
struct bucket_list {
struct bucket_list *next; /* pointer to next bucket_list */
+ uint version;
struct astobj2 *astobj; /* pointer to internal data */
};
@@ -234,6 +252,7 @@
p->next = NULL;
p->astobj = INTERNAL_OBJ(user_data);
+ p->version = ast_atomic_fetchadd_int(&c->version, 1);
if (c->buckets[i].head == NULL)
c->buckets[i].head = p;
else
@@ -262,6 +281,8 @@
{
// ast_verbose("unlinking %p from container\n", user_data);
astobj2_callback(c, OBJ_SINGLE | OBJ_UNLINK | OBJ_POINTER, match_by_addr, user_data);
+ /* the container has changed its content, so we update the version */
+ ast_atomic_fetchadd_int(&c->version, -1);
astobj2_ref(user_data, -1);
return NULL;
}
@@ -392,10 +413,9 @@
*/
void astobj2_iterator_init(struct container *c, struct astobj2_iterator *a)
{
+ a->c = c;
a->bucket = 0;
- a->pos = 0;
- a->c = c;
- a->cur = NULL;
+ a->version = 0;
}
/*
@@ -404,67 +424,31 @@
void * astobj2_iterator_next(struct astobj2_iterator *a)
{
int lim;
- struct bucket *bp;
-
- if (a->cur)
- astobj2_ref(EXTERNAL_OBJ(a->cur), -1);
- else { /* search from the beginning */
- a->bucket = 0;
- a->pos = -1;
- }
+ struct bucket_list *p = NULL;
astobj2_lock(a->c);
lim = a->c->n_buckets;
- bp = a->c->buckets;
-
- /* we browse the buckets array, moving to the next
+
+ /* Browse the buckets array, moving to the next
* buckets if we don't find the entry in the current one.
+ * Stop when we find an element with version number greater
+ * than the current one (we reset the version to 0 when we
+ * switch buckets).
*/
- for ( ; a->bucket < lim;
- /* move to next bucket */
- a->bucket++, a->pos = -1) {
- struct bucket_list *p = bp[a->bucket].head, *cand = NULL;
- int i;
-
- if (p == NULL) /* empty bucket */
- continue;
-
- if (a->pos == -1) { /* found at the beginning of the bucket */
- a->pos = 0;
- a->cur = p->astobj;
- break;
- }
-
- /* we browse the buckets list for the current object,
- * by address or by position.
- * When we find it, record it in cand.
- * The next element to return will be cand->next.
- */
- for (i = 0; p; i++, p = p->next) {
- if (p->astobj == a->cur) { /* found current element */
- a->pos = i; /* mark new position */
- cand = p;
- break;
- } else if (i == a->pos) { /* element not found, but this is a candidate */
- cand = p;
+ for (; a->bucket < lim; a->bucket++, a->version = 0) {
+ /* scan the current bucket */
+ for (p = a->c->buckets[a->bucket].head; p; p = p->next) {
+ if (p->version > a->version) { /* found */
+ a->version = p->version;
+ /* inc refcount of returned object */
+ astobj2_ref(EXTERNAL_OBJ(p->astobj), 1);
+ goto done;
}
}
- if (cand == NULL || cand->next == NULL) /* not found, try next bucket */
- continue;
- /* ok, what we want is at cand->next */
- a->pos++;
- a->cur = cand->next->astobj;
- break;
- }
-
- if (a->bucket == lim) { /* not found */
- astobj2_unlock(a->c);
- return NULL;
- }
- astobj2_ref(EXTERNAL_OBJ(a->cur), 1); /* inc refcount of returned object */
-
+ }
+done:
astobj2_unlock(a->c);
- return EXTERNAL_OBJ(a->cur);
+ return p ? EXTERNAL_OBJ(p->astobj) : NULL;
}
/* callback for destroying container.
@@ -544,6 +528,7 @@
if (x++ & 1) {
astobj2_unlink(c1, obj);
}
+ astobj2_ref(obj, -1);
}
}
ast_cli(fd, "testing callbacks again\n");
More information about the asterisk-commits
mailing list