implemented more flexible iterator hook API

kernel interface handles interface changes and updates address list
This commit is contained in:
Martin Willi
2007-06-15 13:23:18 +00:00
parent 02b3ec0a10
commit 08a8f4496f
5 changed files with 439 additions and 255 deletions
+37 -5
View File
@@ -26,15 +26,46 @@
#include <library.h>
typedef enum hook_result_t hook_result_t;
/**
* @brief Return value of an iterator hook.
*
* Returning HOOK_AGAIN is useful to "inject" additional elements in an
* iteration, HOOK_NEXT is the normal iterator behavior, and HOOK_SKIP may
* be used to filter elements out.
*
* @ingroup utils
*/
enum hook_result_t {
/**
* A value was placed in out, hook is called again with the same "in"
*/
HOOK_AGAIN,
/**
* A value was placed in out, hook is called again with next "in" (if any)
*/
HOOK_NEXT,
/**
* No value in out, call again with next "in" (if any)
*/
HOOK_SKIP,
};
/**
* @brief Iterator hook function prototype.
*
* @param param user supplied parameter
* @param in the value the hook receives from the iterator
* @param out the value supplied as a result to the iterator
* @return TRUE to return "out", FALSE to skip this value
* @return a hook_result_t
*
* @ingroup utils
*/
typedef bool (iterator_hook_t)(void *param, void *in, void **out);
typedef hook_result_t (iterator_hook_t)(void *param, void *in, void **out);
typedef struct iterator_t iterator_t;
@@ -45,8 +76,6 @@ typedef struct iterator_t iterator_t;
* iterator_t defines an interface for iterating over collections.
* It allows searching, deleting, updating and inserting.
*
* Thanks to JMP for iterator lessons :-)
*
* @b Constructors:
* - via linked_list_t.create_iterator, or
* - any other class which supports the iterator_t interface
@@ -84,8 +113,11 @@ struct iterator_t {
* Sometimes it is useful to hook in an iterator. The hook function is
* called before any successful return of iterate(). It takes the
* iterator value, may manipulate it (or the references object), and returns
* the value that the iterate() function returns.
* the value that the iterate() function returns. Depending on the hook
* return value, the hook is called again, called with next, or skipped.
* A value of NULL deactivates the iterator hook.
* If an iterator is hooked, only the iterate() method is valid,
* all other methods behave undefined.
*
* @param this calling object
* @param hook iterator hook which manipulates the iterated value
+31 -28
View File
@@ -151,10 +151,10 @@ static int get_list_count(private_iterator_t *this)
/**
* default iterator hook which does nothing
*/
static bool iterator_hook(void *param, void *in, void **out)
static hook_result_t iterator_hook(void *param, void *in, void **out)
{
*out = in;
return TRUE;
return HOOK_NEXT;
}
/**
@@ -180,40 +180,43 @@ static void set_iterator_hook(private_iterator_t *this, iterator_hook_t *hook,
*/
static bool iterate(private_iterator_t *this, void** value)
{
if (this->list->count == 0)
while (TRUE)
{
return FALSE;
}
if (this->current == NULL)
{
this->current = (this->forward) ? this->list->first : this->list->last;
if (!this->hook(this->hook_param, this->current->value, value))
if (this->forward)
{
return iterate(this, value);
this->current = this->current ? this->current->next : this->list->first;
}
return TRUE;
}
if (this->forward)
{
if (this->current->next == NULL)
else
{
this->current = this->current ? this->current->previous : this->list->last;
}
if (this->current == NULL)
{
return FALSE;
}
this->current = this->current->next;
if (!this->hook(this->hook_param, this->current->value, value))
switch (this->hook(this->hook_param, this->current->value, value))
{
return iterate(this, value);
case HOOK_AGAIN:
/* rewind */
if (this->forward)
{
this->current = this->current->previous;
}
else
{
this->current = this->current->next;
}
break;
case HOOK_NEXT:
/* normal iteration */
break;
case HOOK_SKIP:
/* advance */
continue;
}
return TRUE;
}
if (this->current->previous == NULL)
{
return FALSE;
}
this->current = this->current->previous;
if (!this->hook(this->hook_param, this->current->value, value))
{
return iterate(this, value);
break;
}
return TRUE;
}