#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdarg.h>
#define TRUE true
#define FALSE false
/**
* Object allocation/initialization macro, using designated initializer.
*/
#define INIT(this, ...) ({ (this) = malloc(sizeof(*(this))); \
*(this) = (typeof(*(this))){ __VA_ARGS__ }; (this); })
/**
* Method declaration/definition macro, providing private and public interface.
*
* Defines a method name with this as first parameter and a return value ret,
* and an alias for this method with a _ prefix, having the this argument
* safely casted to the public interface iface.
* _name is provided a function pointer, but will get optimized out by GCC.
*/
#define METHOD(iface, name, ret, this, ...) \
static ret name(union {iface *_public; this;} \
__attribute__((transparent_union)), ##__VA_ARGS__); \
static typeof(name) *_##name = (typeof(name)*)name; \
static ret name(this, ##__VA_ARGS__)
/**
* args macro
*/
/**
* This macro allows counting the number of arguments passed to a macro.
* Combined with the VA_ARGS_DISPATCH() macro this can be used to implement
* macro overloading based on the number of arguments.
* 0 to 10 arguments are currently supported.
*/
#define VA_ARGS_NUM(...) _VA_ARGS_NUM(0,##__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0)
#define _VA_ARGS_NUM(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NUM,...) NUM
/**
* This macro can be used to dispatch a macro call based on the number of given
* arguments, for instance:
*
* @code
* #define MY_MACRO(...) VA_ARGS_DISPATCH(MY_MACRO, __VA_ARGS__)(__VA_ARGS__)
* #define MY_MACRO1(arg) one_arg(arg)
* #define MY_MACRO2(arg1,arg2) two_args(arg1,arg2)
* @endcode
*
* MY_MACRO() can now be called with either one or two arguments, which will
* resolve to one_arg(arg) or two_args(arg1,arg2), respectively.
*/
#define VA_ARGS_DISPATCH(func, ...) _VA_ARGS_DISPATCH(func, VA_ARGS_NUM(__VA_ARGS__))
#define _VA_ARGS_DISPATCH(func, num) __VA_ARGS_DISPATCH(func, num)
#define __VA_ARGS_DISPATCH(func, num) func ## num
/**
* Assign variadic arguments to the given variables.
*
* @note The order and types of the variables are significant and must match the
* variadic arguments passed to the function that calls this macro exactly.
*
* @param last the last argument before ... in the function that calls this
* @param ... variable names
*/
#define VA_ARGS_GET(last, ...) ({ \
va_list _va_args_get_ap; \
va_start(_va_args_get_ap, last); \
_VA_ARGS_GET_ASGN(__VA_ARGS__) \
va_end(_va_args_get_ap); \
})
/**
* Assign variadic arguments from a va_list to the given variables.
*
* @note The order and types of the variables are significant and must match the
* variadic arguments passed to the function that calls this macro exactly.
*
* @param list the va_list variable in the function that calls this
* @param ... variable names
*/
#define VA_ARGS_VGET(list, ...) ({ \
va_list _va_args_get_ap; \
va_copy(_va_args_get_ap, list); \
_VA_ARGS_GET_ASGN(__VA_ARGS__) \
va_end(_va_args_get_ap); \
})
#define _VA_ARGS_GET_ASGN(...) VA_ARGS_DISPATCH(_VA_ARGS_GET_ASGN, __VA_ARGS__)(__VA_ARGS__)
#define _VA_ARGS_GET_ASGN1(v1) __VA_ARGS_GET_ASGN(v1)
#define _VA_ARGS_GET_ASGN2(v1,v2) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2)
#define _VA_ARGS_GET_ASGN3(v1,v2,v3) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3)
#define _VA_ARGS_GET_ASGN4(v1,v2,v3,v4) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4)
#define _VA_ARGS_GET_ASGN5(v1,v2,v3,v4,v5) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
__VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4) __VA_ARGS_GET_ASGN(v5)
#define __VA_ARGS_GET_ASGN(v) v = va_arg(_va_args_get_ap, typeof(v));
typedef struct enumerator_t enumerator_t;
struct enumerator_t {
bool (*enumerate)(enumerator_t *this, ...);
bool (*venumerate)(enumerator_t *this, va_list args);
void (*destroy)(enumerator_t *this);
};
bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
{
va_list args;
bool result;
if (!enumerator->venumerate)
{
return FALSE;
}
va_start(args, enumerator);
result = enumerator->venumerate(enumerator, args);
va_end(args);
return result;
}
typedef enum status_t status_t;
/**
* Return values of function calls.
*/
enum status_t {
/** Call succeeded */
SUCCESS,
/** Call failed */
FAILED,
/** Out of resources */
OUT_OF_RES,
/** The suggested operation is already done */
ALREADY_DONE,
/** Not supported */
NOT_SUPPORTED,
/** One of the arguments is invalid */
INVALID_ARG,
/** Something could not be found */
NOT_FOUND,
/** Error while parsing */
PARSE_ERROR,
/** Error while verifying */
VERIFY_ERROR,
/** Object in invalid state */
INVALID_STATE,
/** Destroy object which called method belongs to */
DESTROY_ME,
/** Another call to the method is required */
NEED_MORE,
};
/**
* 对链表中的元素进行匹配的功能
*
* @param item current list item
* @param args user supplied data
* @return TRUE, if the item matched, FALSE otherwise
*/
typedef bool (*linked_list_match_t)(void *item, va_list args);
/**
* 对链表中的元素上进行函数调用
*
* @param item current list item
* @param args user supplied data
*/
typedef void (*linked_list_invoke_t)(void *item, va_list args);
typedef struct linked_list_t linked_list_t;
struct linked_list_t {
/**
* 得到列表中项的计数。
*
* @return number of items in list
*/
int (*get_count) (linked_list_t *this);
/**
* 在列表上建立一个枚举器。
*
* @note 枚举者的位置在第一次调用枚举( )之前是无效的。
*
* @return enumerator over list items
*/
enumerator_t* (*create_enumerator)(linked_list_t *this);
/**
* 将枚举者的当前位置重置到列表的开头。
*
* @param enumerator enumerator to reset
*/
void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator);
/**
* 在列表的开头插入一个新的项目。
*
* @param item item value to insert in list
*/
void (*insert_first) (linked_list_t *this, void *item);
/**
* 删除列表中的第一项,并返回其值。
*
* @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);
/**
* 在枚举器当前指向的项前插入一个新项。
*
* 如果该方法在所有项都被枚举后才被调用,则该项最后被插入。这对于在排序列表中插入项目是有帮助的。
*
* @note The position of the enumerator is not changed. So it is safe to
* call this before or after remove_at() to replace the item at the current
* position (the enumerator will continue with the next item in the list).
* And in particular, when inserting an item before calling enumerate(),
* the enumeration will continue (or start) at the item that was first in
* the list before any items were inserted (enumerate() will return FALSE
* if the list was empty before).
*
* @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);
/**
* 从枚举器指向的列表中移除一个项。
*
* If this method is called before calling enumerate() of the enumerator,
* the first item in the list, if any, will be removed. No item is removed,
* if the method is called after enumerating all items.
*
* @param enumerator enumerator with position
*/
void (*remove_at)(linked_list_t *this, enumerator_t *enumerator);
/**
* 从与给定项目匹配的列表中删除项目。
*
* 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*));
/**
* 返回第一个列表项的值,不将其移除。
*
* @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);
/**
* 在列表的末尾插入一个新的项目。
*
* @param item value to insert into list
*/
void (*insert_last) (linked_list_t *this, void *item);
/**
* 删除列表中的最后一项,并返回其值。
*
* @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);
/**
* 返回最后一个列表项的值,不将其移除。
*
* @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);
/**
* 找到列表中的第一个匹配元素。
*
* 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 so does this function, and the
* current object is returned in the third parameter (if given), otherwise,
* the next item is checked.
*
* If match is NULL, *item and the current object are compared.
*
* @param match comparison function to call on each object, or NULL
* @param item the list item, if found, or NULL
* @param ... user data to supply to match function
* @return TRUE if found, FALSE otherwise (or if neither match,
* nor item is supplied)
*/
bool (*find_first)(linked_list_t *this, linked_list_match_t match,
void **item, ...);
/**
* 在所有包含的对象上调用一个方法。
*
* 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 evaluated at compile time using the offsetof
* macro, e.g.: list->invoke(list, offsetof(object_t, method));
*
* @param offset offset of the method to invoke on objects
*/
void (*invoke_offset)(linked_list_t *this, size_t offset);
/**
* 在所有包含的对象上调用一个函数。
*
* @param function function to call for each object
* @param ... user data to supply to called function
*/
void (*invoke_function)(linked_list_t *this, linked_list_invoke_t function,
...);
/**
* 利用对象的克隆方法,克隆一个链表及其对象。
*
* @param offset offset to the objects clone function
* @return cloned list
*/
linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset);
/**
* 用给定比较的方法比较两个列表及其相等的对象。
*
* @param other list to compare
* @param offset offset of the objects equals method
* @return TRUE if lists and objects are equal, FALSE otherwise
*/
bool (*equals_offset) (linked_list_t *this, linked_list_t *other,
size_t offset);
/**
* Compare two lists and their objects for equality using the given function.
*
* @param other list to compare
* @param function function to compare the objects
* @return TRUE if lists and objects are equal, FALSE otherwise
*/
bool (*equals_function) (linked_list_t *this, linked_list_t *other,
bool (*)(void*,void*));
/**
* 销毁一个Linked _ List对象。
*/
void (*destroy) (linked_list_t *this);
/**
* 使用析构函数销毁列表及其对象。
*
* 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);
/**
* 使用清理函数销毁列表及其内容。
*
* 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*));
};
linked_list_t *linked_list_create(void);
typedef struct element_t element_t;
/**
* This element holds a pointer to the value it represents.
*/
struct element_t {
/**
* 列表项的值。
*/
void *value;
/**
* 前一个列表元素。
*
* NULL if first element in list.
*/
element_t *previous;
/**
* 下一个.
*
* NULL if last element in list.
*/
element_t *next;
};
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;
/**
* 列表中的项目数量。
*/
int count;
/**
* 列表中的第一个元素。如果列表中没有元素,则NULL。
*/
element_t *first;
/**
* 列表中的最后一个元素。如果列表中没有元素,则NULL。
*/
element_t *last;
};
METHOD(linked_list_t, get_count, int,
private_linked_list_t *this)
{
return this->count;
}
typedef struct private_enumerator_t private_enumerator_t;
/**
* linked lists enumerator implementation
*/
struct private_enumerator_t {
/**
* implements enumerator interface
*/
enumerator_t public;
/**
* associated linked list
*/
private_linked_list_t *list;
/**
* current item
*/
element_t *current;
};
static bool do_enumerate(private_enumerator_t *this, va_list args)
{
void **item;
VA_ARGS_VGET(args, item);
if (!this->current)
{
return FALSE;
}
if (item)
{
*item = this->current->value;
}
return TRUE;
}
METHOD(enumerator_t, enumerate_next, bool,
private_enumerator_t *this, va_list args)
{
if (this->current)
{
this->current = this->current->next;
}
return do_enumerate(this, args);
}
METHOD(enumerator_t, enumerate_current, bool,
private_enumerator_t *this, va_list args)
{
this->public.venumerate = _enumerate_next;
return do_enumerate(this, args);
}
METHOD(linked_list_t, create_enumerator, enumerator_t*,
private_linked_list_t *this)
{
private_enumerator_t *enumerator;
INIT(enumerator,
.public = {
.enumerate = enumerator_enumerate_default,
.venumerate = _enumerate_current,
.destroy = (void*)free,
},
.list = this,
.current = this->first,
);
return &enumerator->public;
}
METHOD(linked_list_t, reset_enumerator, void,
private_linked_list_t *this, private_enumerator_t *enumerator)
{
enumerator->current = this->first;
enumerator->public.venumerate = _enumerate_current;
}
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, get_last, status_t,
private_linked_list_t *this, void **item)
{
if (this->count == 0)
{
return NOT_FOUND;
}
*item = this->last->value;
return SUCCESS;
}
//返回首次匹配的item
METHOD(linked_list_t, find_first, bool,
private_linked_list_t *this, linked_list_match_t match, void **item, ...)
{
element_t *current = this->first;
va_list args;
bool matched = FALSE;
if (!match && !item)
{
return FALSE;
}
while (current)
{
if (match)
{
va_start(args, item);
matched = match(current->value, args);
va_end(args);
}
else
{
matched = current->value == *item;
}
if (matched)
{
if (item != NULL)
{
*item = current->value;
}
return TRUE;
}
current = current->next;
}
return FALSE;
}
static element_t *element_create(void *value)
{
element_t *this;
INIT(this,
.value = value,
);
return this;
}
//创建一个item,赋值val,插入list最前面
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++;
}
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;
//list为空,无所谓,调用insert_last插入即可,insert_last里面会创建item
current = enumerator->current;
if (!current)
{
insert_last(this, item);
return;
}
//创建item,若current->previous非空,插入previous和current之间,否则插在current之前,此时相当于放在list第一个位置
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++;
}
/**
* 从列表中解开一个元素,返回下面的元素
*/
static element_t* remove_element(private_linked_list_t *this,
element_t *element)
{
element_t *next, *previous;
//释放当前element,后空,则修正this->last,前空则修正this->first,否则next和previous互连,若都空则同时修正last和first为NULL
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, 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, 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->next;
/* the enumerator already points to the next item */
enumerator->public.venumerate = _enumerate_current;
remove_element(this, current);
}
}
METHOD(linked_list_t, invoke_offset, void,
private_linked_list_t *this, size_t offset)
{
element_t *current = this->first;
void (**method)(void*);
while (current)
{
//如果一个链表包含带函数指针的对象,invoke ( )可以在每个对象上调用一个方法。其中
//方法是通过函数指针的一个偏移量来指定的。可以在编译时使用offsetof进行评估
method = current->value + offset;
(*method)(current->value);
current = current->next;
}
}
METHOD(linked_list_t, invoke_function, void,
private_linked_list_t *this, linked_list_invoke_t fn, ...)
{
element_t *current = this->first;
va_list args;
//在所有包含的对象上调用fn,参数为链表上的对象和传入的args
while (current)
{
va_start(args, fn);
fn(current->value, args);
va_end(args);
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;
//新建链表,将原链表中的每个元素各自都执行其offset指定的函数,将函数返回值保存在链表中
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, equals_offset, bool,
private_linked_list_t *this, linked_list_t *other_pub, size_t offset)
{
private_linked_list_t *other = (private_linked_list_t*)other_pub;
element_t *cur_t, *cur_o;
//链表元素个数不同返回错误
if (this->count != other->count)
{
return FALSE;
}
//遍历,取各元素经offset获取的方法,比较二者,若不相同则返回错误,直至最后能够返回正确
cur_t = this->first;
cur_o = other->first;
while (cur_t && cur_o)
{
bool (**method)(void*,void*) = cur_t->value + offset;
if (!(*method)(cur_t->value, cur_o->value))
{
return FALSE;
}
cur_t = cur_t->next;
cur_o = cur_o->next;
}
return TRUE;
}
//和equals_offset区别在于使用的比较函数为入参fn
METHOD(linked_list_t, equals_function, bool,
private_linked_list_t *this, linked_list_t *other_pub,
bool (*fn)(void*,void*))
{
private_linked_list_t *other = (private_linked_list_t*)other_pub;
element_t *cur_t, *cur_o;
if (this->count != other->count)
{
return FALSE;
}
cur_t = this->first;
cur_o = other->first;
while (cur_t && cur_o)
{
if (!fn(cur_t->value, cur_o->value))
{
return FALSE;
}
cur_t = cur_t->next;
cur_o = cur_o->next;
}
return TRUE;
}
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);
}
linked_list_t *linked_list_create(void)
{
private_linked_list_t *this;
INIT(this,
.public = {
.get_count = _get_count,
.create_enumerator = _create_enumerator,
.reset_enumerator = (void*)_reset_enumerator,
.get_first = _get_first,
.get_last = _get_last,
.find_first = _find_first,
.insert_first = _insert_first,
.insert_last = _insert_last,
.insert_before = (void*)_insert_before,
.remove_first = _remove_first,
.remove_last = _remove_last,
.remove = _remove_,
.remove_at = (void*)_remove_at,
.invoke_offset = _invoke_offset,
.invoke_function = _invoke_function,
.clone_offset = _clone_offset,
.equals_offset = _equals_offset,
.equals_function = _equals_function,
.destroy = _destroy,
.destroy_offset = _destroy_offset,
.destroy_function = _destroy_function,
},
);
return &this->public;
}
#include <stdint.h>
#include <string.h>
int main()
{
typedef struct cache_entry_t cache_entry_t;
/**
* Cache line in the interface name cache.
*/
struct cache_entry_t {
/** reqid of the CHILD_SA */
uint32_t reqid;
/** cached interface name */
char *iface;
};
uint32_t unique_id = 0;
cache_entry_t *val;
linked_list_t *candidates;
candidates = linked_list_create();
cache_entry_t *entry_0;
INIT(entry_0,
.reqid = unique_id++,
.iface = strdup("eth0"),
);
candidates->insert_first(candidates, entry_0);
printf("count: %d\n", candidates->get_count(candidates));
candidates->get_first(candidates, (void *)&val);
printf("first: reqid:%d-iface:%s\n", val->reqid, val->iface);
cache_entry_t *entry_1;
INIT(entry_1,
.reqid = unique_id++,
.iface = strdup("eth1"),
);
candidates->insert_first(candidates, entry_1);
printf("count: %d\n", candidates->get_count(candidates));
candidates->get_first(candidates, (void *)&val);
printf("first: reqid:%d-iface:%s\n", val->reqid, val->iface);
cache_entry_t *entry_2;
INIT(entry_2,
.reqid = unique_id++,
.iface = strdup("eth2"),
);
candidates->insert_last(candidates, entry_2);
printf("count: %d\n", candidates->get_count(candidates));
candidates->get_first(candidates, (void *)&val);
printf("first: reqid:%d-iface:%s\n", val->reqid, val->iface);
candidates->get_last(candidates, (void *)&val);
printf("last: reqid:%d-iface:%s\n", val->reqid, val->iface);
if (candidates->find_first(candidates, NULL, (void *)&val, (void *)&entry_2)){
printf("find_first:reqid:%d-iface:%s\n", val->reqid, val->iface);
}else{
printf("not find first\n");
}
candidates->destroy(candidates);
return 0;
}