[svn-commits] rizzo: branch rizzo/astobj2 r45807 - in /team/rizzo/astobj2: include/asterisk...

svn-commits at lists.digium.com svn-commits at lists.digium.com
Fri Oct 20 15:07:38 MST 2006


Author: rizzo
Date: Fri Oct 20 17:07:38 2006
New Revision: 45807

URL: http://svn.digium.com/view/asterisk?rev=45807&view=rev
Log:
bring in a very preliminary version of astobj2


Added:
    team/rizzo/astobj2/include/asterisk/astobj2.h   (with props)
    team/rizzo/astobj2/main/astobj2.c   (with props)
Modified:
    team/rizzo/astobj2/main/Makefile

Added: team/rizzo/astobj2/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/include/asterisk/astobj2.h?rev=45807&view=auto
==============================================================================
--- team/rizzo/astobj2/include/asterisk/astobj2.h (added)
+++ team/rizzo/astobj2/include/asterisk/astobj2.h Fri Oct 20 17:07:38 2006
@@ -1,0 +1,441 @@
+/*
+ * astobj2 - replacement containers for asterisk data structures.
+ *
+ * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef _ASTERISK_ASTOBJ2_H
+#define _ASTERISK_ASTOBJ2_H
+
+#include <inttypes.h>
+#include <strings.h> 
+
+#include "asterisk/lock.h"
+
+/*! \file 
+ *
+ * \brief Object Model implementing objects and containers.
+ *
+These functions implement a container for user-defined object,
+supporting locking, reference counting and callbacks.
+The internal implementation of the container is, in principle,
+opaque to the user so we can use different data structures
+as needs arise. At the moment, however, the only internal
+data structure is a hash table. When other structures will
+be implemented, the initialization function may change.
+
+A container must first be allocated, specifying the initial
+parameters. At the moment, this is done as follows:
+
+    <b>Sample Usage:</b>
+    \code
+
+    struct container *c;
+
+    c = astobj2_container_alloc(MAX_BUCKETS, my_hash_fn, my_cmp_fn, my_dump_fn);
+
+where
+- MAX_BUCKETS is the number of buckets in the hash table,
+- my_hash_fn() is the (user-supplied) function that returns a
+  hash key for the object (further reduced moduly MAX_BUCKETS
+  by the container's code);
+- my_cmp_fn() is the default comparison function used when doing
+  searches on the container,
+- my_dump_fn() is a helper function used only for debugging.
+
+A container knows little or nothing about the object itself,
+other than the fact that it has been created by astobj2_obj_alloc()
+(which is supposed to provide the extra data field used by
+the container code for manipulation).
+All knowledge of the (user-defined) internals of the object
+is left to the (user-supplied) functions defined above.
+
+An object must be allocated with the function astobj2_obj_alloc(),
+which needs to know the size of the user-defined structure,
+and a pointer to a destructor function that is invoked
+when the object is not referenced anymore:
+ 
+    struct foo *o;
+ 
+    o = astobj2_obj_alloc(sizeof(struct foo), my_destructor_fn);
+
+the object return has a refcount = 1.
+Note that the memory for the object is zeroed.
+
+Note that we cannot do free(o) to dispose of the object
+created in this way. Rather, we need to call
+
+    astobj2_ref(o, -1)
+
+which will drop a reference, causing the destructor to be
+called (and then memory freed) when the refcount goes to 0.
+
+If we want to insert the object in the container, we should
+initialize its fields -- especially, those used by my_hash_fn()
+to compute the bucket to use.
+Once done, we can link an object to a container with
+
+    astobj2_link(c, o);
+
+The function returns NULL in case of errors (and the object
+is not inserted in the container). Other values mean success
+(we are not supposed to use the value as a pointer to anything).
+
+\note inserting the object in the container creates another reference
+to the object (owned by the container) so we still need to drop
+ours when we are done.
+
+\note While an object o is in a container, we expect that
+my_hash_fn(o) will always return the same value. The function
+does not lock the object to be computed, so modifications of
+those fields that affect the computation of the hash should
+be done by extractiong the object from the container, and
+reinserting it after the change (this is not terribly expensive).
+
+\note A container with a single buckets is effectively a linked
+list. However there is no ordering among elements.
+
+Objects implement a reference counter keeping the count
+of the number of references that reference an object.
+
+When this number becomes zero the destructor will be
+called and the object will be free'd.
+ */
+
+#ifndef FALSE
+#define FALSE    0
+#endif
+
+#ifndef TRUE
+#define TRUE     1
+#endif
+
+/*!
+ * Invoked just before freeing the memory for the object.
+ * It is passed a pointer to user data.
+ */
+typedef void (*astobj2_destructor_fn)(void *);
+
+/*!
+ * astobj2 objects are always prepended this data structure,
+ * which contains a lock, a reference counter,
+ * the flags and a pointer to a destructor.
+ * The refcount is used to decide when it is time to
+ * invoke the destructor.
+ */
+struct astobj2_priv_data {
+	ast_mutex_t	lock;
+	int		ref_counter;
+	astobj2_destructor_fn destructor_fn;
+};
+
+/*!
+ * What an astobj2 object looks like: fixed-size private data
+ * followed by variable-size user data.
+ */
+struct astobj2 {
+	struct astobj2_priv_data priv_data;
+	void *user_data[0];
+};
+
+/*!
+ * Lock an object.
+ * 
+ * \param a A pointer to the object we want lock.
+ * \return 0 on success, other values on error.
+ */
+int astobj2_lock(void *a);
+
+/*!
+ * Unlock an object.
+ * 
+ * \param a A pointer to the object we want unlock.
+ * \return 0 on success, other values on error.
+ */
+int astobj2_unlock(void *a);
+
+/*!
+ * Reference/unreference an object.
+ *
+ * \param o A pointer to the object
+ * \param delta Value to add to the reference counter.
+ * \return The value of the reference counter before the operation.
+ *
+ * Increase/decrease the reference counter according
+ * the value of delta.
+ * If the refcount goes to zero, the object is destroyed.
+ * \note: if we know the pointer to an object, it is because we
+ * have a reference count to it, so the only case when the object
+ * can go away is when we release our reference, and it is
+ * the last one in existence.
+ */
+int astobj2_ref(void *o, int delta);
+
+/*!
+ * Allocate and initialize an object.
+ * 
+ * \param data_size The sizeof() of user-defined structure.
+ * \param destructor_fn The function destructor (can be NULL)
+ * \return A pointer to user data. 
+ *
+ * Allocates a struct astobj2 with sufficient space for the
+ * user-defined structure.
+ * \notes:
+ * - storage is zeroed; XXX maybe we want a flag to enable/disable this.
+ * - the refcount of the object just created is 1
+ * - the returned pointer cannot be free()'d or realloc()'ed;
+ *   rather, we just call astobj2_ref(o, -1);
+ */
+void *astobj2_obj_alloc(const size_t data_size, 
+		astobj2_destructor_fn destructor_fn);
+
+/*!
+ * We can perform different operation on an object. We do this
+ * according the following flags.
+ */
+enum search_flags {
+	OBJ_UNLINK	= 0x01,	/* unlink the object found */
+	OBJ_DATA	= 0x02,	/* on match, return the object. */
+	OBJ_SINGLE	= 0x08,	/* stop at the first match */
+	OBJ_POINTER	= 0x10	/* the pointer is an object pointer */
+};
+
+/*!
+ * Type of a generic function to generate a hash value from an object.
+ *
+ */
+typedef int (*astobj2_hash_fn)(const void *obj, const int is_obj);
+
+/*!
+ * valid callback results:
+ * We return a combination of
+ * CMP_MATCH when the object matches the request,
+ * and CMP_STOP when we should not continue the search further.
+ */
+enum _cb_results {
+	CMP_MATCH	= 0x1,
+	CMP_STOP	= 0x2,
+};
+
+/*!
+ * generic function to compare objects.
+ * This, as other callbacks, should return a combination of
+ * _cb_results as described above.
+ *
+ * \param o	object from container
+ * \param arg	search parameters (directly from astobj2_find)
+ * \param flags	passed directly from astobj2_find
+ *	XXX explain.
+ */
+
+/*!
+ * Type of a generic callback function
+ * \param obj  pointer to the (user-defined part) of an object.
+ * \param arg callback argument from astobj2_callback()
+ * \param flags flags from astobj2_callback()
+ * The return values are the same as a compare function.
+ * In fact, they are the same thing.
+ */
+typedef int (*astobj2_callback_fn)(void *obj, void *arg, int flags);
+
+/*! \typedef astobj_dump_fn	XXX should go away
+ *
+ * \brief Type of a generic function to dump external values of an objects.
+ */
+typedef void (*astobj2_dump_fn)(const void *obj);
+
+/*!
+ * A structure to create a linked list of entries,
+ * used within a bucket.
+ * XXX this should be private to the container code
+ */
+struct astobj2_bucket_list {
+	struct astobj2_bucket_list *next;	/* pointer to next bucket_list */ 
+	struct astobj2 *obj;			/* pointer to internal data */
+};
+
+/*!
+ * Here start declarations of containers.
+ */
+
+/*!
+ * This structure contains the total number of buckets 
+ * and variable size array of object pointers.
+ */
+struct container {
+	astobj2_hash_fn hash_fn;
+	astobj2_callback_fn cmp_fn;
+	int	n_buckets;
+	int	elements;	/* number of elements in the container */
+	struct astobj2_bucket_list *buckets[0];	/* variable size */
+};
+
+/*!
+ * Allocate and initialize a container 
+ * with the desired number of buckets.
+ * 
+ * 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 
+ * 			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.
+ */
+struct container *astobj2_container_alloc(const uint n_buckets,
+		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.
+ */
+int astobj2_container_empty(struct container *c);
+
+/*
+ * Here we have functions to manage objects.
+ *
+ * We can use the functions below on any kind of 
+ * object defined by the user.
+ */
+/*!
+ * Add an object to a container.
+ *
+ * \param c the container to operate on.
+ * \param obj the object to be added.
+ * \return NULL on errors, other values on success.
+ *
+ * This function insert an object in a container according its key.
+ *
+ * \note Remember to set the key before calling this function.
+ */
+void *astobj2_link(struct container *c, void *newobj);
+
+/*! \struct Used as return value if the flag OBJ_MULTIPLE is set */
+struct astobj2_list {
+	struct astobj2_list *next;
+	void *obj_pointer;
+};
+
+/*!
+ * astobj2_callback() and astob2_find() are the same thing with only one difference:
+ * the latter uses as a callback the function passed as my_cmp_f() at
+ * the time of the creation of the container.
+ * 
+ * \param c A pointer to the container to operate on.
+ * \param arg passed to the callback.
+ * \param flags A set of flags specifying the operation to perform,
+	partially used by the container code, but also passed to
+	the callback.
+ * \return 	A pointer to the object found/marked, 
+ * 		a pointer to a list of objects matching comparison function,
+ * 		NULL if not found.
+ * If the function returns any objects, their refcount is incremented,
+ * and the caller is in charge of decrementing them once done.
+ * Also, in case of multiple values returned, the list used
+ * to store the objects must be freed by the caller.
+ *
+ * This function searches through a container and performs operations
+ * on objects according on flags passed.
+ * XXX describe better
+ * The comparison is done calling the compare function set implicitly. 
+ * The p pointer can be a pointer to an object or to a key, 
+ * we can say this looking at flags value.
+ * If p points to an object we will search for the object pointed
+ * by this value, otherwise we serch for a key value.
+ * If the key is not uniq we only find the first matching valued.
+ * If we use the OBJ_MARK flags, we mark all the objects matching 
+ * the condition.
+ *
+ * The use of flags argument is the follow:
+ *
+ *	OBJ_UNLINK 		unlinks the object found
+ *	OBJ_DATA		on match, return an object
+ *				Callbacks do not use OBJ_DATA,
+ *				functions such as find() do
+ *	OBJ_SINGLE		stop at the first match.
+ *				Default for _find();
+ *				to a key (not yet supported)
+ *	OBJ_POINTER 		the pointer is an object pointer
+ *
+ * In case we return a list, the callee must take care to destroy 
+ * that list when no longer used.
+ *
+ * \note When the returned object is no longer in use, astobj2_ref() should
+ * be used to free the additional reference possibly created by this function.
+ */
+void *astobj2_find(struct container *c, void *arg, enum search_flags flags);
+void *astobj2_callback(struct container *c,
+	enum search_flags flags,
+	astobj2_callback_fn cb_fn, void *arg);
+
+/*!
+ *
+
+When we need to walk through a container, we use
+astobj2_iterator to keep track of the current position.
+
+Because the navigation is typically done without locking
+the container, objects can be inserted or deleted or moved
+while we work. As a consequence, there is no guarantee that
+the we manage to touch all the elements on the list, or it
+is possible that we touch the same object multiple times.
+We do implement a few things to reduce the chance of the
+above happening.
+
+An iterator must be first initialized with astobj2_iterator_init(),
+then we can use o = astobj2_iterator_next() to move from one
+element to the next. Remember that the object returned by
+astobj2_iterator_next() has its refcount incremented,
+and the refcount will be decremented by the next call to
+astobj2_iterator_next(). If we terminate the loop early,
+we need to release the refcount explicitly when we are
+done with the object.
+Example:
+
+    \code
+
+    struct astobj2_iterator i;;
+    struct my_obj *o;
+
+    astobj2_iterator_init(&i);
+ 
+    while ( (o = astobj2_iterator_next(&i)) ) {
+	... do something on o ...
+    }
+    if (o)
+	astobj2_ref(o, -1);
+
+    \endcode
+
+ */
+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 */
+};
+
+void astobj2_iterator_init(struct container *c, struct astobj2_iterator *i);
+
+void *astobj2_iterator_next(struct astobj2_iterator *a);
+
+#endif /* _ASTERISK_ASTOBJ2_H */

Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/rizzo/astobj2/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/Makefile?rev=45807&r1=45806&r2=45807&view=diff
==============================================================================
--- team/rizzo/astobj2/main/Makefile (original)
+++ team/rizzo/astobj2/main/Makefile Fri Oct 20 17:07:38 2006
@@ -26,6 +26,7 @@
 	utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
+	astobj2.o \
 	strcompat.o
 
 # we need to link in the objects statically, not as a library, because

Added: team/rizzo/astobj2/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/astobj2.c?rev=45807&view=auto
==============================================================================
--- team/rizzo/astobj2/main/astobj2.c (added)
+++ team/rizzo/astobj2/main/astobj2.c Fri Oct 20 17:07:38 2006
@@ -1,0 +1,388 @@
+/*
+ * astobj2 - replacement containers for asterisk data structures.
+ *
+ * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*
+ * Function implementing astobj2 objects.
+ */
+#include "asterisk.h"
+#include <assert.h>
+
+/* TODO: Revision: ? */
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "asterisk/astobj2.h"
+
+/*
+ * From a pointer _p to a user-defined object,
+ * return the pointer to the astobj2 structure
+ */
+#define INTERNAL_OBJ(_p)	((struct astobj2 *)( (_p) == NULL ? NULL : (char *)(_p) - sizeof(struct astobj2) ))
+
+/*
+ * From a pointer _p to an astobj2 object,
+ * return the pointer to the user-defined portion.
+ */
+#define EXTERNAL_OBJ(_p)	((_p) == NULL ? NULL : (_p)->user_data)
+
+int astobj2_lock(void *a)
+{
+	return ast_mutex_lock( &INTERNAL_OBJ(a)->priv_data.lock );
+}
+
+int astobj2_unlock(void *a)
+{
+	return ast_mutex_unlock( &INTERNAL_OBJ(a)->priv_data.lock );
+}
+
+/*
+ * we expect a to be non-NULL
+ */
+int astobj2_ref(void *a, const int delta)
+{
+#if 0
+ 	ast_log(LOG_NOTICE, "Reference counter changed by %i\n", delta);
+#endif
+	struct astobj2 *obj = INTERNAL_OBJ(a);
+
+	int current_value;
+	int ret;
+
+	assert(a != NULL);
+	/* if delta is 0, just return the refcount */
+	if (delta == 0)
+		return (obj->priv_data.ref_counter);
+
+	/* we modify with an atomic operation the reference counter */
+	ret = ast_atomic_fetchadd_int( &obj->priv_data.ref_counter, delta );
+	current_value = ret + delta;
+
+	/* this case must never happen */
+	if (current_value < 0)
+		ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, a);
+
+	if ( current_value <= 0 ) { /* last reference, destroy the object */
+		ast_log(LOG_DEBUG, "refcount %d on object %p, we destroy the object\n", current_value, a);
+
+		if (obj->priv_data.destructor_fn != NULL) 
+			obj->priv_data.destructor_fn(a);
+
+		ast_mutex_destroy(&obj->priv_data.lock);
+		/* for safety, zero-out the astobj2 header and also the
+		 * first word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
+		free( obj );
+	}
+
+	return ret;
+}
+
+/*
+ * We always alloc at least the size of a void *,
+ * for debugging purposes.
+ */
+void *astobj2_obj_alloc(size_t data_size, astobj2_destructor_fn destructor_fn)
+{
+	/* allocation */
+	struct astobj2 *a;
+
+	if (data_size < sizeof(void *))
+		data_size = sizeof(void *);
+
+	a = calloc ( 1, sizeof(struct astobj2) + data_size );
+
+	if ( a == NULL)
+		return NULL;
+
+	/* init */
+	ast_mutex_init(&a->priv_data.lock);
+	a->priv_data.ref_counter = 1;
+	a->priv_data.destructor_fn = destructor_fn;	/* can be NULL */
+
+	/* return a pointer to the user data */
+	return EXTERNAL_OBJ(a);
+}
+
+/* XXX todo callback that unlinks and unrefs every element */
+static void container_destruct(void *c);
+
+/*
+ * A container is just an object, after all!
+ */
+struct container *
+astobj2_container_alloc(const uint n_buckets, astobj2_hash_fn hash_fn,
+		astobj2_callback_fn cmp_fn)
+{
+	/* compute the container size */
+	size_t container_size = sizeof (struct container)
+		+ n_buckets * sizeof (struct astobj2_bucket_list *);
+
+	/* XXX must fix the destructor */
+	struct container *c = astobj2_obj_alloc(container_size, container_destruct);
+
+	if ( c == NULL )
+		return NULL;
+
+	/* init */
+	c->elements = 0;
+	c->n_buckets = n_buckets;
+	c->hash_fn = hash_fn;
+	c->cmp_fn = cmp_fn;
+
+	return c;
+}
+
+/* XXX better to keep a global count of elements */
+int astobj2_container_empty(struct container *c)
+{
+	return c->elements;
+}
+
+/*!
+ * link an object to a container
+ */
+void *astobj2_link(struct container *c, void *newobj)
+{
+	struct astobj2_bucket_list *list_pointer;
+	uint i = c->hash_fn( newobj, TRUE );
+
+	astobj2_lock(c);
+	i %= c->n_buckets;
+	list_pointer = calloc( 1, sizeof (struct astobj2_bucket_list) );
+
+	/* linking the object to head */
+	if (list_pointer != NULL) {
+		list_pointer->next = c->buckets[i];
+		list_pointer->obj = INTERNAL_OBJ(newobj);
+		c->buckets[i] = list_pointer;
+		list_pointer = newobj;
+	}
+	astobj2_unlock(c);
+	return list_pointer;
+}
+
+/*! 
+ * \internal
+ * \brief Unlink an object from the list
+ * and destroy the associated * astobj2_bucket_list structure.
+ */
+static void obj_unlink(struct astobj2_bucket_list *prev_pointer)
+{
+	struct astobj2_bucket_list *to_delete = prev_pointer->next;
+
+	prev_pointer->next = to_delete->next;
+	free(to_delete);
+}
+
+/*!
+ * Browse the container using different stategies accoding the flags.
+ * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is 
+ * specified.
+ */
+void *astobj2_callback(struct container *c,
+	const enum search_flags flags,
+	astobj2_callback_fn cb_fn, void *arg)
+{
+	int i, last;
+	int match;
+	struct astobj2 *ret = NULL;
+
+	if ( (flags & (OBJ_SINGLE | OBJ_DATA)) == OBJ_DATA) {
+		ast_log(LOG_WARNING, "multiple data return not implemented yet");
+		return NULL;
+	}
+	/*
+	 * XXX this can be optimized.
+	 */
+	if (flags & OBJ_POINTER)	/* we know hash can handle this case */
+		i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
+	else			/* don't know, let's scan all buckets */
+		i = -1;		/* XXX this must be fixed later. */
+
+	if (i < 0) {
+		i = 0;
+		last = c->n_buckets;
+	} else {
+		last = i+1;
+	}
+
+	astobj2_lock(c);
+
+	for(; i < last ; i++) {
+		struct astobj2_bucket_list *prev = NULL, *cur = c->buckets[i];
+		while (cur) {
+			/* match by pointer or exec a function */
+			if ( flags & OBJ_POINTER )
+				match = ( cur->obj == INTERNAL_OBJ(arg) );
+			else
+				match = cb_fn(EXTERNAL_OBJ(cur->obj), arg, flags );
+
+			/* we found the object, performing operations according flags */
+			if (!match) {
+				prev = cur;
+				cur = cur->next;
+				continue;
+			}
+			if (flags & OBJ_DATA)
+				ret = cur->obj;
+			if (flags & OBJ_UNLINK) {
+				struct astobj2_bucket_list *x = cur;
+
+				if (prev == NULL)
+					c->buckets[i] = cur->next;
+				else
+					prev->next = cur->next;
+				cur = cur->next ;
+				free(x);
+			}
+
+			if (flags & OBJ_SINGLE) {
+				/* We found the only match we need */
+				i = last;	/* force exit from outer loop */
+				break;
+			}
+			if (flags & OBJ_DATA) {
+#if 0	/* XXX to be completed */
+				/* here build a list of object pointers and increase
+				 * the reference counter for each reference created */
+				struct astobj2_list *new_obj;
+				new_obj = calloc(1, sizeof(struct astobj2_list));
+				if ( new_obj == NULL ) {
+					ast_log(LOG_WARNING, "No list created, out of memory\n");
+					continue;
+				}
+				astobj2_ref(EXTERNAL_OBJ(list_pointer->obj), 1);
+				new_obj->next = (struct astobj2_list *)ret;
+				ret = new_obj;
+#endif
+			}
+			prev = cur;
+			cur = cur->next;
+		}
+	}
+	astobj2_unlock(c);
+
+	/* increase the reference counter, unlock the container and return */
+	if ( ret != NULL ) {
+		astobj2_ref(ret, 1);
+		ret = (void *)EXTERNAL_OBJ(ret);
+	} 
+	return ret;
+}
+
+void *astobj2_find(struct container *c, void *p, enum search_flags flags)
+{
+	if (flags == 0)
+		flags = OBJ_SINGLE | OBJ_DATA;	/* reasonable default */
+	ast_log(LOG_NOTICE, "astobj2_find\n");
+	return astobj2_callback(c, flags, c->cmp_fn, p);
+}
+
+void astobj2_iterator_init(struct container *c, struct astobj2_iterator *a)
+{
+	a->bucket = 0;
+	a->pos = 0;
+	a->c = c;
+	a->cur = NULL;
+}
+
+/*
+ * move to the next element in the container.
+ */
+void * astobj2_iterator_next(struct astobj2_iterator *a)
+{
+	int lim;
+	struct astobj2_bucket_list **bp;
+
+	if (a->cur)
+		astobj2_ref(EXTERNAL_OBJ(a->cur), -1);
+	else {	/* search from the beginning */
+		a->bucket = 0;
+		a->pos = -1;
+	}
+
+	astobj2_lock(a->c);
+	lim = a->c->n_buckets;
+	bp = a->c->buckets;
+	
+	/* we browse the buckets array, moving to the next
+	 * buckets if we don't find the entry in the current one.
+	 */
+	for ( ; a->bucket < lim;
+			/* move to next bucket */
+			a->bucket++, a->pos = -1) {
+		struct astobj2_bucket_list *p = bp[a->bucket], *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->obj;
+			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->obj == 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;
+			}
+		}
+		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->obj;
+		break;
+	}
+
+	if (a->bucket == lim)	/* not found */
+		return NULL;
+	astobj2_ref(EXTERNAL_OBJ(a->cur), 1);	/* inc refcount of returned object */
+
+	astobj2_unlock(a->c);
+	return EXTERNAL_OBJ(a->cur);
+}
+
+/* callback for destroying container.
+ * we can make it simple as we know what it does
+ */
+static int cd_cb(void *obj, void *arg, int flag)
+{
+	astobj2_ref(obj, -1);
+	return 0;
+}
+	
+static void container_destruct(void *_c)
+{
+	struct container *c = _c;
+	
+	astobj2_callback(c, OBJ_UNLINK, cd_cb, NULL);
+	astobj2_ref(c, -1);
+}

Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain



More information about the svn-commits mailing list