유 니 버 설 단 방향 링크 디자인 (2) - 인터페이스의 실현

인터페이스의 실현:
/***************************slist.c**********************************/
#include "slist.h"
#include "typedef.h"

#define SLIST_HEAD      0
#define SLIST_TAIL      -1

typedef struct _SListNode
{
    void *data;
    struct _SListNode *next;
    
}SListNode;

struct _SList
{
    SListNode* first;
    SlistDataDestroyFunc data_destroy;
    void* data_destroy_ctx;
};

static SListNode* slit_create_node(void *data)
{
    SListNode* node = (SListNode*)malloc(sizeof(SListNode));

    if(NULL != node)
    {                    
        node->data = data;
        node->next = NULL;
    }
    return node;
}

SList* slist_create(SlistDataDestroyFunc data_destroy, void* data_destroy_ctx)
{
    SList* this = NULL;	

    this = (SList*)malloc(sizeof(SList));	
    if(NULL != this)		
    {
        this->first = NULL;    
        this->data_destroy = data_destroy;
        this->data_destroy_ctx = data_destroy_ctx;
    }
    
    return this;
}

Ret slist_prepend(SList* this, void* data)
{   
    return slist_insert(this, SLIST_HEAD, data);
}

Ret slist_append(SList* this, void* data)
{      
   return slist_insert(this, SLIST_TAIL, data);
}

static SListNode* slist_get_prev_node(SList* this, size_t index, int fail_return_last)
{
    return_val_if_fail(this != NULL, NULL);

    SListNode* node = this->first;
    
    index--;
    while(node!= NULL && node->next != NULL && index > 0)
    {
        node =  node->next;    
        index--;
    }

    if(!fail_return_last)
    {
        return node = index > 0 ? NULL: node;
    }

    return node;    
}

Ret slist_insert(SList* this, size_t index, void* data)
{
    SListNode* node = NULL;
    SListNode* cursor = NULL;
    return_val_if_fail(this != NULL, RET_INVALIDPARM);

    node = slit_create_node(data);
    if(NULL == node)
    {
        return RET_OOM;
    }

    //null list
    if(this->first == NULL)
    {
        this->first = node;
        return RET_OK;
    }

    cursor = (index == 0) ? NULL: slist_get_prev_node(this, index, 1);
    if(index >= 0 && index < slist_length(this))
    {
        //head node
        if(NULL == cursor)
        {
            cursor = this->first;
            this->first = node;
            node->next = cursor;
        }
        else
        {
            node->next = cursor->next;
            cursor->next = node;
        }
    }
    else
    {
       /*default insert to tail if not find*/
       cursor->next = node;
       node->next = NULL;
    }    
    return RET_OK;
}

Ret slist_delete(SList* this, size_t index)
{
    return_val_if_fail(this != NULL, RET_INVALIDPARM);

    SListNode* node = NULL;
    SListNode* tmp = NULL;

    if(-1 == index)
    {
        return RET_OK;
    }

    //locate prev node of current node, which is different from dlist
    node = slist_get_prev_node(this, index, 1);
    if(0 == index)
    {
        node = this->first;
        this->first = node->next;
        free(node);
        node = NULL;
    }
    else
    {
        tmp = node->next;
        node->next = node->next->next;
        free(tmp);
        tmp = NULL;
    }

    return RET_OK;
}

Ret slist_get_by_index(SList* this, size_t index, void** data)
{
    return_val_if_fail(this != NULL, 0);

    SListNode* prev_node = NULL;    

    if(index == 0)
    {
        *data = this->first->data;
        return RET_OK;
    }
   
    prev_node = slist_get_prev_node(this, index, 1);

    if(NULL != prev_node)
    { 
       *data = prev_node->next->data;
    }
    
    return (prev_node != NULL) ? RET_OK : RET_FAILED;
}

Ret slist_set_by_index(SList* this, size_t index, void* data)
{
    return_val_if_fail(this != NULL, 0);

    SListNode* prev_node = NULL;   

    if(0 == index)
    {
        this->first->data = data;
        return RET_OK;
    }    
    
    prev_node = slist_get_prev_node(this, index, 1);

    if(prev_node != NULL)
    {
      prev_node->next->data = data;
    }
    
    return  (prev_node != NULL) ? RET_OK : RET_FAILED;
}

size_t slist_find(SList* this, SlistDataCmpFunc cmp, void* data)
{
    return_val_if_fail(this != NULL, 0);

    size_t index = 0;   
    SListNode* node = this->first;
    
    while(node != NULL)
    {        
        if(0 == cmp((void*)node->data, data))
        {
            return index;
        }
        node = node->next;        
        index++;
    }
    /*return -1 if not find */
    return -1; 
}

size_t slist_length(SList* this)
{
    return_val_if_fail(this != NULL, 0);

    size_t length = 0;
    SListNode* node = this->first;

    while(node != NULL)
    {
        node = node->next;
        length++;
    }
    return length;
}

static void slist_destroy_data(SList* this, void* data)
{
    if(this->data_destroy != NULL)
    {        
        this->data_destroy(this->data_destroy_ctx, data);
    }
    return;
}

static void slist_destroy_node(SList* this, SListNode* node)
{
    if(node != NULL)
    {      
        node->next = NULL;              
        slist_destroy_data(this, node->data);     
        free(node);    
    }
}

void slist_destroy(SList* this)
{
    return_if_fail(this != NULL);

    SListNode* iter = this->first;
    SListNode* next = NULL;

    while(iter != NULL)
    {
        next = iter->next;      
        slist_destroy_node(this, iter);
        iter = next;
    }

    this->first = NULL;
    free(this);
        
    return;
}

Ret slist_foreach(SList* this , SlistDataVisitFunc visit, void* data)
{
    return_val_if_fail(this != NULL, RET_INVALIDPARM);

    SListNode* node = this->first;

    while(node != NULL)
    {
        visit(data, node->data);
        node = node->next;
    }
    return RET_OK;
}

SList* slist_reverse(SList* this)
{
    assert(NULL != this);
    
    SListNode* pPrev = NULL;
    SListNode* pCurrent = this->first;
    SListNode* pNext = pCurrent->next;

    while(pNext->next != NULL)
    {
        pCurrent->next = pPrev;
        pPrev = pCurrent;
        pCurrent = pNext;
        pNext = pNext->next;
    }

    pCurrent->next = pPrev;
    pPrev = pCurrent;
    pNext->next = pCurrent;

    this->first = pNext;
    
    return this;
}

좋은 웹페이지 즐겨찾기