Wednesday, 22 August 2018

Doubly linked list

/*
 * File name: m_list.h
 * Author: Seree Rakwong
 * Date: 13-SEP-2013
 *
 * A list is implemented by the range as [a, b) (including a, but b)
 */

#ifndef _MLIST_H_
#define _MLIST_H_

#include <stdlib.h>
#include <string.h>
#include "m_node.h"

#ifdef __cplusplus
extern "C" {
#endif
struct _LIST_STRUCT;
typedef struct _LIST_STRUCT list_t;

struct _LIST_ITER_STRUCT;
typedef struct _LIST_ITER_STRUCT* list_iter_t;

list_t* list_create();
void    list_destroy(list_t*);

typedef long (*fn_list_insert_first)(list_t*, const void*, unsigned long);
typedef long (*fn_list_insert_last)(list_t*, const void*, unsigned long);
typedef long (*fn_list_insert_before)(list_t*, list_iter_t, const void*, unsigned long);
typedef long (*fn_list_insert_after)(list_t*, list_iter_t, const void*, unsigned long);
typedef long (*fn_list_remove_at)(list_t*, list_iter_t);
typedef long (*fn_list_remove_all)(list_t*);
typedef long (*fn_list_remove_first)(list_t*);
typedef long (*fn_list_remove_last)(list_t*);
typedef unsigned long (*fn_list_get_count)(list_t*);
typedef list_iter_t   (*fn_list_begin)(list_t*);
typedef list_iter_t   (*fn_list_end)(list_t*);
typedef node_t        (*fn_list_at)(list_iter_t iter);

/*
long list_insert_first(list_t*, const void*, unsigned long);
long list_insert_last(list_t*, const void*, unsigned long);
long list_insert_before(list_t*, list_iter_t, const void*, unsigned long);
long list_insert_after(list_t*, list_iter_t, const void*, unsigned long);
long list_remove_at(list_t*, list_iter_t);
long list_remove_all(list_t*);
long list_remove_first(list_t*);
long list_remove_last(list_t*);
unsigned long list_get_count(list_t*);
list_iter_t   list_begin(list_t*);
list_iter_t   list_end(list_t*);
node_t        list_at(list_iter_t iter);
*/

struct _LIST_ITER_STRUCT
{
    node_t      node;
    list_iter_t prev;
    list_iter_t next;
};

struct _LIST_STRUCT
{
    list_iter_t     head;
    list_iter_t     tail;
    unsigned long   nodes;
    /* methods */
    fn_list_insert_first        insert_first;
    fn_list_insert_last         insert_last;
    fn_list_insert_before       insert_before;
    fn_list_insert_after        insert_after;
    fn_list_remove_at           remove_at;
    fn_list_remove_all          remove_all;
    fn_list_remove_first        remove_first;
    fn_list_remove_last         remove_last;
    fn_list_get_count           count;
    fn_list_begin               begin;
    fn_list_end                 end;
    fn_list_at                  at;
};

#ifdef __cplusplus
}
#endif

#endif /* _MLIST_H_ */

/*
 * File name: m_list.c
 * Author: Seree Rakwong
 * Date: 13-SEP-2013
 */
#include "m_list.h"

#ifdef __cplusplus
extern "C" {
#endif

list_iter_t _list_iterator_init(const void* vp, unsigned long size)
{
    list_iter_t iter = (list_iter_t)malloc(sizeof(struct _LIST_ITER_STRUCT));
    if (iter != 0)
    {
        memset(iter, 0, sizeof(struct _LIST_ITER_STRUCT));
        if (vp && size > 0)
        {
            iter->node = node_init(vp, size);
        }
    }
    return iter;
}

void _list_iterator_release(list_iter_t iter)
{
    if (iter)
    {
        if (iter->node)
        {
            node_release(iter->node);
        }
        free(iter);
    }
}

/*------------------------------------------------------------*/
long list_insert_first(list_t*, const void*, unsigned long);
long list_insert_last(list_t*, const void*, unsigned long);
long list_insert_before(list_t*, list_iter_t, const void*, unsigned long);
long list_insert_after(list_t*, list_iter_t, const void*, unsigned long);
void list_free(list_t*);
long list_remove_at(list_t*, list_iter_t);
long list_remove_all(list_t*);
long list_remove_first(list_t*);
long list_remove_last(list_t*);
unsigned long list_get_count(list_t*);
list_iter_t   list_begin(list_t*);
list_iter_t   list_end(list_t*);
node_t        list_at(list_iter_t iter);

/*------------------------------------------------------------*/
list_t* list_create()
{
    list_t* list = (list_t*)malloc(sizeof(list_t));
    
    if (list != 0)
    {
        list->nodes = 0;
        list->head = list->tail = _list_iterator_init(0, 0);
        /* init methods */
        list->insert_first  = list_insert_first;
        list->insert_last   = list_insert_last;
        list->insert_before = list_insert_before;
        list->insert_after  = list_insert_after;
        list->remove_at     = list_remove_at;
        list->remove_all    = list_remove_all;
        list->remove_first  = list_remove_first;
        list->remove_last   = list_remove_last;
        list->count         = list_get_count;
        list->begin         = list_begin;
        list->end           = list_end;
        list->at            = list_at;
    }
    return list;
}

void    list_destroy(list_t* list)
{
    if (list)
    {
        list->remove_all(list);
        free(list);
    }
}

long list_insert_first(list_t* list, const void* vp, unsigned long size)
{
    long rc = 0;
    list_iter_t iter = 0;
    
    if (vp && size)
    {
        iter = _list_iterator_init(vp, size);
        if (iter != 0)
        {
            iter->next = list->head;
            list->head->prev = iter;
            list->head = iter;

            ++list->nodes;
        }
        else
        {
            rc = -2;
        }
    }
    else
    {
        rc = -1;
    }
    return rc;
}

long list_insert_last(list_t* list, const void* vp, unsigned long size)
{
    long rc = 0;
    list_iter_t iter = 0;
    
    if (vp && size)
    {
        iter = _list_iterator_init(vp, size);
        if (iter != 0)
        {
            iter->next = list->tail;
            iter->prev = list->tail->prev;

            if (list->tail->prev)
            {
                list->tail->prev->next = iter;
            }
            list->tail->prev = iter;

            if (list->head == list->tail)
            {
                list->head = iter;
            }

            ++list->nodes;
        }
        else
        {
            rc = -2;
        }
    }
    else
    {
        rc = -1;
    }
    return rc;
}

long list_insert_before(list_t* list, list_iter_t iter_after, const void* vp, unsigned long size)
{
    long rc = 0;
    list_iter_t iter = 0;
    
    if (vp && size > 0)
    {
        iter = _list_iterator_init(vp, size);
        if (iter != 0)
        {
            iter->next = iter_after;
            iter->prev = iter_after->prev;

            if (iter_after->prev)
            {
                iter_after->prev->next = iter;
            }
            iter_after->prev = iter;

            ++list->nodes;
        }
        else
        {
            rc = -2;
        }
    }
    else
    {
        rc = -1;
    }
    return rc;
}

long list_insert_after(list_t* list, list_iter_t iter_before, const void* vp, unsigned long size)
{
    long rc = 0;
    list_iter_t iter = 0;
    
    if (vp && size > 0)
    {
        iter = _list_iterator_init(vp, size);
        if (iter != 0)
        {
            iter->prev = iter_before;
            iter->next = iter_before->next;

            if (iter_before->next)
            {
                iter_before->next->prev = iter;
            }
            iter_before->next = iter;

            ++list->nodes;
        }
        else
        {
            rc = -2;
        }
    }
    else
    {
        rc = -1;
    }
    return rc;
}

long list_remove_at(list_t* list, list_iter_t iter)
{
    long rc = 0;

    /* is it a head item? */
    if (iter == list->head)
    {
        return list->remove_first(list);
    }

    /* is it a tail item? */
    if (iter == list->tail)
    {
        return list->remove_last(list);
    }

    /* link them */
    if (iter->next)
    {
        iter->next->prev = iter->prev;
    }
    if (iter->prev)
    {
        iter->prev->next = iter->next;
    }

    /* remove it */
    _list_iterator_release(iter);

    if (list->nodes > 0)
    {
        --list->nodes;
    }

    return rc;
}

long list_remove_all(list_t* list)
{
    long rc = 0;
    list_iter_t iter = list->head;

    while (iter != list->tail)
    {
        list->remove_first(list);
        iter = list->head;
    }
    /*
    * set the tail and head of the list
    */
    list->tail->prev = 0;
    list->head = list->tail;
    list->nodes = 0;

    return rc;
}

long list_remove_first(list_t* list)
{
    long rc = 0;
    list_iter_t iter = list->head;

    if (iter == list->tail)
    {
        /* no more item to remove */
        return 0;
    }

    list->head = iter->next;
    list->head->prev = 0;
    /* ok to free the memory */
    _list_iterator_release(iter);

    if (list->nodes > 0)
    {
        --list->nodes;
    }

    return rc;
}

long list_remove_last(list_t* list)
{
    long rc = 0;
    list_iter_t iter = list->tail->prev;

    if (!iter)
    {
        /* no more item to remove */
        return 0;
    }

    list->tail->prev = iter->prev;
    if (iter->prev)
    {
        iter->prev->next = list->tail;
    }
    /* ok to free the memory */
    _list_iterator_release(iter);
    
    if (list->nodes > 0)
    {
        --list->nodes;
    }
    return rc;
}

unsigned long list_get_count(list_t* list)
{
    return list->nodes;
}

list_iter_t list_begin(list_t* list)
{
    return list->head;
}

list_iter_t list_end(list_t* list)
{
    return list->tail;
}

node_t list_at(list_iter_t iter)
{
    if (iter)
    {
        return iter->node;
    }
    return 0;
}

#ifdef __cplusplus
}
#endif

No comments:

Post a Comment