Beispiel #1
0
/**
 * \brief Delete an element from the association list.
 *
 * \param al          The association list which contains the element to delete.
 * \param key         The key to the element to delete.
 * \param eq          The equals predicate for two keys.
 * \param free_key    The function which is used to free the key data, or
 *			\c NULL if no action should be taken on the key data.
 * \param free_value  The function which is used to free the value data, or
 *			\c NULL if no action should be taken on the value data.
 *
 * \return  The alist, or \c NULL if the key could not be found.
 *
 * \par Errno values:
 * - \b EINVAL if the key could not be found.
 *
 * \sa alist_insert
 */
alist
alist_delete(alist al, gendata key, eq_func eq, free_func free_key,
	     free_func free_value)
{
	sll l, n;
	alist_entry e;

	assert(al != NULL);
	assert(eq != NULL);

	l = al->list;

	if (sll_empty(l)) {
		errno = EINVAL;
		return NULL;
	}

	/*
	 * The first entry is a special case.  Doubly linked lists might
	 *  be easier, but it's not convenience we are after in here.
	 */
	e = sll_get_data(l).ptr;
	if (eq(key, e->key)) {
		if (free_key != NULL)
			free_key(e->key.ptr);
		if (free_value != NULL)
			free_value(e->value.ptr);
		/* We are removing the first entry from the list! */
		al->list = sll_remove_head(l, free);
		return al;
	}

	/* n is always one ahead of l (so, n == l->next) */
	n = sll_next(l);

	while (!sll_empty(n)) {
		e = sll_get_data(n).ptr;
		if (eq(key, e->key)) {
			if (free_key != NULL)
				free_key(e->key.ptr);
			if (free_value != NULL)
				free_value(e->value.ptr);
			sll_remove_next(l, free);
			return al;
		}
		l = sll_next(l);
		n = sll_next(n);
	}

	/* If we got here, we obviously didn't find the entry. */
	errno = EINVAL;
	return NULL;
}
Beispiel #2
0
void * sll_front(sb_sll * instance)
{
	if (sll_empty(instance)) {
		return NULL;
	}
	return instance->head->elem;
}
Beispiel #3
0
/**
 * \brief Free all memory allocated for an association list.
 *
 * The data within the list is freed by calling the user-supplied
 * function \p free_value.  The key used to identify the entry can also
 * be freed by the user-supplied \p free_key function.
 *
 * \attention
 * If the same data or key is included multiple times in the list, the free
 * functions get called that many times on the data or key.
 *
 * \param al          The association list to destroy.
 * \param free_key    The function which is used to free the key data, or
 *			\c NULL if no action should be taken on the key data.
 * \param free_value  The function which is used to free the value data, or
 *			\c NULL if no action should be taken on the value data.
 *
 * \sa alist_create
 */
void
alist_destroy(alist al, free_func free_key, free_func free_value)
{
	alist_entry e;

	assert(al != NULL);

	/*
	 * What we would really like to do is just call
	 * sll_destroy(*p, f);
	 * Problem is we can't pass a function which knows
	 * about the * free_{key, value} functions. (you can't do
	 * currying in C)
	 */
	while (!sll_empty(al->list)) {
		e = sll_get_data(al->list).ptr;
		if (free_key != NULL)
			free_key(e->key.ptr);
		if (free_value != NULL)
			free_value(e->value.ptr);
		al->list = sll_remove_head(al->list, free);
	}

	free(al);
}
Beispiel #4
0
/**
 * \brief Merge two association lists together uniquely.
 *
 * Add all data elements from an association list to another association list
 * with the given key.  If a duplicate key is encountered, the entry is not
 * inserted into the \p base list.
 *
 * \note
 * This function is \f$ O(n \cdot m) \f$ with \f$ n \f$ the length of
 * \p base and \f$ m \f$ the length of \p rest.
 *
 * \param base	      The association list to insert the data in.
 * \param rest        The association list to be merged into \p base.
 * \param eq          The equals predicate for two keys.
 *
 * \return  The \p base alist, merged with \p rest, or NULL in case of error.
 *           If an error occurred, the \p base list is still valid, but
 *           it is undefined which items from the \p rest list will have been
 *           merged into the list and which haven't.
 *	    The \p rest alist will have been modified so it still contains
 *	     the entries which had matching keys in the \p base alist.
 *	    The \p rest alist will thus still be valid.
 *
 * \par Errno values:
 * - \b ENOMEM if out of memory.
 *
 * \sa alist_insert_uniq alist_delete alist_merge
 */
alist
alist_merge_uniq(alist base, alist rest, eq_func eq)
{
	sll l;
	alist_entry e;
	alist base_tmp;

	assert(base != NULL);
	assert(rest != NULL);

	l = rest->list;

	while (!sll_empty(l)) {
		e = sll_get_data(l).ptr;
		base_tmp = alist_insert_uniq(base, e->key, e->value, eq);

		if (base_tmp == NULL) {
			if (errno == ENOMEM)
				return NULL;
			else
				l = sll_next(l);
		} else {
			base = base_tmp;
			l = sll_remove_head(l, free);
		}
	}

	return base;
}
Beispiel #5
0
/**
 * \brief Merge two association lists together.
 *
 * Add all data elements from an association list to another association
 * list, replacing the value of all existing elements with the same key.
 *
 * \note
 * This function is \f$ O(n \cdot m) \f$ with \f$ n \f$ the length of
 * \p base and \f$ m \f$ the length of \p rest.
 *
 * \param base	      The association list to insert the data in.
 * \param rest        The association list to be merged into \p base.
 * \param eq          The equals predicate for two keys.
 * \param free_key    The function used to free the \p rest list's key data,
 *		       or \c NULL if the data does not need to be freed.
 * \param free_value  The function used to free the \p base value's data if it
 *		       needs to be replaced, or \c NULL if the data does not
 *		       need to be freed.
 *
 * \return  The \p base alist, merged with \p rest, or NULL in case of error.
 *           If an error occurred, the \p base list is still valid, but
 *           it is undefined which items from the \p rest list will have been
 *           merged into the list and which haven't.  The \p rest list will
 *	     not be valid after the function has finished.
 *
 * \par Errno values:
 * - \b ENOMEM if out of memory.
 *
 * \sa alist_insert alist_delete alist_merge_uniq
 */
alist
alist_merge(alist base, alist rest, eq_func eq, free_func free_key,
	     free_func free_value)
{
	sll l;
	alist_entry e;

	assert(base != NULL);
	assert(rest != NULL);

	l = rest->list;

	while (!sll_empty(l)) {
		e = sll_get_data(l).ptr;
		base = alist_insert(base, e->key, e->value, eq,
				    free_key, free_value);

		/*
		 * HACK: We are cheating here, since we're assuming the alist
		 * implementation is a pointer to a container struct for the
		 * list itself.  If this implementation would ever change, this
		 * function would simple not work. (Imagine an error happening
		 * in sll_append in the middle of appending.  What should be
		 * returned?  Not NULL, since we have memory leakage then)
		 */
		if (base == NULL)
			return NULL;

		l = sll_remove_head(l, free);
	}

	free(rest);
	return base;
}
Beispiel #6
0
/**
 * \brief Return whether or not an association list is empty.
 *
 * \param al  The association list to check.
 *
 * \return  Non-zero if the list is empty, 0 if it is not.
 */
int
alist_empty(alist al)
{
	assert(al != NULL);

	return sll_empty(al->list);
}
Beispiel #7
0
void sll_destroy(sb_sll * instance)
{
	while(!sll_empty(instance)) {
		sll_remove_front(instance);
	}
	
	free(instance);
}
Beispiel #8
0
void
stress_test_sll(int amt)
{
	sll l1;
	sll l2;
	gendata x, y;
	int i;

	l1 = sll_create();
	l2 = sll_create();
	assert(sll_empty(l1));
	assert(sll_empty(l2));
	printf("Filling two slls with 2 * %d items...\n", amt);
	for (i = 0; i < amt; ++i) {
		x.num = i;
		l1 = sll_prepend_head(l1, x);
		l2 = sll_prepend_head(l2, x);
		assert(!sll_empty(l1));
		assert(!sll_empty(l2));
		l1 = sll_append_head(l1, x);
		l2 = sll_append_head(l2, x);
		assert(!sll_empty(l1));
		assert(!sll_empty(l2));
	}
	assert(sll_count(l1) == (unsigned int)(2 * amt));
	assert(sll_count(l2) == (unsigned int)(2 * amt));

	l1 = sll_append(l1, l2);
	assert(sll_count(l1) == (unsigned int)(4 * amt));

	/* From now on, l2 is `invalid' */

	printf("Removing 2 * 2 * %d items from the appended sll...\n", amt);
	for (i = 0; i < (2 * amt); ++i) {
		x = sll_get_data(sll_next(l1));
		assert(!sll_empty(l1));
		l1 = sll_remove_next(l1, NULL);
		y = sll_get_data(l1);
		assert(!sll_empty(l1));
		l1 = sll_remove_head(l1, NULL);

		/*
		 * We have to count backwards in this check, since we're
		 * using the list like a stack, prepending all the time.
		 */
		assert(x.num == amt - (i % amt) - 1);
		assert(x.num == y.num);
	}
	assert(sll_empty(l1));
	sll_destroy(l1, NULL);
}
Beispiel #9
0
/*
 * Internal function which alist_insert and alist_insert_uniq call.
 * Argument list is the same as these two functions, except for an extra
 * integer tacked onto the end.  This integer is nonzero if existing
 * key entries are not allowed.  If existing key entries are allowed, the
 * value of that key is overwritten.
 */
static alist
alist_insert_internal(alist al, gendata key, gendata value, eq_func eq,
		      free_func free_key, free_func free_value, int uniq)
{
	sll new_head;
	alist_entry e;
	gendata e_data;
	sll l;

	assert(al != NULL);
	assert(eq != NULL);

	l = al->list;

	/*
	 * We'll have to check if there's already a value with the same key.
	 * If there is, overwrite that value unless uniq.
	 */
	while (!sll_empty(l)) {
		e = sll_get_data(l).ptr;
		if (eq(key, e->key)) {
			/* Duplicates not allowed? */
			if (uniq) {
				errno = EINVAL;
				return NULL;
			}

			/* Free old data */
			if (free_key != NULL)
				free_key(e->key.ptr);
			if (free_value != NULL)
				free_value(e->value.ptr);
			e->value = value;
			e_data.ptr = e;
			sll_set_data(l, e_data);
			return al;
		}
		l = sll_next(l);
	}

	/* If we got here, the key does not occur in the table yet */
	if ((e = malloc(sizeof(alist_entry_t))) == NULL)
		return NULL;

	e->key = key;
	e->value = value;
	e_data.ptr = e;

	new_head = sll_prepend_head(al->list, e_data);
	if (new_head == NULL) {
		free(e);
		return NULL;
	}

	al->list = new_head;
	return al;
}
Beispiel #10
0
/**
 * \brief Walk through all elements of an alist.
 *
 * Walk an alist, using a user-specified function on the list's pairs.
 *
 * \attention
 * While using this function, it is not allowed to remove entries other than
 * the current entry.  It is allowed to change the contents of the key and
 * value.
 *
 * \param al    The alist to walk.
 * \param walk  The function which will process the pairs.
 * \param data  Any data to pass to the function every time it is called.
 */
void
alist_walk(alist al, assoc_func walk, gendata data)
{
	alist_entry e;
	sll l = al->list;
	sll n = NULL;

	assert(al != NULL);
	assert(walk != NULL);

	while(!sll_empty(l)) {
		/* n is stored in case user deletes the current entry */
		n = sll_next(l);
		e = sll_get_data(l).ptr;
		walk(&e->key, &e->value, data);
		l = n;
	}
}
Beispiel #11
0
int main(int argc, char ** argv)
{
	sb_sll * list;
	list = sll_init();
	int i;
	int * element = NULL;
	for (i = 0; i < 100000; i++)
	{
		element = (int *) malloc(sizeof(int));
		*element = i;
		sll_add_front(list, (void *) element);
	}

	while (!sll_empty(list)) {
		element = (int *) sll_front(list);
		printf("element: %d\n", *element);
		sll_remove_front(list);
		free(element);
	}

	sll_destroy(list);
	return EXIT_SUCCESS;
}
Beispiel #12
0
/**
 * \brief Look up an element in the association list.
 *
 * \param al    The association list which contains the element.
 * \param key   The key to the element.
 * \param eq    The equals predicate for two keys.
 * \param data  A pointer to the location where the element is stored, if
 *               it was found.
 *
 * \return  The alist if the key was found, or \c NULL if the key could not be
 *          found.
 *
 * \par Errno values:
 * - \b EINVAL if the key could not be found.
 *
 * \sa alist_insert
 */
alist
alist_lookup(alist al, gendata key, eq_func eq, gendata *data)
{
	sll l;
	alist_entry e;

	assert(al != NULL);
	assert(eq != NULL);

	l = al->list;

	while (!sll_empty(l)) {
		e = sll_get_data(l).ptr;
		if (eq(key, e->key)) {
			*data = e->value;
			return al;
		}
		l = sll_next(l);
	}

	/* If we got here, we obviously didn't find the entry. */
	errno = EINVAL;
	return NULL;
}