Merge branch 'dev'
This commit is contained in:
@@ -1,21 +0,0 @@
|
|||||||
#ifndef UC_HEAPSORT_H_
|
|
||||||
#define UC_HEAPSORT_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
///compare function. Needs only to return < 0 if
|
|
||||||
//the first element is less than the second
|
|
||||||
typedef int (*uc_hs_cmp)(const void *, const void *);
|
|
||||||
|
|
||||||
void
|
|
||||||
uc_heapsort(void *base, size_t count, size_t width,
|
|
||||||
uc_hs_cmp cmp);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -83,7 +83,7 @@ static inline struct UHNode *uc_htable_first_bucket(const struct UHTable *table,
|
|||||||
* Get the next node in the bucket.
|
* Get the next node in the bucket.
|
||||||
* @return next node or NULL
|
* @return next node or NULL
|
||||||
*/
|
*/
|
||||||
static inline struct UHNode *uc_htable_next_bucket(const struct UHNode *node)
|
static inline struct UHNode *uc_htable_next_in_bucket(const struct UHNode *node)
|
||||||
{
|
{
|
||||||
return node->next;
|
return node->next;
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ static inline struct UHNode *uc_htable_next_hash(const struct UHNode *node)
|
|||||||
|
|
||||||
|
|
||||||
//internal helper
|
//internal helper
|
||||||
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t bucket);
|
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t start_bucket);
|
||||||
|
|
||||||
/** Get the first node in the hash table
|
/** Get the first node in the hash table
|
||||||
*
|
*
|
||||||
@@ -151,7 +151,7 @@ void uc_htable_swap(struct UHTable *a, struct UHTable *b);
|
|||||||
#define UC_HTABLE_FOREACH_BUCKET(table, node_iter, hash)\
|
#define UC_HTABLE_FOREACH_BUCKET(table, node_iter, hash)\
|
||||||
for ((node_iter) = uc_htable_first_bucket((table), (hash));\
|
for ((node_iter) = uc_htable_first_bucket((table), (hash));\
|
||||||
(node_iter) != NULL;\
|
(node_iter) != NULL;\
|
||||||
(node_iter) = uc_htable_next_bucket((node_iter)))
|
(node_iter) = uc_htable_next_in_bucket((node_iter)))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over all nodes that has the given hash.
|
* Iterate over all nodes that has the given hash.
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ void uc_log_destination_set_module_loglevel(
|
|||||||
* SHORT_NAME_1=LEVEL:SHORT_NAME_2=LEVEL:SHORT_NAME_N=LEVEL
|
* SHORT_NAME_1=LEVEL:SHORT_NAME_2=LEVEL:SHORT_NAME_N=LEVEL
|
||||||
*
|
*
|
||||||
* The SHORT_NAME_N is the .short_name within a struct uc_log_module
|
* The SHORT_NAME_N is the .short_name within a struct uc_log_module
|
||||||
* LEVEL is one of DEBUG,INFO, WARNING or ERROR
|
* LEVEL is one of DEBUG, INFO, WARNING, ERROR or NONE
|
||||||
* Example:
|
* Example:
|
||||||
* DB=DEBUG:IO=ERROR:POLLER=INFO
|
* DB=DEBUG:IO=ERROR:POLLER=INFO
|
||||||
*
|
*
|
||||||
@@ -280,8 +280,8 @@ void uc_logf(int log_level, int module, int raw,
|
|||||||
# define UC_DEBUGFR(mod, fmt, ...)\
|
# define UC_DEBUGFR(mod, fmt, ...)\
|
||||||
uc_logf(UC_LL_DEBUG, mod,1 , UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
uc_logf(UC_LL_DEBUG, mod,1 , UC_SRC_LOCATION, fmt, ## __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define UC_DEBUGF(mod, fmt, ...)
|
# define UC_DEBUGF(mod, fmt, ...) do {} while (0)
|
||||||
# define UC_DEBUGFR(mod, fmt, ...)
|
# define UC_DEBUGFR(mod, fmt, ...) do {} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Main macro that should be used for logging.
|
/** Main macro that should be used for logging.
|
||||||
|
|||||||
@@ -0,0 +1,252 @@
|
|||||||
|
#ifndef UC_TAILQ_H_
|
||||||
|
#define UC_TAILQ_H_
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define UC_INLINE inline __attribute__((always_inline,flatten))
|
||||||
|
#else
|
||||||
|
#define UC_INLINE inline
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* Doubly Linked List.
|
||||||
|
* It is used either as
|
||||||
|
* 1) a linked list "head" - a node serving to hold pointer to the
|
||||||
|
* first and last node in a list
|
||||||
|
* 2) a linked list entry - a node in the linked list
|
||||||
|
*
|
||||||
|
* This is variant of sys/queue.h TAILQ which avoids too many conditionals.
|
||||||
|
* The struct TailQ serves both as an entry/node in a linked list,
|
||||||
|
* and as head of a linked list.
|
||||||
|
*
|
||||||
|
* Note that unlike the sys/queue.h TAILQ, the list does
|
||||||
|
* not begin/end with a NULL pointer. For a entry node, the beginning/end
|
||||||
|
* is a back pointer to the head node.
|
||||||
|
*
|
||||||
|
* Traditional linked list TailQ
|
||||||
|
* node->prev == NULL node->prev == head
|
||||||
|
* node->next == NULL node->next == head
|
||||||
|
*
|
||||||
|
* Do not ever add an entry that's a NULL pointer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct TailQ {
|
||||||
|
//pointer to next element, or for a head node,
|
||||||
|
//pointer to the first entry
|
||||||
|
struct TailQ *next;
|
||||||
|
//pointer to previous element, or for a head node,
|
||||||
|
//pointer to the last node
|
||||||
|
struct TailQ *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UC_TAILQ_HEAD_INIT(name) {&(name), &(name)}
|
||||||
|
|
||||||
|
#define UC_TAILQ_HEAD(name)\
|
||||||
|
struct TailQ name = UC_TAILQ_HEAD_INIT(name)
|
||||||
|
|
||||||
|
//given 'ptr' as a pointer to a struct 'member',
|
||||||
|
//find the struct that ptr is the member of, where
|
||||||
|
//'type' is the type of the containing struct
|
||||||
|
//This is basically UC_CONTAINER_OF in ucore/utils.h, this is here
|
||||||
|
//to make tailq.h a standalone header
|
||||||
|
#define UC_TAILQ_CONTAINER(ptr, type, member) ({\
|
||||||
|
typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); })
|
||||||
|
|
||||||
|
|
||||||
|
static UC_INLINE void uc_tailq_init(struct TailQ *head)
|
||||||
|
{
|
||||||
|
head->prev = head;
|
||||||
|
head->next = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test if the tailq is empty
|
||||||
|
*/
|
||||||
|
static UC_INLINE int uc_tailq_empty(const struct TailQ *head)
|
||||||
|
{
|
||||||
|
return head->next == head->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert the entry between prev and next
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_insert(struct TailQ *entry,
|
||||||
|
struct TailQ *prev,
|
||||||
|
struct TailQ *next)
|
||||||
|
{
|
||||||
|
entry->prev = prev;
|
||||||
|
prev->next = entry;
|
||||||
|
|
||||||
|
entry->next = next;
|
||||||
|
next->prev = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert entry to the tail(end) of the tailq
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_insert_tail(struct TailQ *head, struct TailQ *entry)
|
||||||
|
{
|
||||||
|
//head becomes entry->next, signalling the end of the tailq
|
||||||
|
uc_tailq_insert(entry, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert entry to the head(start) of the tailq
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_insert_head(struct TailQ *head, struct TailQ *entry)
|
||||||
|
{
|
||||||
|
//head becomes entry->prev, signalling the end of the tailq
|
||||||
|
uc_tailq_insert(entry, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Link the first and second entry together,
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_link(struct TailQ *first, struct TailQ *second)
|
||||||
|
{
|
||||||
|
first->next = second;
|
||||||
|
second->prev = first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove the entry from the tailq it is part of.
|
||||||
|
* (It *must* already be part of a tailq.
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_remove(struct TailQ *entry)
|
||||||
|
{
|
||||||
|
uc_tailq_link(entry->prev, entry->next);
|
||||||
|
|
||||||
|
//help catch illegal use:
|
||||||
|
entry->next = (void*)0x101;
|
||||||
|
entry->prev = (void*)0x102;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Move entry from its current tailq to the head of another tailq.
|
||||||
|
* (entry must be part of a tailq)
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_move_head(struct TailQ *entry, struct TailQ *head)
|
||||||
|
{
|
||||||
|
uc_tailq_link(entry->prev, entry->next);
|
||||||
|
uc_tailq_insert(entry, head, head->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Move entry from its current tailq to the tail of another tailq.
|
||||||
|
* (entry must be part of a tailq)
|
||||||
|
*/
|
||||||
|
static UC_INLINE void uc_tailq_move_tail(struct TailQ *entry, struct TailQ *head)
|
||||||
|
{
|
||||||
|
uc_tailq_link(entry->prev, entry->next);
|
||||||
|
uc_tailq_insert(entry, head->prev, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIRST/NEXT/LAST/PREV macros similar to sys/queue.h
|
||||||
|
//Note that unlike the standard TAILQ, you have to check
|
||||||
|
// != head instead of != NULL to determine if the tailq entry
|
||||||
|
// exists
|
||||||
|
|
||||||
|
#define UC_TAILQ_FIRST(head)\
|
||||||
|
((head)->next)
|
||||||
|
|
||||||
|
#define UC_TAILQ_NEXT(entry)\
|
||||||
|
((entry)->next)
|
||||||
|
|
||||||
|
#define UC_TAILQ_LAST(head)\
|
||||||
|
((head)->prev)
|
||||||
|
|
||||||
|
#define UC_TAILQ_PREV(entry)\
|
||||||
|
((entry)->prev)
|
||||||
|
|
||||||
|
/** Iterate over a tailq. The tailq cannot be altered while iterating.
|
||||||
|
*
|
||||||
|
* @param entry a struct TailQ* to which each element is assigned.
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH(entry, head)\
|
||||||
|
for ((entry) = UC_TAILQ_FIRST(head); \
|
||||||
|
(entry) != (head); \
|
||||||
|
(entry) = UC_TAILQ_NEXT(entry))
|
||||||
|
|
||||||
|
/** Iterate over the containing element in a tailq.
|
||||||
|
* The tailq cannot be altered while iterating.
|
||||||
|
*
|
||||||
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
||||||
|
* @param member the member of ptr that is the tailq node
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_CONTAINER(ptr, member, head)\
|
||||||
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member);\
|
||||||
|
&(ptr)->member != (head);\
|
||||||
|
(ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
||||||
|
|
||||||
|
/** Iterate over a tailq in reverse order.
|
||||||
|
* The tailq cannot be altered while iterating.
|
||||||
|
*
|
||||||
|
* @param entry a struct TailQ* to which each element is assigned.
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_REVERSE(entry, head)\
|
||||||
|
for ((entry) = UC_TAILQ_LAST(entry); \
|
||||||
|
(entry) != (head); \
|
||||||
|
(entry) = UC_TAILQ_PREV(entry)
|
||||||
|
|
||||||
|
/** Iterate over the containing element in a tailq in reverse.
|
||||||
|
* The tailq cannot be altered while iterating.
|
||||||
|
*
|
||||||
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
||||||
|
* @param member the member of ptr that is the tailq node
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_REVERSE_CONTAINER(ptr, member, head)\
|
||||||
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member);\
|
||||||
|
&(ptr)->member != (head);\
|
||||||
|
(ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member))
|
||||||
|
|
||||||
|
/** Iterate over a tailq. safe to remove the entry when iterating.
|
||||||
|
*
|
||||||
|
* @param entry a struct TailQ* to which each element is assigned.
|
||||||
|
* @param nxt a struct TailQ* needed for temporary storage.
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_SAFE(entry, nxt, head)\
|
||||||
|
for ((entry) = UC_TAILQ_FIRST(head), (nxt) = UC_TAILQ_NEXT(entry); \
|
||||||
|
(entry) != (head); \
|
||||||
|
(entry) = (nxt), (nxt) = UC_TAILQ_NEXT(entry))\
|
||||||
|
|
||||||
|
/** Iterate over the containing element in a tailq, safe to remove
|
||||||
|
* the entry when iterating
|
||||||
|
*
|
||||||
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
||||||
|
* @param nxt same type as ptr needed for temporary storage.
|
||||||
|
* @param member the member of ptr that is the tailq node
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_CONTAINER_SAFE(ptr, nxt, member, head)\
|
||||||
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_FIRST(head), typeof(*ptr), member),\
|
||||||
|
(nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member);\
|
||||||
|
&(ptr)->member != (head);\
|
||||||
|
(ptr) = (nxt),\
|
||||||
|
(nxt) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
||||||
|
|
||||||
|
/** Iterate over a tailq in reverse order. safe to remove the entry when
|
||||||
|
* iterating.
|
||||||
|
*
|
||||||
|
* @param entry a struct TailQ* to which each element is assigned.
|
||||||
|
* @param prv a struct TailQ* needed for temporary storage.
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_REVERSE_SAFE(entry, prv, head)\
|
||||||
|
for ((entry) = UC_TAILQ_LAST(head), (prv) = UC_TAILQ_PREV(entry); \
|
||||||
|
(entry) != (head); \
|
||||||
|
(entry) = (prv), (prv) = UC_TAILQ_PREV(entry))\
|
||||||
|
|
||||||
|
/** Iterate over the containing element in a tailq in reverse order, safe
|
||||||
|
* to remove the entry when iterating
|
||||||
|
*
|
||||||
|
* @param ptr a pointer to the struct which the tailq nodes are member of
|
||||||
|
* @param prv same type as ptr needed for temporary storage.
|
||||||
|
* @param member the member of ptr that is the tailq node
|
||||||
|
* @param head the struct TailQ* head of the tailq
|
||||||
|
*/
|
||||||
|
#define UC_TAILQ_FOREACH_REVERSE_CONTAINER_SAFE(ptr, prv, member, head)\
|
||||||
|
for ((ptr) = UC_TAILQ_CONTAINER(UC_TAILQ_LAST(head), typeof(*ptr), member),\
|
||||||
|
(prv) = UC_TAILQ_CONTAINER(UC_TAILQ_PREV(&(ptr)->member), typeof(*ptr), member);\
|
||||||
|
&(ptr)->member != (head);\
|
||||||
|
(ptr) = (prv),\
|
||||||
|
(prv) = UC_TAILQ_CONTAINER(UC_TAILQ_NEXT(&(ptr)->member), typeof(*ptr), member))
|
||||||
|
|
||||||
|
#undef UC_INLINE
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -60,20 +60,21 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
|||||||
/**
|
/**
|
||||||
* Test if x is a power of 2
|
* Test if x is a power of 2
|
||||||
*
|
*
|
||||||
* @param x value
|
* @param x value, must be an unsigned type
|
||||||
* @return 1 if x is a power of 20, 0 if it is not
|
* @return 1 if x is a power of 20, 0 if it is not
|
||||||
*/
|
*/
|
||||||
#define UC_IS_POW2(x) ((x) && !((x) & (x) - 1))
|
#define UC_IS_POW2(x) ((x) && !((x) & (x) - 1))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * Expands @x and turns it into a string.
|
* Expands @x and turns it into a string.
|
||||||
* */
|
*/
|
||||||
#define UC_STRINGIFY(x) UC_STRINGIFY_HLP(x)
|
#define UC_STRINGIFY(x) UC_STRINGIFY_HLP(x)
|
||||||
#define UC_STRINGIFY_HLP(x) #x
|
#define UC_STRINGIFY_HLP(x) #x
|
||||||
|
|
||||||
/** Macro that expands to a string for the current file:line
|
/** Macro that expands to a string for the current file:line
|
||||||
*/
|
*/
|
||||||
#define UC_SRC_LOCATION __FILE__ ":" UC_STRINGIFY(__LINE__)
|
#define UC_SRC_LOCATION __FILE__ ":" UC_STRINGIFY(__LINE__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assert() that is not affected by NDEBUG define
|
* assert() that is not affected by NDEBUG define
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
#include "ucore/heapsort.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
uc_sift(unsigned char *base, size_t start, size_t count, size_t width,
|
|
||||||
uc_hs_cmp cmp)
|
|
||||||
{
|
|
||||||
size_t root = start, child;
|
|
||||||
|
|
||||||
while ((root * 2 + 1) < count) {
|
|
||||||
child = root * 2 + 1;
|
|
||||||
if (child < (count - 1)
|
|
||||||
&& cmp(&base[child * width], &base[(child + 1) * width]) < 0)
|
|
||||||
child++;
|
|
||||||
|
|
||||||
if (cmp(&base[root * width], &base[child * width]) < 0) {
|
|
||||||
memcpy(base + root * width, base + child * width, width);
|
|
||||||
root = child;
|
|
||||||
} else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
uc_heapsort(void *base_, size_t count, size_t width,
|
|
||||||
uc_hs_cmp cmp)
|
|
||||||
{
|
|
||||||
int start = count / 2 - 1, end = count - 1;
|
|
||||||
unsigned char *base = base_;
|
|
||||||
|
|
||||||
while (start >= 0) {
|
|
||||||
uc_sift(base, start, count, width, cmp);
|
|
||||||
start--;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (end > 0) {
|
|
||||||
memcpy(base + end * width, base, width);
|
|
||||||
uc_sift(base, 0, end, width, cmp);
|
|
||||||
end--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-3
@@ -50,13 +50,13 @@ struct UHNode *uc_htable_next_hash_hlp(struct UHNode *next, size_t hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//find a node, starting at bucket
|
//find a node, starting at bucket
|
||||||
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t bucket)
|
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t start_bucket)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
struct UHNode *found = NULL;
|
struct UHNode *found = NULL;
|
||||||
|
|
||||||
//search through buckets until a node is found
|
//search through buckets until a node is found
|
||||||
for (i = bucket; i < table->cnt_buckets; i++) {
|
for (i = start_bucket; i < table->cnt_buckets; i++) {
|
||||||
found = uc_htable_first_bucket(table, i);
|
found = uc_htable_first_bucket(table, i);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
break;
|
break;
|
||||||
@@ -69,7 +69,7 @@ struct UHNode *uc_htable_next(struct UHTable *table, struct UHNode *node)
|
|||||||
{
|
{
|
||||||
struct UHNode *found;
|
struct UHNode *found;
|
||||||
|
|
||||||
found = uc_htable_next_bucket(node);
|
found = uc_htable_next_in_bucket(node);
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
size_t current_bucket = uc_htable_bucket(table, node->hash);
|
size_t current_bucket = uc_htable_bucket(table, node->hash);
|
||||||
found = uc_htable_iter_hlp(table, current_bucket + 1);
|
found = uc_htable_iter_hlp(table, current_bucket + 1);
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ static const char *const g_log_levels[] = {
|
|||||||
"WARNING",
|
"WARNING",
|
||||||
"UNKNOWN_6",
|
"UNKNOWN_6",
|
||||||
"ERROR",
|
"ERROR",
|
||||||
|
"UNKNOWN_8",
|
||||||
"NONE"
|
"NONE"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ucore/tailq.h>
|
||||||
|
#include <ucore/utils.h>
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
char text[64];
|
||||||
|
struct TailQ blocks;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
char name[128];
|
||||||
|
struct TailQ head;
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_block(struct File *f, const char *txt)
|
||||||
|
{
|
||||||
|
struct Block *b = malloc(sizeof *b);
|
||||||
|
strcpy(b->text,txt);
|
||||||
|
uc_tailq_insert_tail(&f->head, &b->blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_file(struct File *f)
|
||||||
|
{
|
||||||
|
struct Block *entry;
|
||||||
|
printf("File: %s\n", f->name);
|
||||||
|
UC_TAILQ_FOREACH_CONTAINER(entry, blocks, &f->head) {
|
||||||
|
printf("Block: %s\n", entry->text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_file_reverse(struct File *f)
|
||||||
|
{
|
||||||
|
struct Block *entry;
|
||||||
|
printf("File: %s\n", f->name);
|
||||||
|
UC_TAILQ_FOREACH_REVERSE_CONTAINER(entry, blocks, &f->head) {
|
||||||
|
printf("Block: %s\n", entry->text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_block(struct File *f, const char *txt)
|
||||||
|
{
|
||||||
|
struct Block *entry, *next;
|
||||||
|
UC_TAILQ_FOREACH_CONTAINER_SAFE(entry, next, blocks, &f->head) {
|
||||||
|
if (strcmp(txt, entry->text) == 0) {
|
||||||
|
uc_tailq_remove(&entry->blocks);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_all_blocks(struct File *f)
|
||||||
|
{
|
||||||
|
struct Block *entry, *next;
|
||||||
|
UC_TAILQ_FOREACH_CONTAINER_SAFE(entry, next, blocks, &f->head) {
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
uc_tailq_init(&f->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
struct File f;
|
||||||
|
uc_tailq_init(&f.head);
|
||||||
|
printf("Is Empty: %d\n", uc_tailq_empty(&f.head));
|
||||||
|
strcpy(f.name,"Test.f");
|
||||||
|
add_block(&f,"one");
|
||||||
|
add_block(&f,"two");
|
||||||
|
add_block(&f,"three");
|
||||||
|
|
||||||
|
print_file(&f);
|
||||||
|
printf("Is Empty: %d\n", uc_tailq_empty(&f.head));
|
||||||
|
|
||||||
|
puts("\nDeleting three");
|
||||||
|
delete_block(&f, "three");
|
||||||
|
print_file(&f);
|
||||||
|
|
||||||
|
puts("\nAdding 2 blocks");
|
||||||
|
add_block(&f,"three");
|
||||||
|
add_block(&f,"three");
|
||||||
|
print_file(&f);
|
||||||
|
puts("\nReverse order:");
|
||||||
|
print_file_reverse(&f);
|
||||||
|
|
||||||
|
puts("\nDeleting three");
|
||||||
|
delete_block(&f, "three");
|
||||||
|
print_file(&f);
|
||||||
|
|
||||||
|
delete_all_blocks(&f);
|
||||||
|
printf("Is Empty: %d\n", uc_tailq_empty(&f.head));
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,6 +102,7 @@ void peer_add_addr(struct HBContext *ctx, const struct sockaddr_in *addr)
|
|||||||
|
|
||||||
peer->timer.callback = peer_timer_cb;
|
peer->timer.callback = peer_timer_cb;
|
||||||
peer->timer.cookie_ptr = ctx;
|
peer->timer.cookie_ptr = ctx;
|
||||||
|
peer->state = PeerUnknown;
|
||||||
|
|
||||||
sec = rand() % PEER_HB_SEC;
|
sec = rand() % PEER_HB_SEC;
|
||||||
usec = rand() % 1000000;
|
usec = rand() % 1000000;
|
||||||
|
|||||||
Reference in New Issue
Block a user