Moved data structures to new collections subfolder
This commit is contained in:
@@ -54,7 +54,7 @@ struct private_backtrace_t {
|
||||
#ifdef HAVE_BFD_H
|
||||
|
||||
#include <bfd.h>
|
||||
#include <utils/hashtable.h>
|
||||
#include <collections/hashtable.h>
|
||||
#include <threading/mutex.h>
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2012 Giuliano Grassi
|
||||
* Copyright (C) 2012 Ralf Sager
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "blocking_queue.h"
|
||||
|
||||
#include <threading/mutex.h>
|
||||
#include <threading/thread.h>
|
||||
#include <threading/condvar.h>
|
||||
#include <utils/linked_list.h>
|
||||
|
||||
typedef struct private_blocking_queue_t private_blocking_queue_t;
|
||||
|
||||
/**
|
||||
* Private data of a blocking_queue_t object.
|
||||
*/
|
||||
struct private_blocking_queue_t {
|
||||
|
||||
/**
|
||||
* Public part
|
||||
*/
|
||||
blocking_queue_t public;
|
||||
|
||||
/**
|
||||
* Linked list containing all items in the queue
|
||||
*/
|
||||
linked_list_t *list;
|
||||
|
||||
/**
|
||||
* Mutex used to synchronize access to the queue
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* Condvar used to wait for items
|
||||
*/
|
||||
condvar_t *condvar;
|
||||
|
||||
};
|
||||
|
||||
METHOD(blocking_queue_t, enqueue, void,
|
||||
private_blocking_queue_t *this, void *item)
|
||||
{
|
||||
this->mutex->lock(this->mutex);
|
||||
this->list->insert_first(this->list, item);
|
||||
this->condvar->signal(this->condvar);
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
METHOD(blocking_queue_t, dequeue, void*,
|
||||
private_blocking_queue_t *this)
|
||||
{
|
||||
bool oldstate;
|
||||
void *item;
|
||||
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex);
|
||||
/* ensure that a canceled thread does not dequeue any items */
|
||||
thread_cancellation_point();
|
||||
while (this->list->remove_last(this->list, &item) != SUCCESS)
|
||||
{
|
||||
oldstate = thread_cancelability(TRUE);
|
||||
this->condvar->wait(this->condvar, this->mutex);
|
||||
thread_cancelability(oldstate);
|
||||
}
|
||||
thread_cleanup_pop(TRUE);
|
||||
return item;
|
||||
}
|
||||
|
||||
METHOD(blocking_queue_t, destroy, void,
|
||||
private_blocking_queue_t *this)
|
||||
{
|
||||
this->list->destroy(this->list);
|
||||
this->condvar->destroy(this->condvar);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
METHOD(blocking_queue_t, destroy_offset, void,
|
||||
private_blocking_queue_t *this, size_t offset)
|
||||
{
|
||||
this->list->invoke_offset(this->list, offset);
|
||||
destroy(this);
|
||||
}
|
||||
|
||||
METHOD(blocking_queue_t, destroy_function, void,
|
||||
private_blocking_queue_t *this, void (*fn)(void*))
|
||||
{
|
||||
this->list->invoke_function(this->list, (linked_list_invoke_t)fn);
|
||||
destroy(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
blocking_queue_t *blocking_queue_create()
|
||||
{
|
||||
private_blocking_queue_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.enqueue = _enqueue,
|
||||
.dequeue = _dequeue,
|
||||
.destroy = _destroy,
|
||||
.destroy_offset = _destroy_offset,
|
||||
.destroy_function = _destroy_function,
|
||||
},
|
||||
.list = linked_list_create(),
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
.condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Tobias Brunner
|
||||
* Copyright (C) 2012 Giuliano Grassi
|
||||
* Copyright (C) 2012 Ralf Sager
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup blocking_queue blocking_queue
|
||||
* @{ @ingroup utils
|
||||
*/
|
||||
|
||||
#ifndef BLOCKING_QUEUE_H_
|
||||
#define BLOCKING_QUEUE_H_
|
||||
|
||||
typedef struct blocking_queue_t blocking_queue_t;
|
||||
|
||||
#include <library.h>
|
||||
|
||||
/**
|
||||
* Class implementing a synchronized blocking queue based on linked_list_t
|
||||
*/
|
||||
struct blocking_queue_t {
|
||||
|
||||
/**
|
||||
* Inserts a new item at the tail of the queue
|
||||
*
|
||||
* @param item item to insert in queue
|
||||
*/
|
||||
void (*enqueue)(blocking_queue_t *this, void *item);
|
||||
|
||||
/**
|
||||
* Removes the first item in the queue and returns its value.
|
||||
* If the queue is empty, this call blocks until a new item is inserted.
|
||||
*
|
||||
* @note This is a thread cancellation point
|
||||
*
|
||||
* @return removed item
|
||||
*/
|
||||
void *(*dequeue)(blocking_queue_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a blocking_queue_t object.
|
||||
*
|
||||
* @note No thread must wait in dequeue() when this function is called
|
||||
*/
|
||||
void (*destroy)(blocking_queue_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a queue and its objects using the given destructor.
|
||||
*
|
||||
* If a queue and the contained objects should be destroyed, use
|
||||
* destroy_offset. The supplied offset specifies the destructor to
|
||||
* call on each object. The offset may be calculated using the offsetof
|
||||
* macro, e.g.: queue->destroy_offset(queue, offsetof(object_t, destroy));
|
||||
*
|
||||
* @note No thread must wait in dequeue() when this function is called
|
||||
*
|
||||
* @param offset offset of the objects destructor
|
||||
*/
|
||||
void (*destroy_offset)(blocking_queue_t *this, size_t offset);
|
||||
|
||||
/**
|
||||
* Destroys a queue and its objects using a cleanup function.
|
||||
*
|
||||
* If a queue and its contents should get destroyed using a specific
|
||||
* cleanup function, use destroy_function. This is useful when the
|
||||
* list contains malloc()-ed blocks which should get freed,
|
||||
* e.g.: queue->destroy_function(queue, free);
|
||||
*
|
||||
* @note No thread must wait in dequeue() when this function is called
|
||||
*
|
||||
* @param function function to call on each object
|
||||
*/
|
||||
void (*destroy_function)(blocking_queue_t *this, void (*)(void*));
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty queue object.
|
||||
*
|
||||
* @return blocking_queue_t object.
|
||||
*/
|
||||
blocking_queue_t *blocking_queue_create();
|
||||
|
||||
#endif /** BLOCKING_QUEUE_H_ @}*/
|
||||
|
||||
@@ -1,560 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Tobias Brunner
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "enumerator.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_empty().enumerate
|
||||
*/
|
||||
static bool enumerate_empty(enumerator_t *enumerator, ...)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
enumerator_t* enumerator_create_empty()
|
||||
{
|
||||
enumerator_t *this = malloc_thing(enumerator_t);
|
||||
this->enumerate = enumerate_empty;
|
||||
this->destroy = (void*)free;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerator implementation for directory enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** directory handle */
|
||||
DIR *dir;
|
||||
/** absolute path of current file */
|
||||
char full[PATH_MAX];
|
||||
/** where directory part of full ends and relative file gets written */
|
||||
char *full_end;
|
||||
} dir_enum_t;
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_directory().destroy
|
||||
*/
|
||||
static void destroy_dir_enum(dir_enum_t *this)
|
||||
{
|
||||
closedir(this->dir);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_directory().enumerate
|
||||
*/
|
||||
static bool enumerate_dir_enum(dir_enum_t *this, char **relative,
|
||||
char **absolute, struct stat *st)
|
||||
{
|
||||
struct dirent *entry = readdir(this->dir);
|
||||
size_t remaining;
|
||||
int len;
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (streq(entry->d_name, ".") || streq(entry->d_name, ".."))
|
||||
{
|
||||
return enumerate_dir_enum(this, relative, absolute, st);
|
||||
}
|
||||
if (relative)
|
||||
{
|
||||
*relative = entry->d_name;
|
||||
}
|
||||
if (absolute || st)
|
||||
{
|
||||
remaining = sizeof(this->full) - (this->full_end - this->full);
|
||||
len = snprintf(this->full_end, remaining, "%s", entry->d_name);
|
||||
if (len < 0 || len >= remaining)
|
||||
{
|
||||
DBG1(DBG_LIB, "buffer too small to enumerate file '%s'",
|
||||
entry->d_name);
|
||||
return FALSE;
|
||||
}
|
||||
if (absolute)
|
||||
{
|
||||
*absolute = this->full;
|
||||
}
|
||||
if (st)
|
||||
{
|
||||
if (stat(this->full, st))
|
||||
{
|
||||
DBG1(DBG_LIB, "stat() on '%s' failed: %s", this->full,
|
||||
strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
enumerator_t* enumerator_create_directory(const char *path)
|
||||
{
|
||||
int len;
|
||||
dir_enum_t *this = malloc_thing(dir_enum_t);
|
||||
this->public.enumerate = (void*)enumerate_dir_enum;
|
||||
this->public.destroy = (void*)destroy_dir_enum;
|
||||
|
||||
if (*path == '\0')
|
||||
{
|
||||
path = "./";
|
||||
}
|
||||
len = snprintf(this->full, sizeof(this->full)-1, "%s", path);
|
||||
if (len < 0 || len >= sizeof(this->full)-1)
|
||||
{
|
||||
DBG1(DBG_LIB, "path string '%s' too long", path);
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
/* append a '/' if not already done */
|
||||
if (this->full[len-1] != '/')
|
||||
{
|
||||
this->full[len++] = '/';
|
||||
this->full[len] = '\0';
|
||||
}
|
||||
this->full_end = &this->full[len];
|
||||
|
||||
this->dir = opendir(path);
|
||||
if (this->dir == NULL)
|
||||
{
|
||||
DBG1(DBG_LIB, "opening directory '%s' failed: %s", path, strerror(errno));
|
||||
free(this);
|
||||
return NULL;
|
||||
}
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerator implementation for directory enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
/** implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/** string to parse */
|
||||
char *string;
|
||||
/** current position */
|
||||
char *pos;
|
||||
/** separater chars */
|
||||
const char *sep;
|
||||
/** trim chars */
|
||||
const char *trim;
|
||||
} token_enum_t;
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_token().destroy
|
||||
*/
|
||||
static void destroy_token_enum(token_enum_t *this)
|
||||
{
|
||||
free(this->string);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_token().enumerate
|
||||
*/
|
||||
static bool enumerate_token_enum(token_enum_t *this, char **token)
|
||||
{
|
||||
const char *sep, *trim;
|
||||
char *pos = NULL, *tmp;
|
||||
bool last = FALSE;
|
||||
|
||||
/* trim leading characters/separators */
|
||||
while (*this->pos)
|
||||
{
|
||||
trim = this->trim;
|
||||
while (*trim)
|
||||
{
|
||||
if (*trim == *this->pos)
|
||||
{
|
||||
this->pos++;
|
||||
break;
|
||||
}
|
||||
trim++;
|
||||
}
|
||||
sep = this->sep;
|
||||
while (*sep)
|
||||
{
|
||||
if (*sep == *this->pos)
|
||||
{
|
||||
this->pos++;
|
||||
break;
|
||||
}
|
||||
sep++;
|
||||
}
|
||||
if (!*trim && !*sep)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (*this->pos)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
{
|
||||
/* read quoted token */
|
||||
tmp = strchr(this->pos + 1, *this->pos);
|
||||
if (tmp)
|
||||
{
|
||||
*token = this->pos + 1;
|
||||
*tmp = '\0';
|
||||
this->pos = tmp + 1;
|
||||
return TRUE;
|
||||
}
|
||||
/* unterminated string, FALL-THROUGH */
|
||||
}
|
||||
default:
|
||||
{
|
||||
/* find nearest separator */
|
||||
sep = this->sep;
|
||||
while (*sep)
|
||||
{
|
||||
tmp = strchr(this->pos, *sep);
|
||||
if (tmp && (pos == NULL || tmp < pos))
|
||||
{
|
||||
pos = tmp;
|
||||
}
|
||||
sep++;
|
||||
}
|
||||
*token = this->pos;
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
this->pos = pos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
last = TRUE;
|
||||
pos = this->pos = strchr(this->pos, '\0');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* trim trailing characters/separators */
|
||||
pos--;
|
||||
while (pos >= *token)
|
||||
{
|
||||
trim = this->trim;
|
||||
while (*trim)
|
||||
{
|
||||
if (*trim == *pos)
|
||||
{
|
||||
*(pos--) = '\0';
|
||||
break;
|
||||
}
|
||||
trim++;
|
||||
}
|
||||
sep = this->sep;
|
||||
while (*sep)
|
||||
{
|
||||
if (*sep == *pos)
|
||||
{
|
||||
*(pos--) = '\0';
|
||||
break;
|
||||
}
|
||||
sep++;
|
||||
}
|
||||
if (!*trim && !*sep)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!last || pos >= *token)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
enumerator_t* enumerator_create_token(const char *string, const char *sep,
|
||||
const char *trim)
|
||||
{
|
||||
token_enum_t *enumerator = malloc_thing(token_enum_t);
|
||||
|
||||
enumerator->public.enumerate = (void*)enumerate_token_enum;
|
||||
enumerator->public.destroy = (void*)destroy_token_enum;
|
||||
enumerator->string = strdup(string);
|
||||
enumerator->pos = enumerator->string;
|
||||
enumerator->sep = sep;
|
||||
enumerator->trim = trim;
|
||||
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerator for nested enumerations
|
||||
*/
|
||||
typedef struct {
|
||||
/* implements enumerator_t */
|
||||
enumerator_t public;
|
||||
/* outer enumerator */
|
||||
enumerator_t *outer;
|
||||
/* inner enumerator */
|
||||
enumerator_t *inner;
|
||||
/* constructor for inner enumerator */
|
||||
enumerator_t *(*create_inner)(void *outer, void *data);
|
||||
/* data to pass to constructor above */
|
||||
void *data;
|
||||
/* destructor for data */
|
||||
void (*destroy_data)(void *data);
|
||||
} nested_enumerator_t;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_nested().enumerate()
|
||||
*/
|
||||
static bool enumerate_nested(nested_enumerator_t *this, void *v1, void *v2,
|
||||
void *v3, void *v4, void *v5)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
while (this->inner == NULL)
|
||||
{
|
||||
void *outer;
|
||||
|
||||
if (!this->outer->enumerate(this->outer, &outer))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
this->inner = this->create_inner(outer, this->data);
|
||||
}
|
||||
if (this->inner->enumerate(this->inner, v1, v2, v3, v4, v5))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
this->inner->destroy(this->inner);
|
||||
this->inner = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_nested().destroy()
|
||||
**/
|
||||
static void destroy_nested(nested_enumerator_t *this)
|
||||
{
|
||||
if (this->destroy_data)
|
||||
{
|
||||
this->destroy_data(this->data);
|
||||
}
|
||||
DESTROY_IF(this->inner);
|
||||
this->outer->destroy(this->outer);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
enumerator_t *enumerator_create_nested(enumerator_t *outer,
|
||||
enumerator_t *(inner_constructor)(void *outer, void *data),
|
||||
void *data, void (*destroy_data)(void *data))
|
||||
{
|
||||
nested_enumerator_t *enumerator = malloc_thing(nested_enumerator_t);
|
||||
|
||||
enumerator->public.enumerate = (void*)enumerate_nested;
|
||||
enumerator->public.destroy = (void*)destroy_nested;
|
||||
enumerator->outer = outer;
|
||||
enumerator->inner = NULL;
|
||||
enumerator->create_inner = (void*)inner_constructor;
|
||||
enumerator->data = data;
|
||||
enumerator->destroy_data = destroy_data;
|
||||
|
||||
return &enumerator->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerator for filtered enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
enumerator_t public;
|
||||
enumerator_t *unfiltered;
|
||||
void *data;
|
||||
bool (*filter)(void *data, ...);
|
||||
void (*destructor)(void *data);
|
||||
} filter_enumerator_t;
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_filter().destroy
|
||||
*/
|
||||
static void destroy_filter(filter_enumerator_t *this)
|
||||
{
|
||||
if (this->destructor)
|
||||
{
|
||||
this->destructor(this->data);
|
||||
}
|
||||
this->unfiltered->destroy(this->unfiltered);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_filter().enumerate
|
||||
*/
|
||||
static bool enumerate_filter(filter_enumerator_t *this, void *o1, void *o2,
|
||||
void *o3, void *o4, void *o5)
|
||||
{
|
||||
void *i1, *i2, *i3, *i4, *i5;
|
||||
|
||||
while (this->unfiltered->enumerate(this->unfiltered, &i1, &i2, &i3, &i4, &i5))
|
||||
{
|
||||
if (this->filter(this->data, &i1, o1, &i2, o2, &i3, o3, &i4, o4, &i5, o5))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* see header
|
||||
*/
|
||||
enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
|
||||
bool (*filter)(void *data, ...),
|
||||
void *data, void (*destructor)(void *data))
|
||||
{
|
||||
filter_enumerator_t *this = malloc_thing(filter_enumerator_t);
|
||||
|
||||
this->public.enumerate = (void*)enumerate_filter;
|
||||
this->public.destroy = (void*)destroy_filter;
|
||||
this->unfiltered = unfiltered;
|
||||
this->filter = filter;
|
||||
this->data = data;
|
||||
this->destructor = destructor;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerator for cleaner enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
enumerator_t public;
|
||||
enumerator_t *wrapped;
|
||||
void (*cleanup)(void *data);
|
||||
void *data;
|
||||
} cleaner_enumerator_t;
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_cleanup().destroy
|
||||
*/
|
||||
static void destroy_cleaner(cleaner_enumerator_t *this)
|
||||
{
|
||||
this->cleanup(this->data);
|
||||
this->wrapped->destroy(this->wrapped);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_cleaner().enumerate
|
||||
*/
|
||||
static bool enumerate_cleaner(cleaner_enumerator_t *this, void *v1, void *v2,
|
||||
void *v3, void *v4, void *v5)
|
||||
{
|
||||
return this->wrapped->enumerate(this->wrapped, v1, v2, v3, v4, v5);
|
||||
}
|
||||
|
||||
/**
|
||||
* see header
|
||||
*/
|
||||
enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
|
||||
void (*cleanup)(void *data), void *data)
|
||||
{
|
||||
cleaner_enumerator_t *this = malloc_thing(cleaner_enumerator_t);
|
||||
|
||||
this->public.enumerate = (void*)enumerate_cleaner;
|
||||
this->public.destroy = (void*)destroy_cleaner;
|
||||
this->wrapped = wrapped;
|
||||
this->cleanup = cleanup;
|
||||
this->data = data;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/**
|
||||
* enumerator for single enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
enumerator_t public;
|
||||
void *item;
|
||||
void (*cleanup)(void *item);
|
||||
bool done;
|
||||
} single_enumerator_t;
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_single().destroy
|
||||
*/
|
||||
static void destroy_single(single_enumerator_t *this)
|
||||
{
|
||||
if (this->cleanup)
|
||||
{
|
||||
this->cleanup(this->item);
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of enumerator_create_single().enumerate
|
||||
*/
|
||||
static bool enumerate_single(single_enumerator_t *this, void **item)
|
||||
{
|
||||
if (this->done)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*item = this->item;
|
||||
this->done = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* see header
|
||||
*/
|
||||
enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item))
|
||||
{
|
||||
single_enumerator_t *this = malloc_thing(single_enumerator_t);
|
||||
|
||||
this->public.enumerate = (void*)enumerate_single;
|
||||
this->public.destroy = (void*)destroy_single;
|
||||
this->item = item;
|
||||
this->cleanup = cleanup;
|
||||
this->done = FALSE;
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup enumerator enumerator
|
||||
* @{ @ingroup utils
|
||||
*/
|
||||
|
||||
#ifndef ENUMERATOR_H_
|
||||
#define ENUMERATOR_H_
|
||||
|
||||
typedef struct enumerator_t enumerator_t;
|
||||
|
||||
#include "../utils.h"
|
||||
|
||||
/**
|
||||
* Enumerator interface, allows enumeration over collections.
|
||||
*/
|
||||
struct enumerator_t {
|
||||
|
||||
/**
|
||||
* Enumerate collection.
|
||||
*
|
||||
* The enumerate function takes a variable argument list containing
|
||||
* pointers where the enumerated values get written.
|
||||
*
|
||||
* @param ... variable list of enumerated items, implementation dependent
|
||||
* @return TRUE if pointers returned
|
||||
*/
|
||||
bool (*enumerate)(enumerator_t *this, ...);
|
||||
|
||||
/**
|
||||
* Destroy a enumerator instance.
|
||||
*/
|
||||
void (*destroy)(enumerator_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an enumerator which enumerates over nothing
|
||||
*
|
||||
* @return an enumerator over no values
|
||||
*/
|
||||
enumerator_t* enumerator_create_empty();
|
||||
|
||||
/**
|
||||
* Create an enumerator which enumerates over a single item
|
||||
*
|
||||
* @param item item to enumerate
|
||||
* @param cleanup cleanup function called on destroy with the item
|
||||
* @return an enumerator over a single value
|
||||
*/
|
||||
enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item));
|
||||
|
||||
/**
|
||||
* Create an enumerator over files/subdirectories in a directory.
|
||||
*
|
||||
* This enumerator_t.enumerate() function returns a (to the directory) relative
|
||||
* filename (as a char*), an absolute filename (as a char*) and a file status
|
||||
* (to a struct stat), which all may be NULL. "." and ".." entries are
|
||||
* skipped. Example:
|
||||
*
|
||||
* @code
|
||||
char *rel, *abs;
|
||||
struct stat st;
|
||||
enumerator_t *e;
|
||||
|
||||
e = enumerator_create_directory("/tmp");
|
||||
if (e)
|
||||
{
|
||||
while (e->enumerate(e, &rel, &abs, &st))
|
||||
{
|
||||
if (S_ISDIR(st.st_mode) && *rel != '.')
|
||||
{
|
||||
printf("%s\n", abs);
|
||||
}
|
||||
}
|
||||
e->destroy(e);
|
||||
}
|
||||
@endcode
|
||||
*
|
||||
* @param path path of the directory
|
||||
* @return the directory enumerator, NULL on failure
|
||||
*/
|
||||
enumerator_t* enumerator_create_directory(const char *path);
|
||||
|
||||
/**
|
||||
* Create an enumerator over tokens of a string.
|
||||
*
|
||||
* Tokens are separated by one of the characters in sep and trimmed by the
|
||||
* characters in trim.
|
||||
*
|
||||
* @param string string to parse
|
||||
* @param sep separator characters
|
||||
* @param trim characters to trim from tokens
|
||||
* @return enumerator over char* tokens
|
||||
*/
|
||||
enumerator_t* enumerator_create_token(const char *string, const char *sep,
|
||||
const char *trim);
|
||||
|
||||
/**
|
||||
* Creates an enumerator which enumerates over enumerated enumerators :-).
|
||||
*
|
||||
* The variable argument list of enumeration values is limit to 5.
|
||||
*
|
||||
* @param outer outer enumerator
|
||||
* @param inner_constructor constructor to inner enumerator
|
||||
* @param data data to pass to each inner_constructor call
|
||||
* @param destroy_data destructor to pass to data
|
||||
* @return the nested enumerator
|
||||
*/
|
||||
enumerator_t *enumerator_create_nested(enumerator_t *outer,
|
||||
enumerator_t *(*inner_constructor)(void *outer, void *data),
|
||||
void *data, void (*destroy_data)(void *data));
|
||||
|
||||
/**
|
||||
* Creates an enumerator which filters output of another enumerator.
|
||||
*
|
||||
* The filter function receives the user supplied "data" followed by a
|
||||
* unfiltered enumeration item, followed by an output pointer where to write
|
||||
* the filtered data. Then the next input/output pair follows.
|
||||
* It returns TRUE to deliver the
|
||||
* values to the caller of enumerate(), FALSE to filter this enumeration.
|
||||
*
|
||||
* The variable argument list of enumeration values is limit to 5.
|
||||
*
|
||||
* @param unfiltered unfiltered enumerator to wrap, gets destroyed
|
||||
* @param filter filter function
|
||||
* @param data user data to supply to filter
|
||||
* @param destructor destructor function to clean up data after use
|
||||
* @return the filtered enumerator
|
||||
*/
|
||||
enumerator_t *enumerator_create_filter(enumerator_t *unfiltered,
|
||||
bool (*filter)(void *data, ...),
|
||||
void *data, void (*destructor)(void *data));
|
||||
|
||||
/**
|
||||
* Create an enumerator wrapper which does a cleanup on destroy.
|
||||
*
|
||||
* @param wrapped wrapped enumerator
|
||||
* @param cleanup cleanup function called on destroy
|
||||
* @param data user data to supply to cleanup
|
||||
* @return the enumerator with cleanup
|
||||
*/
|
||||
enumerator_t *enumerator_create_cleaner(enumerator_t *wrapped,
|
||||
void (*cleanup)(void *data), void *data);
|
||||
|
||||
#endif /** ENUMERATOR_H_ @}*/
|
||||
@@ -1,444 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2012 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "hashtable.h"
|
||||
|
||||
/** The maximum capacity of the hash table (MUST be a power of 2) */
|
||||
#define MAX_CAPACITY (1 << 30)
|
||||
|
||||
typedef struct pair_t pair_t;
|
||||
|
||||
/**
|
||||
* This pair holds a pointer to the key and value it represents.
|
||||
*/
|
||||
struct pair_t {
|
||||
/**
|
||||
* Key of a hash table item.
|
||||
*/
|
||||
void *key;
|
||||
|
||||
/**
|
||||
* Value of a hash table item.
|
||||
*/
|
||||
void *value;
|
||||
|
||||
/**
|
||||
* Cached hash (used in case of a resize).
|
||||
*/
|
||||
u_int hash;
|
||||
|
||||
/**
|
||||
* Next pair in an overflow list.
|
||||
*/
|
||||
pair_t *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty pair object.
|
||||
*/
|
||||
static inline pair_t *pair_create(void *key, void *value, u_int hash)
|
||||
{
|
||||
pair_t *this;
|
||||
|
||||
INIT(this,
|
||||
.key = key,
|
||||
.value = value,
|
||||
.hash = hash,
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
typedef struct private_hashtable_t private_hashtable_t;
|
||||
|
||||
/**
|
||||
* Private data of a hashtable_t object.
|
||||
*
|
||||
*/
|
||||
struct private_hashtable_t {
|
||||
/**
|
||||
* Public part of hash table.
|
||||
*/
|
||||
hashtable_t public;
|
||||
|
||||
/**
|
||||
* The number of items in the hash table.
|
||||
*/
|
||||
u_int count;
|
||||
|
||||
/**
|
||||
* The current capacity of the hash table (always a power of 2).
|
||||
*/
|
||||
u_int capacity;
|
||||
|
||||
/**
|
||||
* The current mask to calculate the row index (capacity - 1).
|
||||
*/
|
||||
u_int mask;
|
||||
|
||||
/**
|
||||
* The load factor.
|
||||
*/
|
||||
float load_factor;
|
||||
|
||||
/**
|
||||
* The actual table.
|
||||
*/
|
||||
pair_t **table;
|
||||
|
||||
/**
|
||||
* The hashing function.
|
||||
*/
|
||||
hashtable_hash_t hash;
|
||||
|
||||
/**
|
||||
* The equality function.
|
||||
*/
|
||||
hashtable_equals_t equals;
|
||||
};
|
||||
|
||||
typedef struct private_enumerator_t private_enumerator_t;
|
||||
|
||||
/**
|
||||
* hash table enumerator implementation
|
||||
*/
|
||||
struct private_enumerator_t {
|
||||
|
||||
/**
|
||||
* implements enumerator interface
|
||||
*/
|
||||
enumerator_t enumerator;
|
||||
|
||||
/**
|
||||
* associated hash table
|
||||
*/
|
||||
private_hashtable_t *table;
|
||||
|
||||
/**
|
||||
* current row index
|
||||
*/
|
||||
u_int row;
|
||||
|
||||
/**
|
||||
* number of remaining items in hashtable
|
||||
*/
|
||||
u_int count;
|
||||
|
||||
/**
|
||||
* current pair
|
||||
*/
|
||||
pair_t *current;
|
||||
|
||||
/**
|
||||
* previous pair (used by remove_at)
|
||||
*/
|
||||
pair_t *prev;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* This function returns the next-highest power of two for the given number.
|
||||
* The algorithm works by setting all bits on the right-hand side of the most
|
||||
* significant 1 to 1 and then increments the whole number so it rolls over
|
||||
* to the nearest power of two. Note: returns 0 for n == 0
|
||||
*/
|
||||
static u_int get_nearest_powerof2(u_int n)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
--n;
|
||||
for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
|
||||
{
|
||||
n |= n >> i;
|
||||
}
|
||||
return ++n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init hash table parameters
|
||||
*/
|
||||
static void init_hashtable(private_hashtable_t *this, u_int capacity)
|
||||
{
|
||||
capacity = max(1, min(capacity, MAX_CAPACITY));
|
||||
this->capacity = get_nearest_powerof2(capacity);
|
||||
this->mask = this->capacity - 1;
|
||||
this->load_factor = 0.75;
|
||||
|
||||
this->table = calloc(this->capacity, sizeof(pair_t*));
|
||||
}
|
||||
|
||||
/**
|
||||
* Double the size of the hash table and rehash all the elements.
|
||||
*/
|
||||
static void rehash(private_hashtable_t *this)
|
||||
{
|
||||
pair_t **old_table;
|
||||
u_int row, old_capacity;
|
||||
|
||||
if (this->capacity >= MAX_CAPACITY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
old_capacity = this->capacity;
|
||||
old_table = this->table;
|
||||
|
||||
init_hashtable(this, old_capacity << 1);
|
||||
|
||||
for (row = 0; row < old_capacity; row++)
|
||||
{
|
||||
pair_t *pair, *next;
|
||||
u_int new_row;
|
||||
|
||||
pair = old_table[row];
|
||||
while (pair)
|
||||
{ /* insert pair at the front of new bucket*/
|
||||
next = pair->next;
|
||||
new_row = pair->hash & this->mask;
|
||||
pair->next = this->table[new_row];
|
||||
this->table[new_row] = pair;
|
||||
pair = next;
|
||||
}
|
||||
}
|
||||
free(old_table);
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, put, void*,
|
||||
private_hashtable_t *this, void *key, void *value)
|
||||
{
|
||||
void *old_value = NULL;
|
||||
pair_t *pair;
|
||||
u_int hash, row;
|
||||
|
||||
hash = this->hash(key);
|
||||
row = hash & this->mask;
|
||||
pair = this->table[row];
|
||||
while (pair)
|
||||
{ /* search existing bucket for key */
|
||||
if (this->equals(key, pair->key))
|
||||
{
|
||||
old_value = pair->value;
|
||||
pair->value = value;
|
||||
pair->key = key;
|
||||
break;
|
||||
}
|
||||
pair = pair->next;
|
||||
}
|
||||
if (!pair)
|
||||
{ /* insert at the front of bucket */
|
||||
pair = pair_create(key, value, hash);
|
||||
pair->next = this->table[row];
|
||||
this->table[row] = pair;
|
||||
this->count++;
|
||||
}
|
||||
if (this->count >= this->capacity * this->load_factor)
|
||||
{
|
||||
rehash(this);
|
||||
}
|
||||
return old_value;
|
||||
}
|
||||
|
||||
static void *get_internal(private_hashtable_t *this, void *key,
|
||||
hashtable_equals_t equals)
|
||||
{
|
||||
void *value = NULL;
|
||||
pair_t *pair;
|
||||
|
||||
if (!this->count)
|
||||
{ /* no need to calculate the hash */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pair = this->table[this->hash(key) & this->mask];
|
||||
while (pair)
|
||||
{
|
||||
if (equals(key, pair->key))
|
||||
{
|
||||
value = pair->value;
|
||||
break;
|
||||
}
|
||||
pair = pair->next;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, get, void*,
|
||||
private_hashtable_t *this, void *key)
|
||||
{
|
||||
return get_internal(this, key, this->equals);
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, get_match, void*,
|
||||
private_hashtable_t *this, void *key, hashtable_equals_t match)
|
||||
{
|
||||
return get_internal(this, key, match);
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, remove_, void*,
|
||||
private_hashtable_t *this, void *key)
|
||||
{
|
||||
void *value = NULL;
|
||||
pair_t *pair, *prev = NULL;
|
||||
u_int row;
|
||||
|
||||
row = this->hash(key) & this->mask;
|
||||
pair = this->table[row];
|
||||
while (pair)
|
||||
{
|
||||
if (this->equals(key, pair->key))
|
||||
{
|
||||
if (prev)
|
||||
{
|
||||
prev->next = pair->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->table[row] = pair->next;
|
||||
}
|
||||
value = pair->value;
|
||||
this->count--;
|
||||
free(pair);
|
||||
break;
|
||||
}
|
||||
prev = pair;
|
||||
pair = pair->next;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, remove_at, void,
|
||||
private_hashtable_t *this, private_enumerator_t *enumerator)
|
||||
{
|
||||
if (enumerator->table == this && enumerator->current)
|
||||
{
|
||||
pair_t *current = enumerator->current;
|
||||
if (enumerator->prev)
|
||||
{
|
||||
enumerator->prev->next = current->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->table[enumerator->row] = current->next;
|
||||
}
|
||||
enumerator->current = enumerator->prev;
|
||||
free(current);
|
||||
this->count--;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, get_count, u_int,
|
||||
private_hashtable_t *this)
|
||||
{
|
||||
return this->count;
|
||||
}
|
||||
|
||||
METHOD(enumerator_t, enumerate, bool,
|
||||
private_enumerator_t *this, void **key, void **value)
|
||||
{
|
||||
while (this->count && this->row < this->table->capacity)
|
||||
{
|
||||
this->prev = this->current;
|
||||
if (this->current)
|
||||
{
|
||||
this->current = this->current->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current = this->table->table[this->row];
|
||||
}
|
||||
if (this->current)
|
||||
{
|
||||
if (key)
|
||||
{
|
||||
*key = this->current->key;
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
*value = this->current->value;
|
||||
}
|
||||
this->count--;
|
||||
return TRUE;
|
||||
}
|
||||
this->row++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, create_enumerator, enumerator_t*,
|
||||
private_hashtable_t *this)
|
||||
{
|
||||
private_enumerator_t *enumerator;
|
||||
|
||||
INIT(enumerator,
|
||||
.enumerator = {
|
||||
.enumerate = (void*)_enumerate,
|
||||
.destroy = (void*)free,
|
||||
},
|
||||
.table = this,
|
||||
.count = this->count,
|
||||
);
|
||||
|
||||
return &enumerator->enumerator;
|
||||
}
|
||||
|
||||
METHOD(hashtable_t, destroy, void,
|
||||
private_hashtable_t *this)
|
||||
{
|
||||
pair_t *pair, *next;
|
||||
u_int row;
|
||||
|
||||
for (row = 0; row < this->capacity; row++)
|
||||
{
|
||||
pair = this->table[row];
|
||||
while (pair)
|
||||
{
|
||||
next = pair->next;
|
||||
free(pair);
|
||||
pair = next;
|
||||
}
|
||||
}
|
||||
free(this->table);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
|
||||
u_int capacity)
|
||||
{
|
||||
private_hashtable_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.put = _put,
|
||||
.get = _get,
|
||||
.get_match = _get_match,
|
||||
.remove = _remove_,
|
||||
.remove_at = (void*)_remove_at,
|
||||
.get_count = _get_count,
|
||||
.create_enumerator = _create_enumerator,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.hash = hash,
|
||||
.equals = equals,
|
||||
);
|
||||
|
||||
init_hashtable(this, capacity);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2012 Tobias Brunner
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup hashtable hashtable
|
||||
* @{ @ingroup utils
|
||||
*/
|
||||
|
||||
#ifndef HASHTABLE_H_
|
||||
#define HASHTABLE_H_
|
||||
|
||||
#include <utils/enumerator.h>
|
||||
|
||||
typedef struct hashtable_t hashtable_t;
|
||||
|
||||
/**
|
||||
* Prototype for a function that computes the hash code from the given key.
|
||||
*
|
||||
* @param key key to hash
|
||||
* @return hash code
|
||||
*/
|
||||
typedef u_int (*hashtable_hash_t)(void *key);
|
||||
|
||||
/**
|
||||
* Prototype for a function that compares the two keys for equality.
|
||||
*
|
||||
* @param key first key (the one we are looking for)
|
||||
* @param other_key second key
|
||||
* @return TRUE if the keys are equal
|
||||
*/
|
||||
typedef bool (*hashtable_equals_t)(void *key, void *other_key);
|
||||
|
||||
/**
|
||||
* Class implementing a hash table.
|
||||
*
|
||||
* General purpose hash table. This hash table is not synchronized.
|
||||
*/
|
||||
struct hashtable_t {
|
||||
|
||||
/**
|
||||
* Create an enumerator over the hash table key/value pairs.
|
||||
*
|
||||
* @return enumerator over (void *key, void *value)
|
||||
*/
|
||||
enumerator_t *(*create_enumerator) (hashtable_t *this);
|
||||
|
||||
/**
|
||||
* Adds the given value with the given key to the hash table, if there
|
||||
* exists no entry with that key. NULL is returned in this case.
|
||||
* Otherwise the existing value is replaced and the function returns the
|
||||
* old value.
|
||||
*
|
||||
* @param key the key to store
|
||||
* @param value the value to store
|
||||
* @return NULL if no item was replaced, the old value otherwise
|
||||
*/
|
||||
void *(*put) (hashtable_t *this, void *key, void *value);
|
||||
|
||||
/**
|
||||
* Returns the value with the given key, if the hash table contains such an
|
||||
* entry, otherwise NULL is returned.
|
||||
*
|
||||
* @param key the key of the requested value
|
||||
* @return the value, NULL if not found
|
||||
*/
|
||||
void *(*get) (hashtable_t *this, void *key);
|
||||
|
||||
/**
|
||||
* Returns the value with a matching key, if the hash table contains such an
|
||||
* entry, otherwise NULL is returned.
|
||||
*
|
||||
* Compared to get() the given match function is used to compare the keys
|
||||
* for equality. The hash function does have to be deviced properly in
|
||||
* order to make this work if the match function compares keys differently
|
||||
* than the equals function provided to the constructor. This basically
|
||||
* allows to enumerate all entries with the same hash value.
|
||||
*
|
||||
* @param key the key to match against
|
||||
* @param match match function to be used when comparing keys
|
||||
* @return the value, NULL if not found
|
||||
*/
|
||||
void *(*get_match) (hashtable_t *this, void *key, hashtable_equals_t match);
|
||||
|
||||
/**
|
||||
* Removes the value with the given key from the hash table and returns the
|
||||
* removed value (or NULL if no such value existed).
|
||||
*
|
||||
* @param key the key of the value to remove
|
||||
* @return the removed value, NULL if not found
|
||||
*/
|
||||
void *(*remove) (hashtable_t *this, void *key);
|
||||
|
||||
/**
|
||||
* Removes the key and value pair from the hash table at which the given
|
||||
* enumerator currently points.
|
||||
*
|
||||
* @param enumerator enumerator, from create_enumerator
|
||||
*/
|
||||
void (*remove_at) (hashtable_t *this, enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Gets the number of items in the hash table.
|
||||
*
|
||||
* @return number of items
|
||||
*/
|
||||
u_int (*get_count) (hashtable_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a hash table object.
|
||||
*/
|
||||
void (*destroy) (hashtable_t *this);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty hash table object.
|
||||
*
|
||||
* @param hash hash function
|
||||
* @param equals equals function
|
||||
* @param capacity initial capacity
|
||||
* @return hashtable_t object.
|
||||
*/
|
||||
hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
|
||||
u_int capacity);
|
||||
|
||||
#endif /** HASHTABLE_H_ @}*/
|
||||
@@ -30,7 +30,7 @@ typedef enum id_match_t id_match_t;
|
||||
typedef enum id_part_t id_part_t;
|
||||
|
||||
#include <chunk.h>
|
||||
#include <utils/enumerator.h>
|
||||
#include <collections/enumerator.h>
|
||||
|
||||
/**
|
||||
* Matches returned from identification_t.match
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <utils/backtrace.h>
|
||||
#include <utils/hashtable.h>
|
||||
#include <collections/hashtable.h>
|
||||
|
||||
typedef struct private_leak_detective_t private_leak_detective_t;
|
||||
|
||||
|
||||
@@ -1,615 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Tobias Brunner
|
||||
* Copyright (C) 2005-2006 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "linked_list.h"
|
||||
|
||||
typedef struct element_t element_t;
|
||||
|
||||
/**
|
||||
* This element holds a pointer to the value it represents.
|
||||
*/
|
||||
struct element_t {
|
||||
|
||||
/**
|
||||
* Value of a list item.
|
||||
*/
|
||||
void *value;
|
||||
|
||||
/**
|
||||
* Previous list element.
|
||||
*
|
||||
* NULL if first element in list.
|
||||
*/
|
||||
element_t *previous;
|
||||
|
||||
/**
|
||||
* Next list element.
|
||||
*
|
||||
* NULL if last element in list.
|
||||
*/
|
||||
element_t *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty linked list object.
|
||||
*/
|
||||
element_t *element_create(void *value)
|
||||
{
|
||||
element_t *this;
|
||||
INIT(this,
|
||||
.value = value,
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
typedef struct private_linked_list_t private_linked_list_t;
|
||||
|
||||
/**
|
||||
* Private data of a linked_list_t object.
|
||||
*
|
||||
*/
|
||||
struct private_linked_list_t {
|
||||
/**
|
||||
* Public part of linked list.
|
||||
*/
|
||||
linked_list_t public;
|
||||
|
||||
/**
|
||||
* Number of items in the list.
|
||||
*/
|
||||
int count;
|
||||
|
||||
/**
|
||||
* First element in list.
|
||||
* NULL if no elements in list.
|
||||
*/
|
||||
element_t *first;
|
||||
|
||||
/**
|
||||
* Last element in list.
|
||||
* NULL if no elements in list.
|
||||
*/
|
||||
element_t *last;
|
||||
};
|
||||
|
||||
typedef struct private_enumerator_t private_enumerator_t;
|
||||
|
||||
/**
|
||||
* linked lists enumerator implementation
|
||||
*/
|
||||
struct private_enumerator_t {
|
||||
|
||||
/**
|
||||
* implements enumerator interface
|
||||
*/
|
||||
enumerator_t enumerator;
|
||||
|
||||
/**
|
||||
* associated linked list
|
||||
*/
|
||||
private_linked_list_t *list;
|
||||
|
||||
/**
|
||||
* current item
|
||||
*/
|
||||
element_t *current;
|
||||
|
||||
/**
|
||||
* enumerator has enumerated all items
|
||||
*/
|
||||
bool finished;
|
||||
};
|
||||
|
||||
METHOD(enumerator_t, enumerate, bool,
|
||||
private_enumerator_t *this, void **item)
|
||||
{
|
||||
if (this->finished)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (!this->current)
|
||||
{
|
||||
this->current = this->list->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->current = this->current->next;
|
||||
}
|
||||
if (!this->current)
|
||||
{
|
||||
this->finished = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
*item = this->current->value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, create_enumerator, enumerator_t*,
|
||||
private_linked_list_t *this)
|
||||
{
|
||||
private_enumerator_t *enumerator;
|
||||
|
||||
INIT(enumerator,
|
||||
.enumerator = {
|
||||
.enumerate = (void*)_enumerate,
|
||||
.destroy = (void*)free,
|
||||
},
|
||||
.list = this,
|
||||
);
|
||||
|
||||
return &enumerator->enumerator;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, reset_enumerator, void,
|
||||
private_linked_list_t *this, private_enumerator_t *enumerator)
|
||||
{
|
||||
enumerator->current = NULL;
|
||||
enumerator->finished = FALSE;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, has_more, bool,
|
||||
private_linked_list_t *this, private_enumerator_t *enumerator)
|
||||
{
|
||||
if (enumerator->current)
|
||||
{
|
||||
return enumerator->current->next != NULL;
|
||||
}
|
||||
return !enumerator->finished && this->first != NULL;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, get_count, int,
|
||||
private_linked_list_t *this)
|
||||
{
|
||||
return this->count;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, insert_first, void,
|
||||
private_linked_list_t *this, void *item)
|
||||
{
|
||||
element_t *element;
|
||||
|
||||
element = element_create(item);
|
||||
if (this->count == 0)
|
||||
{
|
||||
/* first entry in list */
|
||||
this->first = element;
|
||||
this->last = element;
|
||||
}
|
||||
else
|
||||
{
|
||||
element->next = this->first;
|
||||
this->first->previous = element;
|
||||
this->first = element;
|
||||
}
|
||||
this->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* unlink an element form the list, returns following element
|
||||
*/
|
||||
static element_t* remove_element(private_linked_list_t *this,
|
||||
element_t *element)
|
||||
{
|
||||
element_t *next, *previous;
|
||||
|
||||
next = element->next;
|
||||
previous = element->previous;
|
||||
free(element);
|
||||
if (next)
|
||||
{
|
||||
next->previous = previous;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->last = previous;
|
||||
}
|
||||
if (previous)
|
||||
{
|
||||
previous->next = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->first = next;
|
||||
}
|
||||
if (--this->count == 0)
|
||||
{
|
||||
this->first = NULL;
|
||||
this->last = NULL;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, get_first, status_t,
|
||||
private_linked_list_t *this, void **item)
|
||||
{
|
||||
if (this->count == 0)
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
*item = this->first->value;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, remove_first, status_t,
|
||||
private_linked_list_t *this, void **item)
|
||||
{
|
||||
if (get_first(this, item) == SUCCESS)
|
||||
{
|
||||
remove_element(this, this->first);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, insert_last, void,
|
||||
private_linked_list_t *this, void *item)
|
||||
{
|
||||
element_t *element;
|
||||
|
||||
element = element_create(item);
|
||||
if (this->count == 0)
|
||||
{
|
||||
/* first entry in list */
|
||||
this->first = element;
|
||||
this->last = element;
|
||||
}
|
||||
else
|
||||
{
|
||||
element->previous = this->last;
|
||||
this->last->next = element;
|
||||
this->last = element;
|
||||
}
|
||||
this->count++;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, insert_before, void,
|
||||
private_linked_list_t *this, private_enumerator_t *enumerator,
|
||||
void *item)
|
||||
{
|
||||
element_t *current, *element;
|
||||
|
||||
current = enumerator->current;
|
||||
if (!current)
|
||||
{
|
||||
if (enumerator->finished)
|
||||
{
|
||||
this->public.insert_last(&this->public, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->public.insert_first(&this->public, item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
element = element_create(item);
|
||||
if (current->previous)
|
||||
{
|
||||
current->previous->next = element;
|
||||
element->previous = current->previous;
|
||||
current->previous = element;
|
||||
element->next = current;
|
||||
}
|
||||
else
|
||||
{
|
||||
current->previous = element;
|
||||
element->next = current;
|
||||
this->first = element;
|
||||
}
|
||||
this->count++;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, replace, void*,
|
||||
private_linked_list_t *this, private_enumerator_t *enumerator,
|
||||
void *item)
|
||||
{
|
||||
void *old = NULL;
|
||||
|
||||
if (enumerator->current)
|
||||
{
|
||||
old = enumerator->current->value;
|
||||
enumerator->current->value = item;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, get_last, status_t,
|
||||
private_linked_list_t *this, void **item)
|
||||
{
|
||||
if (this->count == 0)
|
||||
{
|
||||
return NOT_FOUND;
|
||||
}
|
||||
*item = this->last->value;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, remove_last, status_t,
|
||||
private_linked_list_t *this, void **item)
|
||||
{
|
||||
if (get_last(this, item) == SUCCESS)
|
||||
{
|
||||
remove_element(this, this->last);
|
||||
return SUCCESS;
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, remove_, int,
|
||||
private_linked_list_t *this, void *item, bool (*compare)(void*,void*))
|
||||
{
|
||||
element_t *current = this->first;
|
||||
int removed = 0;
|
||||
|
||||
while (current)
|
||||
{
|
||||
if ((compare && compare(current->value, item)) ||
|
||||
(!compare && current->value == item))
|
||||
{
|
||||
removed++;
|
||||
current = remove_element(this, current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, remove_at, void,
|
||||
private_linked_list_t *this, private_enumerator_t *enumerator)
|
||||
{
|
||||
element_t *current;
|
||||
|
||||
if (enumerator->current)
|
||||
{
|
||||
current = enumerator->current;
|
||||
enumerator->current = current->previous;
|
||||
remove_element(this, current);
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, find_first, status_t,
|
||||
private_linked_list_t *this, linked_list_match_t match,
|
||||
void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
|
||||
{
|
||||
element_t *current = this->first;
|
||||
|
||||
while (current)
|
||||
{
|
||||
if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
|
||||
(!match && item && current->value == *item))
|
||||
{
|
||||
if (item != NULL)
|
||||
{
|
||||
*item = current->value;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, find_last, status_t,
|
||||
private_linked_list_t *this, linked_list_match_t match,
|
||||
void **item, void *d1, void *d2, void *d3, void *d4, void *d5)
|
||||
{
|
||||
element_t *current = this->last;
|
||||
|
||||
while (current)
|
||||
{
|
||||
if ((match && match(current->value, d1, d2, d3, d4, d5)) ||
|
||||
(!match && item && current->value == *item))
|
||||
{
|
||||
if (item != NULL)
|
||||
{
|
||||
*item = current->value;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
current = current->previous;
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, invoke_offset, void,
|
||||
private_linked_list_t *this, size_t offset,
|
||||
void *d1, void *d2, void *d3, void *d4, void *d5)
|
||||
{
|
||||
element_t *current = this->first;
|
||||
linked_list_invoke_t *method;
|
||||
|
||||
while (current)
|
||||
{
|
||||
method = current->value + offset;
|
||||
(*method)(current->value, d1, d2, d3, d4, d5);
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, invoke_function, void,
|
||||
private_linked_list_t *this, linked_list_invoke_t fn,
|
||||
void *d1, void *d2, void *d3, void *d4, void *d5)
|
||||
{
|
||||
element_t *current = this->first;
|
||||
|
||||
while (current)
|
||||
{
|
||||
fn(current->value, d1, d2, d3, d4, d5);
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, clone_offset, linked_list_t*,
|
||||
private_linked_list_t *this, size_t offset)
|
||||
{
|
||||
element_t *current = this->first;
|
||||
linked_list_t *clone;
|
||||
|
||||
clone = linked_list_create();
|
||||
while (current)
|
||||
{
|
||||
void* (**method)(void*) = current->value + offset;
|
||||
clone->insert_last(clone, (*method)(current->value));
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, clone_function, linked_list_t*,
|
||||
private_linked_list_t *this, void* (*fn)(void*))
|
||||
{
|
||||
element_t *current = this->first;
|
||||
linked_list_t *clone;
|
||||
|
||||
clone = linked_list_create();
|
||||
while (current)
|
||||
{
|
||||
clone->insert_last(clone, fn(current->value));
|
||||
current = current->next;
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, destroy, void,
|
||||
private_linked_list_t *this)
|
||||
{
|
||||
void *value;
|
||||
|
||||
/* Remove all list items before destroying list */
|
||||
while (remove_first(this, &value) == SUCCESS)
|
||||
{
|
||||
/* values are not destroyed so memory leaks are possible
|
||||
* if list is not empty when deleting */
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, destroy_offset, void,
|
||||
private_linked_list_t *this, size_t offset)
|
||||
{
|
||||
element_t *current = this->first, *next;
|
||||
|
||||
while (current)
|
||||
{
|
||||
void (**method)(void*) = current->value + offset;
|
||||
(*method)(current->value);
|
||||
next = current->next;
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
METHOD(linked_list_t, destroy_function, void,
|
||||
private_linked_list_t *this, void (*fn)(void*))
|
||||
{
|
||||
element_t *current = this->first, *next;
|
||||
|
||||
while (current)
|
||||
{
|
||||
fn(current->value);
|
||||
next = current->next;
|
||||
free(current);
|
||||
current = next;
|
||||
}
|
||||
free(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Described in header.
|
||||
*/
|
||||
linked_list_t *linked_list_create()
|
||||
{
|
||||
private_linked_list_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_count = _get_count,
|
||||
.create_enumerator = _create_enumerator,
|
||||
.reset_enumerator = (void*)_reset_enumerator,
|
||||
.has_more = (void*)_has_more,
|
||||
.get_first = _get_first,
|
||||
.get_last = _get_last,
|
||||
.find_first = (void*)_find_first,
|
||||
.find_last = (void*)_find_last,
|
||||
.insert_first = _insert_first,
|
||||
.insert_last = _insert_last,
|
||||
.insert_before = (void*)_insert_before,
|
||||
.replace = (void*)_replace,
|
||||
.remove_first = _remove_first,
|
||||
.remove_last = _remove_last,
|
||||
.remove = _remove_,
|
||||
.remove_at = (void*)_remove_at,
|
||||
.invoke_offset = (void*)_invoke_offset,
|
||||
.invoke_function = (void*)_invoke_function,
|
||||
.clone_offset = _clone_offset,
|
||||
.clone_function = _clone_function,
|
||||
.destroy = _destroy,
|
||||
.destroy_offset = _destroy_offset,
|
||||
.destroy_function = _destroy_function,
|
||||
},
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
/*
|
||||
* See header.
|
||||
*/
|
||||
linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator)
|
||||
{
|
||||
linked_list_t *list;
|
||||
void *item;
|
||||
|
||||
list = linked_list_create();
|
||||
|
||||
while (enumerator->enumerate(enumerator, &item))
|
||||
{
|
||||
list->insert_last(list, item);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
* See header.
|
||||
*/
|
||||
linked_list_t *linked_list_create_with_items(void *item, ...)
|
||||
{
|
||||
linked_list_t *list;
|
||||
va_list args;
|
||||
|
||||
list = linked_list_create();
|
||||
|
||||
va_start(args, item);
|
||||
while (item)
|
||||
{
|
||||
list->insert_last(list, item);
|
||||
item = va_arg(args, void*);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Tobias Brunner
|
||||
* Copyright (C) 2005-2008 Martin Willi
|
||||
* Copyright (C) 2005 Jan Hutter
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup linked_list linked_list
|
||||
* @{ @ingroup utils
|
||||
*/
|
||||
|
||||
#ifndef LINKED_LIST_H_
|
||||
#define LINKED_LIST_H_
|
||||
|
||||
typedef struct linked_list_t linked_list_t;
|
||||
|
||||
#include <utils/enumerator.h>
|
||||
|
||||
/**
|
||||
* Method to match elements in a linked list (used in find_* functions)
|
||||
*
|
||||
* @param item current list item
|
||||
* @param ... user supplied data (only pointers, at most 5)
|
||||
* @return
|
||||
* - TRUE, if the item matched
|
||||
* - FALSE, otherwise
|
||||
*/
|
||||
typedef bool (*linked_list_match_t)(void *item, ...);
|
||||
|
||||
/**
|
||||
* Method to be invoked on elements in a linked list (used in invoke_* functions)
|
||||
*
|
||||
* @param item current list item
|
||||
* @param ... user supplied data (only pointers, at most 5)
|
||||
*/
|
||||
typedef void (*linked_list_invoke_t)(void *item, ...);
|
||||
|
||||
/**
|
||||
* Class implementing a double linked list.
|
||||
*
|
||||
* General purpose linked list. This list is not synchronized.
|
||||
*/
|
||||
struct linked_list_t {
|
||||
|
||||
/**
|
||||
* Gets the count of items in the list.
|
||||
*
|
||||
* @return number of items in list
|
||||
*/
|
||||
int (*get_count) (linked_list_t *this);
|
||||
|
||||
/**
|
||||
* Create an enumerator over the list.
|
||||
*
|
||||
* @note The enumerator's position is invalid before the first call
|
||||
* to enumerate().
|
||||
*
|
||||
* @return enumerator over list items
|
||||
*/
|
||||
enumerator_t* (*create_enumerator)(linked_list_t *this);
|
||||
|
||||
/**
|
||||
* Resets the enumerator's current position to the beginning of the list.
|
||||
*
|
||||
* @param enumerator enumerator to reset
|
||||
*/
|
||||
void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Checks if there are more elements following after the enumerator's
|
||||
* current position.
|
||||
*
|
||||
* @param enumerator enumerator to check
|
||||
*/
|
||||
bool (*has_more)(linked_list_t *this, enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Inserts a new item at the beginning of the list.
|
||||
*
|
||||
* @param item item value to insert in list
|
||||
*/
|
||||
void (*insert_first) (linked_list_t *this, void *item);
|
||||
|
||||
/**
|
||||
* Removes the first item in the list and returns its value.
|
||||
*
|
||||
* @param item returned value of first item, or NULL
|
||||
* @return SUCCESS, or NOT_FOUND if list is empty
|
||||
*/
|
||||
status_t (*remove_first) (linked_list_t *this, void **item);
|
||||
|
||||
/**
|
||||
* Inserts a new item before the item the enumerator currently points to.
|
||||
*
|
||||
* If this method is called before starting the enumeration the item is
|
||||
* inserted first. If it is called after all items have been enumerated
|
||||
* the item is inserted last. This is helpful when inserting items into
|
||||
* a sorted list.
|
||||
*
|
||||
* @note The position of the enumerator is not changed.
|
||||
*
|
||||
* @param enumerator enumerator with position
|
||||
* @param item item value to insert in list
|
||||
*/
|
||||
void (*insert_before)(linked_list_t *this, enumerator_t *enumerator,
|
||||
void *item);
|
||||
|
||||
/**
|
||||
* Replaces the item the enumerator currently points to with the given item.
|
||||
*
|
||||
* @param enumerator enumerator with position
|
||||
* @param item item value to replace current item with
|
||||
* @return current item or NULL if the enumerator is at an
|
||||
* invalid position
|
||||
*/
|
||||
void *(*replace)(linked_list_t *this, enumerator_t *enumerator, void *item);
|
||||
|
||||
/**
|
||||
* Remove an item from the list where the enumerator points to.
|
||||
*
|
||||
* @param enumerator enumerator with position
|
||||
*/
|
||||
void (*remove_at)(linked_list_t *this, enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Remove items from the list matching the given item.
|
||||
*
|
||||
* If a compare function is given, it is called for each item, with the
|
||||
* first parameter being the current list item and the second parameter
|
||||
* being the supplied item. Return TRUE from the compare function to remove
|
||||
* the item, return FALSE to keep it in the list.
|
||||
*
|
||||
* If compare is NULL, comparison is done by pointers.
|
||||
*
|
||||
* @param item item to remove/pass to comparator
|
||||
* @param compare compare function, or NULL
|
||||
* @return number of removed items
|
||||
*/
|
||||
int (*remove)(linked_list_t *this, void *item, bool (*compare)(void*,void*));
|
||||
|
||||
/**
|
||||
* Returns the value of the first list item without removing it.
|
||||
*
|
||||
* @param item returned value of first item
|
||||
* @return SUCCESS, NOT_FOUND if list is empty
|
||||
*/
|
||||
status_t (*get_first) (linked_list_t *this, void **item);
|
||||
|
||||
/**
|
||||
* Inserts a new item at the end of the list.
|
||||
*
|
||||
* @param item value to insert into list
|
||||
*/
|
||||
void (*insert_last) (linked_list_t *this, void *item);
|
||||
|
||||
/**
|
||||
* Removes the last item in the list and returns its value.
|
||||
*
|
||||
* @param item returned value of last item, or NULL
|
||||
* @return SUCCESS, NOT_FOUND if list is empty
|
||||
*/
|
||||
status_t (*remove_last) (linked_list_t *this, void **item);
|
||||
|
||||
/**
|
||||
* Returns the value of the last list item without removing it.
|
||||
*
|
||||
* @param item returned value of last item
|
||||
* @return SUCCESS, NOT_FOUND if list is empty
|
||||
*/
|
||||
status_t (*get_last) (linked_list_t *this, void **item);
|
||||
|
||||
/** Find the first matching element in the list.
|
||||
*
|
||||
* The first object passed to the match function is the current list item,
|
||||
* followed by the user supplied data.
|
||||
* If the supplied function returns TRUE this function returns SUCCESS, and
|
||||
* the current object is returned in the third parameter, otherwise,
|
||||
* the next item is checked.
|
||||
*
|
||||
* If match is NULL, *item and the current object are compared.
|
||||
*
|
||||
* @warning Only use pointers as user supplied data.
|
||||
*
|
||||
* @param match comparison function to call on each object, or NULL
|
||||
* @param item the list item, if found
|
||||
* @param ... user data to supply to match function (limited to 5 arguments)
|
||||
* @return SUCCESS if found, NOT_FOUND otherwise
|
||||
*/
|
||||
status_t (*find_first) (linked_list_t *this, linked_list_match_t match,
|
||||
void **item, ...);
|
||||
|
||||
/** Find the last matching element in the list.
|
||||
*
|
||||
* The first object passed to the match function is the current list item,
|
||||
* followed by the user supplied data.
|
||||
* If the supplied function returns TRUE this function returns SUCCESS, and
|
||||
* the current object is returned in the third parameter, otherwise,
|
||||
* the next item is checked.
|
||||
*
|
||||
* If match is NULL, *item and the current object are compared.
|
||||
*
|
||||
* @warning Only use pointers as user supplied data.
|
||||
*
|
||||
* @param match comparison function to call on each object, or NULL
|
||||
* @param item the list item, if found
|
||||
* @param ... user data to supply to match function (limited to 5 arguments)
|
||||
* @return SUCCESS if found, NOT_FOUND otherwise
|
||||
*/
|
||||
status_t (*find_last) (linked_list_t *this, linked_list_match_t match,
|
||||
void **item, ...);
|
||||
|
||||
/**
|
||||
* Invoke a method on all of the contained objects.
|
||||
*
|
||||
* If a linked list contains objects with function pointers,
|
||||
* invoke() can call a method on each of the objects. The
|
||||
* method is specified by an offset of the function pointer,
|
||||
* which can be evalutated at compile time using the offsetof
|
||||
* macro, e.g.: list->invoke(list, offsetof(object_t, method));
|
||||
*
|
||||
* @warning Only use pointers as user supplied data.
|
||||
*
|
||||
* @param offset offset of the method to invoke on objects
|
||||
* @param ... user data to supply to called function (limited to 5 arguments)
|
||||
*/
|
||||
void (*invoke_offset) (linked_list_t *this, size_t offset, ...);
|
||||
|
||||
/**
|
||||
* Invoke a function on all of the contained objects.
|
||||
*
|
||||
* @warning Only use pointers as user supplied data.
|
||||
*
|
||||
* @param function offset of the method to invoke on objects
|
||||
* @param ... user data to supply to called function (limited to 5 arguments)
|
||||
*/
|
||||
void (*invoke_function) (linked_list_t *this, linked_list_invoke_t function, ...);
|
||||
|
||||
/**
|
||||
* Clones a list and its objects using the objects' clone method.
|
||||
*
|
||||
* @param offset offset ot the objects clone function
|
||||
* @return cloned list
|
||||
*/
|
||||
linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset);
|
||||
|
||||
/**
|
||||
* Clones a list and its objects using a given function.
|
||||
*
|
||||
* @param function function that clones an object
|
||||
* @return cloned list
|
||||
*/
|
||||
linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*));
|
||||
|
||||
/**
|
||||
* Destroys a linked_list object.
|
||||
*/
|
||||
void (*destroy) (linked_list_t *this);
|
||||
|
||||
/**
|
||||
* Destroys a list and its objects using the destructor.
|
||||
*
|
||||
* If a linked list and the contained objects should be destroyed, use
|
||||
* destroy_offset. The supplied offset specifies the destructor to
|
||||
* call on each object. The offset may be calculated using the offsetof
|
||||
* macro, e.g.: list->destroy_offset(list, offsetof(object_t, destroy));
|
||||
*
|
||||
* @param offset offset of the objects destructor
|
||||
*/
|
||||
void (*destroy_offset) (linked_list_t *this, size_t offset);
|
||||
|
||||
/**
|
||||
* Destroys a list and its contents using a a cleanup function.
|
||||
*
|
||||
* If a linked list and its contents should get destroyed using a specific
|
||||
* cleanup function, use destroy_function. This is useful when the
|
||||
* list contains malloc()-ed blocks which should get freed,
|
||||
* e.g.: list->destroy_function(list, free);
|
||||
*
|
||||
* @param function function to call on each object
|
||||
*/
|
||||
void (*destroy_function) (linked_list_t *this, void (*)(void*));
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an empty linked list object.
|
||||
*
|
||||
* @return linked_list_t object.
|
||||
*/
|
||||
linked_list_t *linked_list_create(void);
|
||||
|
||||
/**
|
||||
* Creates a linked list from an enumerator.
|
||||
*
|
||||
* @param enumerator enumerator over void*, gets destroyed
|
||||
* @return linked_list_t object, containing enumerated values
|
||||
*/
|
||||
linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator);
|
||||
|
||||
/**
|
||||
* Creates a linked list from a NULL terminated vararg list of items.
|
||||
*
|
||||
* @param first first item
|
||||
* @param ... subsequent items, terminated by NULL
|
||||
* @return linked_list_t object, containing passed items
|
||||
*/
|
||||
linked_list_t *linked_list_create_with_items(void *first, ...);
|
||||
|
||||
#endif /** LINKED_LIST_H_ @}*/
|
||||
Reference in New Issue
Block a user