diff --git a/include/cdsl_defs.h b/include/cdsl_defs.h index e85fbe9..5bd6a88 100644 --- a/include/cdsl_defs.h +++ b/include/cdsl_defs.h @@ -97,6 +97,9 @@ extern "C" { #define DECLARE_PRINTER(fn) void fn(void* node) #endif +/**! + * + */ typedef void* (*cdsl_generic_compare_t)(void*, void*); typedef void (*cdsl_generic_printer_t) (void*); typedef void* (*cdsl_alloc_t)(unsigned long sz); diff --git a/include/cdsl_dlist.h b/include/cdsl_dlist.h index e5dc766..4131bc6 100644 --- a/include/cdsl_dlist.h +++ b/include/cdsl_dlist.h @@ -12,22 +12,25 @@ #define CDSL_DLIST_H_ #include "base_list.h" +#include "sort.h" #if defined(__cplusplus) extern "C" { #endif -#define cdsl_dlistIsEmpty(lhead) (((dlistEntry_t*) lhead)->head== NULL) +#define cdsl_dlistIsEmpty(lhead) (((dlistEntry_t*) lhead)->head== NULL) -#define cdsl_dlistSize(lentry) cdsl_listSize((listEntry_t*) lentry) -#define cdsl_dlistContain(lentry, item) cdsl_listContain((listEntry_t*) lentry, (listNode_t*) item) -#define cdsl_dlistPrint(lentry,print) cdsl_listPrint((listEntry_t*) lentry, print) +#define cdsl_dlistSize(lentry) cdsl_listSize((listEntry_t*) lentry) +#define cdsl_dlistContain(lentry, item) cdsl_listContain((listEntry_t*) lentry, (listNode_t*) item) +#define cdsl_dlistPrint(lentry,print) cdsl_listPrint((listEntry_t*) lentry, print) -#define cdsl_dlistIterInit(lentry, iter) cdsl_iterInit((listEntry_t*) lentry, iter) -#define cdsl_dlistIterHasNext(iter) cdsl_iterHasNext(iter) -#define cdsl_dlistIterNext(iter) cdsl_iterNext(iter) +#define cdsl_dlistIterInit(lentry, iter) cdsl_iterInit((listEntry_t*) lentry, iter) +#define cdsl_dlistIterHasNext(iter) cdsl_iterHasNext(iter) +#define cdsl_dlistIterNext(iter) cdsl_iterNext(iter) + +#define cdsl_dlistSort(lentry, order, compare) cdsl_listMergeSort((listEntry_t*) lentry, order, compare, TRUE) typedef struct cdsl_dlnode dlistNode_t; typedef struct cdsl_dlentry dlistEntry_t; diff --git a/include/cdsl_slist.h b/include/cdsl_slist.h index 075a537..1c6277c 100644 --- a/include/cdsl_slist.h +++ b/include/cdsl_slist.h @@ -9,21 +9,24 @@ #define CDSL_SLIST_H_ #include "base_list.h" +#include "sort.h" #if defined(__cplusplus) extern "C" { #endif -#define cdsl_slistIsEmpty(node) (((slistEntry_t*) node)->head == NULL) +#define cdsl_slistIsEmpty(node) (((slistEntry_t*) node)->head == NULL) -#define cdsl_slistSize(lentry) cdsl_listSize((listEntry_t*) lentry) -#define cdsl_slistContain(lentry, item) cdsl_listContain((listEntry_t*) lentry, (listNode_t*) item) -#define cdsl_slistPrint(lentry,print) cdsl_listPrint((listEntry_t*) lentry, print) +#define cdsl_slistSize(lentry) cdsl_listSize((listEntry_t*) lentry) +#define cdsl_slistContain(lentry, item) cdsl_listContain((listEntry_t*) lentry, (listNode_t*) item) +#define cdsl_slistPrint(lentry,print) cdsl_listPrint((listEntry_t*) lentry, print) + +#define cdsl_slistIterInit(lentry, iter) cdsl_iterInit((listEntry_t*) lentry, iter) +#define cdsl_slistIterHasNext(iter) cdsl_iterHasNext(iter) +#define cdsl_slistIterNext(iter) cdsl_iterNext(iter) +#define cdsl_slistSort(lentry, order, compare) cdsl_listMergeSort((listEntry_t*) lentry, order, compare, FALSE) -#define cdsl_slistIterInit(lentry, iter) cdsl_iterInit((listEntry_t*) lentry, iter) -#define cdsl_slistIterHasNext(iter) cdsl_iterHasNext(iter) -#define cdsl_slistIterNext(iter) cdsl_iterNext(iter) typedef struct cdsl_slnode slistNode_t; typedef struct cdsl_slentry slistEntry_t; diff --git a/include/sort.h b/include/sort.h new file mode 100644 index 0000000..f7ef6ad --- /dev/null +++ b/include/sort.h @@ -0,0 +1,29 @@ + + +#ifndef __CDSL_SORT_C +#define __CDSL_SORT_C + +#ifdef __cplusplus +extern "C" { +#endif + +#include "base_list.h" + +typedef enum { + ASC, + DESC +}sortOrder_t; +/** + * @return positive if one is larger than the_other, or negative otherwise. 0 when the two are exactly same + */ +typedef int (*cdsl_comparator_t)(void* one, void* the_other); + +extern void cdsl_listMergeSort(listEntry_t* entry, sortOrder_t order, cdsl_comparator_t comp, BOOL isDoubleLink); + +#ifdef __cplusplus +} +#endif + + + +#endif diff --git a/source/base_list.c b/source/base_list.c index b7cacf6..92fe97a 100644 --- a/source/base_list.c +++ b/source/base_list.c @@ -76,7 +76,8 @@ listNode_t* cdsl_iterNext(listIter_t* iter) return NULL; if(!iter->prev) iter->prev = (listNode_t*) iter->entry; - return iter->prev->next; + iter->prev = iter->prev->next; + return iter->prev; } listNode_t* cdsl_iterRemove(listIter_t* iter) diff --git a/source/recipe.mk b/source/recipe.mk index 84e4d61..f712c11 100644 --- a/source/recipe.mk +++ b/source/recipe.mk @@ -11,6 +11,7 @@ OBJ-y+= base_list\ cdsl_spltree\ cdsl_rbtree\ cdsl_hashtree\ - baremetal + baremetal\ + sort \ No newline at end of file diff --git a/source/sort.c b/source/sort.c new file mode 100644 index 0000000..1e6764f --- /dev/null +++ b/source/sort.c @@ -0,0 +1,85 @@ + + + +#include "cdsl_dlist.h" +#include "sort.h" + + +static listNode_t* merge_sort_rc(listNode_t* head, sortOrder_t order, cdsl_comparator_t comp, BOOL isDouble); +static listNode_t* peek_middle(listNode_t* head); + +extern void cdsl_listMergeSort(listEntry_t* entry, sortOrder_t order, cdsl_comparator_t comp, BOOL isDoubleLink) { + entry->head = merge_sort_rc(entry->head, order, comp, isDoubleLink); +} + +static listNode_t* merge_sort_rc(listNode_t* head, sortOrder_t order, cdsl_comparator_t comp, BOOL isDouble) { + if(!(head->next)) { + return head; + } + listNode_t* middle = peek_middle(head); + if(!middle) { + return head; + } + listNode_t* left_cur, *right_cur; + if(head->next == middle) { + head->next = NULL; + left_cur = head; + right_cur = merge_sort_rc(middle, order, comp, isDouble); + } else { + right_cur = merge_sort_rc(middle->next, order, comp, isDouble); + middle->next = NULL; + left_cur = merge_sort_rc(head, order, comp, isDouble); + } + head = NULL; + listNode_t** slot = &head; + // keep + // NOTE : middle used as previous from this point + middle = NULL; + while(!((left_cur == NULL) && (right_cur == NULL))) { + + if ((left_cur != NULL) && (right_cur != NULL)) { + if (comp(left_cur, right_cur) > 0) { + *slot = (order == ASC)? right_cur : left_cur; + } else { + *slot = (order == ASC)? left_cur : right_cur; + } + } else if (left_cur == NULL) { + *slot = right_cur; + } else { + *slot = left_cur; + } + if(*slot == left_cur) { + left_cur = left_cur->next; + } else if(*slot == right_cur) { + right_cur = right_cur->next; + } + if(isDouble) { + if(middle) { + ((dlistNode_t*) *slot)->prev = (dlistNode_t*) middle; + middle = *slot; + } else { + middle = *slot; + ((dlistNode_t*) middle)->prev = NULL; + } + } + slot = &(*slot)->next; + } + return head; +} + +/*** + * head node of list chunk to be searched + * @return head if there is only list node in the list chunk, otherwise return middle list node within the list chunk. + */ +static listNode_t* peek_middle(listNode_t* head) { + listNode_t* mid = head; + uint32_t l_cnt = 0; + while(head->next) { + if((l_cnt % 2) == 0) { + mid = mid->next; + } + l_cnt++; + head = head->next; + } + return mid; +} diff --git a/source/test/cdsl_list_test.c b/source/test/cdsl_list_test.c index 643ec9e..86c0432 100644 --- a/source/test/cdsl_list_test.c +++ b/source/test/cdsl_list_test.c @@ -9,13 +9,14 @@ #include #include "cdsl_dlist.h" #include "cdsl_list_test.h" - +#include "sort.h" struct card { dlistNode_t list_node; int num; }; static DECLARE_COMPARE_FN(compare); +static int compare_sort(void* one, void* the_other); static struct card cards[TEST_SIZE]; BOOL cdsl_listDoTest(void) @@ -45,9 +46,33 @@ BOOL cdsl_listDoTest(void) } } + // test sort + for(idx = 0; idx < TEST_SIZE; idx++) { + cdsl_dlistNodeInit(&cards[idx].list_node); + cards[idx].num = idx; + cdsl_dlistPutHead(&list_entry, &(cards[idx].list_node)); + } + cdsl_dlistSort(&list_entry, DESC, compare_sort); + listIter_t iter; + cdsl_iterInit((listEntry_t*) &list_entry, &iter); + int prev_num = TEST_SIZE; + while(cdsl_iterHasNext(&iter)) { + void* node = (void*) cdsl_iterNext(&iter); + struct card* cp = container_of(node, struct card, list_node); + if(prev_num < cp->num) { + return FALSE; + } + prev_num = cp->num; + } return TRUE; } +static int compare_sort(void* one, void* the_other) { + struct card* this_card = container_of(one, struct card, list_node); + struct card* that_card = container_of(the_other, struct card, list_node); + return this_card->num - that_card->num; +} + static DECLARE_COMPARE_FN(compare) { diff --git a/source/test/cdsl_slist_test.c b/source/test/cdsl_slist_test.c index eb60768..2af4e2e 100644 --- a/source/test/cdsl_slist_test.c +++ b/source/test/cdsl_slist_test.c @@ -21,6 +21,7 @@ typedef struct card { static card_t Cards[TEST_SIZE]; static DECLARE_COMPARE_FN(card_compare); static slistEntry_t listEntry; +static int compare_sort(void* one, void* the_other); BOOL cdsl_slistDoTest(void){ @@ -57,10 +58,34 @@ BOOL cdsl_slistDoTest(void){ if(!card) return FALSE; } + for(i = 0; i < TEST_SIZE; i++) { + cdsl_slistNodeInit(&Cards[i].list_head); + Cards[i].card_num = i; + cdsl_slistPutHead(&listEntry, &Cards[i].list_head); + } + cdsl_slistSort(&listEntry, DESC, compare_sort); + listIter_t iter; + cdsl_iterInit((listEntry_t*) &listEntry, &iter); + int prev_num = TEST_SIZE; + while(cdsl_iterHasNext(&iter)) { + void* node = (void*) cdsl_iterNext(&iter); + struct card* cp = container_of(node, struct card, list_head); + if(prev_num < cp->card_num) { + return FALSE; + } + prev_num = cp->card_num; + } return TRUE; } +static int compare_sort(void* one, void* the_other) { + struct card* this_card = container_of(one, struct card, list_head); + struct card* that_card = container_of(the_other, struct card, list_head); + return this_card->card_num - that_card->card_num; +} + + static DECLARE_COMPARE_FN(card_compare){ if(!a) return b;