C++工具:C语言链表实现C++STL接口--支持泛型宏

本文介绍了一个C++工具,它实现了C风格的链表,但具有STL接口和泛型支持。此链表支持自定义内存分配器,能处理自定义类型的深拷贝,适用于多种数据类型,包括基本类型和字符串。文章提供了使用示例,展示了如何创建、遍历、添加、删除链表元素,并讨论了自定义内存分配的重要性。
摘要由CSDN通过智能技术生成
//!
//! C++工具:C语言链表实现C++STL接口--支持泛型宏
//!
//! == 工具简介 ==
//! 本文是上篇文章的加强版
//!     上篇文章: C++工具:仿C++STL接口的C风格链表--支持函数泛型
//!
//! 上篇文章实现了C语言链表的泛型与C++STL接口,但使用的是函数风格,
//!     不同类型需要用不同函数操作,略显麻烦,且不支持深拷贝数据结构,
//!     指针类型需要手动分配和循环链表释放内存
//!
//! 本章带来的加强版链表采用面向对象的思想,使用与接口与C++STL类似,
//! 	提供自定义内存分配器,支持自定义类型的深拷贝操作,
//! 	默认自动生成八大基本类型和字符串类型链表,
//! 	提供默认浅拷贝分配器和字符串分配器
//!
//! 加强版链表利用结构体封装回调指针实现接口的统一,
//!     利用宏泛型生成对应数据结构类型
//! == 工具简介 ==
//!
//!
//! == 使用说明 ==
//! 以字符串类型作为例子:
//!
//!     == 代码段 ==
//!     // Tlist_make宏的等价声明: Tlist_Tcharp *ls = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
//!     Tlist_Tcharp *ls = Tlist_make(Tcharp);
//!     Tfor_each(ls,it,Tcharp)
//!     {
//!         printf("%s\n",it->value);
//!     }
//!     Tclose_Tcharp(ls);
//!     == 代码段 ==
//!
//! 1.Tlist_Tcharp为链表类型,类似list<char*>
//! 2.Topen_Tcharp函数类似构造函数,链表需要构造函数初始化才能使用
//! 3.Tmalloc_Tcharp是内存分配函数,Tfree_Tcharp是内存释放函数
//! 4.内存分配器可以自定义分配结构体的内存分配问题,和深拷贝问题
//! 5.Tfor_each是遍历宏,参数(1:链表对象,2:返回的迭代器,3:数据接口类型)
//! 6.Tclose_Tcharp函数类似析构函数,释放链表的元素内存与链表本身的内存
//! 7.自定义分配器时注意内存泄露问题,内存分配与释放函数需完全对应
//! 8.Tlist_make宏是快速声明宏,方便使用,如果是自定义分配器,必须符合函数签名格式
//! == 使用说明 ==
//!
//!
//! == 展示顺序 ==
//! 1.main测试代码
//! 2.Tlist_Tapi.h文件
//! 3.测试参考头文件
//! == 展示顺序 ==
//!
//!
//! 结束语:
//!     该链表的使用符合C++程序员在C语言的使用习惯,
//!         也解决了C语言下C++程序员无容器可用的烦恼,
//!         与C语言内核链表相比泛型容器可以降低学习成本
//!     本文提供的容器可能还有很多不足的地方,如果有发现问题请在评论区反馈,
//!         如果本文给你提供了C语言下其他C++泛型容器的设计思想,你已经实现并希望分享给大家,
//!         请在评论区留言并将代码提交到GIthub上
//!     GIthub网址:https://github.com/HellowAmy/cpp_base.git
//!
//!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Tlist_Tapi.h"

//== 自定义类型:自定义内存分配:注意生成顺序 (类型定义 -> 宏代码生成 -> 自定义分配器) ==
typedef struct meg meg;
struct meg
{
    int len;
    char *type;
    char data[100];
};

//注意:
//  当链表调用push_back等需要分配内存的函数元素的函数时,调用Tmalloc
//  调用pop_back等移除元素时需要释放内存的函数时,调用Tfree
//对象
Tlist_Tbuild(Tmeg,meg)
static void Tmalloc_Tmeg(Tls_Tmeg *head,meg value)
{
    head->value.len = value.len;
    head->value.type = (char*)malloc(strlen(value.type) +1);
    strcpy(head->value.type,value.type);
    strcpy(head->value.data,value.data);
}
static void Tfree_Tmeg(Tls_Tmeg *head)
{
    free(head->value.type);
}

//指针
Tlist_Tbuild(Tmegp,meg *)
static void Tmalloc_Tmegp(Tls_Tmegp *head,const meg *value)
{
    //给链表存储的指针分配内存
    head->value = (meg *)malloc(sizeof(meg));

    //给结构体内的成员分配内存
    head->value->type = (char*)malloc(strlen(value->type) +1);
    head->value->type[strlen(value->type)] = '\0';

    head->value->len = value->len;
    strcpy(head->value->type,value->type);
    strcpy(head->value->data,value->data);
}
static void Tfree_Tmegp(Tls_Tmegp *head)
{
    //Tmalloc函数分配了多少Tfee就释放多少
    free(head->value->type);
    free(head->value);
}
//== 自定义类型:自定义内存分配:注意生成顺序 (类型定义 -> 宏代码生成 -> 自定义分配器) ==


//== 自定义类型:(使用默认分配器需要外部malloc分配内存,否则会浅拷贝问题) ==
typedef struct dire dire;
struct dire
{
    int x;
    int y;
    int z;
    char *data;
};
Tls_Tbase(Tdirep,dire *)
//== 自定义类型:(使用默认分配器需要外部malloc分配内存,否则会浅拷贝问题) ==


//各类型加入测试
void test_1()
{
    //== 基础类型测试 ==
    printf("== 基础类型测试 ==\n");
    {
        Tlist_Tchar *ls =  Tlist_make(Tchar); //等价下方声明
//        Tlist_Tchar *ls = Topen_Tchar(Tmalloc_Tchar,Tfree_Tchar);
        const char t1 = 'a';
        char t2 = 'b';
        ls->push_back(ls,t1);
        ls->push_back(ls,t2);
        ls->push_back(ls,'c');

        Tfor_each(ls,it,Tchar)
        {
            printf("%c\n",it->value);
        }
        Tclose_Tchar(ls);
    }
    {
        Tlist_Tint *ls = Topen_Tint(Tmalloc_Tint,Tfree_Tint);
        const int t1 = 100;
        int t2 = 200;
        ls->push_back(ls,t1);
        ls->push_back(ls,t2);
        ls->push_back(ls,300);

        Tfor_each(ls,it,Tint)
        {
            printf("%d\n",it->value);
        }
        Tclose_Tint(ls);
    }
    //== 基础类型测试 ==


    //== 字符串测试 ==
    printf("== 字符串测试 ==\n");
    {
        Tlist_Tcharp *ls = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
        const char* t1 = "a1";
        char* t2 = "a2";
        ls->push_back(ls,t1);
        ls->push_back(ls,t2);
        ls->push_back(ls,"a3");

        Tfor_each(ls,it,Tcharp)
        {
            printf("%s\n",it->value);
        }
        Tclose_Tcharp(ls);
    }
    {
        Tlist_Tcharp *ls = Tlist_make(Tcharp);
        const char* t1 = "a1";
        char* t2 = "a2";
        ls->push_back(ls,t1);
        ls->push_back(ls,t2);
        ls->push_back(ls,"a3");

        Tfor_each(ls,it,Tcharp)
        {
            printf("%s\n",it->value);
        }
        Tclose_Tcharp(ls);
    }
    //== 字符串测试 ==


    //== 自定义测试 ==
    printf("== 自定义测试 ==\n");
    {
        Tlist_Tmeg *ls = Topen_Tmeg(Tmalloc_Tmeg,Tfree_Tmeg);
        {
            const meg t1 = {0,"00","000"};

            meg t2;
            t2.len = 1;
            t2.type = (char *)malloc(100);
            strcpy(t2.type,"11");
            strcpy(t2.data,"111");
            ls->push_back(ls,t1);
            ls->push_back(ls,t2);
        }
        Tfor_each(ls,it,Tmeg)
        {
            printf("p1:[%d : %s : %s]\n",it->value.len,it->value.data,it->value.type);
        }
        Tclose_Tmeg(ls);
    }
    {
        Tlist_Tmegp *ls = Topen_Tmegp(Tmalloc_Tmegp,Tfree_Tmegp);
        {
            meg* t2 = (meg*)malloc(sizeof(meg));
            t2->len = 1;
            t2->type = (char *)malloc(100);
            strcpy(t2->type,"11");
            strcpy(t2->data,"111");
            ls->push_back(ls,t2);

            //使用完了需要释放
            free(t2->type);
        }
        Tfor_each(ls,it,Tmegp)
        {
            printf("p2:[%d : %s : %s]\n",it->value->len,it->value->data,it->value->type);
        }
        Tclose_Tmegp(ls);
    }
    {
        Tlist_Tdirep *ls = Tlist_make(Tdirep);//等价下方声明
//        Tlist_Tdirep *ls = Topen_Tdirep(Tmalloc_Tdirep,Tfree_Tdirep);
        {
            //使用默认分配器时,刚分配加入链表的变量不要释放
            dire *t1 = (dire *)malloc(sizeof(dire));
            t1->x = 1;
            t1->y = 2;
            t1->z = 3;
            t1->data = (char *)malloc(100);
            strcpy(t1->data,"4");
            ls->push_back(ls,t1);

            dire *t2 = (dire *)malloc(sizeof(dire));
            t2->x = 11;
            t2->y = 22;
            t2->z = 33;
            t2->data = (char *)malloc(100);
            strcpy(t2->data,"44");
            ls->push_back(ls,t2);
        }
        //使用默认分配器时,关闭链表时需要手动释放元素的内存
        //for
        Tfor_each(ls,it,Tdirep)
        {
            printf("p3:[%d : %d : %d : %s]\n",it->value->x,it->value->y,it->value->z,it->value->data);
        }
        Tclose_Tdirep(ls);
    }
    //== 自定义测试 ==

    printf("== 测试结束 ==\n");
}

//== 接口测试 ==
void test_2()
{
    printf("\n== 接口测试 ==\n");
    printf("== 操作ls1 ==\n");

    //使用链表时,需要开启和关闭链表
    Tlist_Tcharp *ls1 = Topen_Tcharp(Tmalloc_Tcharp,Tfree_Tcharp);
    ls1->push_back(ls1,"s[1]");
    ls1->push_back(ls1,"s[2]");
    ls1->push_front(ls1,"s[-1]");
    ls1->push_front(ls1,"s[-2]");
    ls1->insert(ls1,2,"s[0.1]");
    ls1->insert(ls1,3,"s[0.2]");

    Tfor_each(ls1,it,Tcharp)
    {
        printf("%s\n",it->value);
    }
    printf("链表个数: %ld\n",ls1->size);

    Tlist_Tcharp *ls2 = Tclone_Tcharp(ls1);
    printf("克隆链表ls2: 链表个数: %ld\n",ls2->size);

    printf("\n==  移除元素 ==\n");
    ls1->pop_back(ls1);
    ls1->pop_front(ls1);
    ls1->erase(ls1,1);

    Tfor_each(ls1,it,Tcharp)
    {
        printf("%s\n",it->value);
    }

    printf("链表个数: %ld\n",ls1->size);

    ls1->clear(ls1); //清空链表
    printf("清空链表:链表个数: %ld\n",ls1->size);

    Tclose_Tcharp(ls1); //关闭链表


    //操作ls2
    printf("== 操作ls2 ==\n");
    Tfor_each(ls2,it,Tcharp)
    {
        printf("%s\n",it->value);
    }
    Tclose_Tcharp(ls2); //关闭链表

    printf("== 测试结束 ==\n");
}

int main()
{

    printf("== begin ==\n");

    test_1();
    test_2();

    printf("== end ==\n");
    return 0;
}

/*
 * 测试结果
 *
== begin ==
== 基础类型测试 ==
a
b
c
100
200
300
== 字符串测试 ==
a1
a2
a3
== 自定义测试 ==
p1:[0 : 000 : 00]
p1:[1 : 111 : 11]
p2:[1 : 111 : 11]
p3:[1 : 2 : 3 : 4]
p3:[11 : 22 : 33 : 44]
== 测试结束 ==

== 接口测试 ==
== 操作ls1 ==
s[-2]
s[-1]
s[0.1]
s[0.2]
s[1]
s[2]
链表个数: 6
克隆链表ls2: 链表个数: 6

==  移除元素 ==
s[-1]
s[0.2]
s[1]
链表个数: 3
清空链表:链表个数: 0
== 操作ls2 ==
s[-2]
s[-1]
s[0.1]
s[0.2]
s[1]
s[2]
== 测试结束 ==
== end ==

*/
//!
//! Tlist_Tapi.h
//!
#ifndef TLIST_TAPI_H
#define TLIST_TAPI_H

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

//未使用变量警告去除
#define Tun(x) (void)(x)

//链表遍历宏
#define Tfor_each(ls,it,Tapi)  \
    for(Tls_##Tapi *it = ls->head->next;it!=NULL;it=it->next)

//定义函数代码生成宏
#define Tlist_Tbuild(Tapi,Tvalue)                                               \
typedef struct Tls_##Tapi Tls_##Tapi;                                           \
struct Tls_##Tapi                                                               \
{                                                                               \
    Tvalue  value;                                                              \
    Tls_##Tapi *prev;                                                           \
    Tls_##Tapi *next;                                                           \
};                                                                              \
                                                                                \
typedef struct Tlist_##Tapi Tlist_##Tapi;                                       \
struct Tlist_##Tapi                                                             \
{                                                                               \
    void    (*alloc)       (Tls_##Tapi *head,const Tvalue value);               \
    void    (*free)        (Tls_##Tapi *head);                                  \
    void    (*init)        (Tls_##Tapi *head);                                  \
    void    (*push_back)   (Tlist_##Tapi *head,const Tvalue value);             \
    void    (*push_front)  (Tlist_##Tapi *head,const Tvalue value);             \
    int     (*insert)      (Tlist_##Tapi *head,size_t pos,const Tvalue value);  \
    void    (*pop_back)    (Tlist_##Tapi *head);                                \
    void    (*pop_front)   (Tlist_##Tapi *head);                                \
    int     (*erase)       (Tlist_##Tapi *head,size_t pos);                     \
    void    (*clear)       (Tlist_##Tapi *head);                                \
    size_t  size;                                                               \
    Tls_##Tapi *head;                                                           \
};                                                                              \
                                                                                \
__attribute__((unused))                                                         \
static void list_init_##Tapi(Tls_##Tapi *head)                                  \
{                                                                               \
    if(head == NULL) return;                                                    \
    head->prev = NULL;                                                          \
    head->next = NULL;                                                          \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void list_push_back_##Tapi(Tlist_##Tapi *ls,const Tvalue value)          \
{                                                                               \
    if(ls->head == NULL) return;                                                \
    Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi));           \
    list_init_##Tapi(new_value);                                                \
                                                                                \
    if(ls->size == 0)                                                           \
    {                                                                           \
        ls->head->prev = new_value;                                             \
        ls->head->next = new_value;                                             \
        new_value->prev = ls->head;                                             \
    }                                                                           \
    else                                                                        \
    {                                                                           \
        new_value->prev = ls->head->prev;                                       \
        ls->head->prev->next = new_value;                                       \
        ls->head->prev = new_value;                                             \
    }                                                                           \
    ls->size += 1;                                                              \
    ls->alloc(new_value,value);                                                 \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void list_push_front_##Tapi(Tlist_##Tapi *ls,const Tvalue value)         \
{                                                                               \
    if(ls->head == NULL) return;                                                \
    Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi));           \
    list_init_##Tapi(new_value);                                                \
                                                                                \
    if(ls->size == 0)                                                           \
    {                                                                           \
        ls->head->prev = new_value;                                             \
        ls->head->next = new_value;                                             \
        new_value->prev = ls->head;                                             \
    }                                                                           \
    else                                                                        \
    {                                                                           \
        ls->head->next->prev = new_value;                                       \
        new_value->next = ls->head->next;                                       \
        new_value->prev = ls->head;                                             \
        ls->head->next = new_value;                                             \
    }                                                                           \
    ls->size += 1;                                                              \
    ls->alloc(new_value,value);                                                 \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static int list_insert_##Tapi(Tlist_##Tapi *ls,size_t pos,const Tvalue value)   \
{                                                                               \
    if(ls->head == NULL || pos >= ls->size) return 0;                           \
    Tls_##Tapi *new_value = (Tls_##Tapi *)malloc(sizeof(Tls_##Tapi));           \
    list_init_##Tapi(new_value);                                                \
                                                                                \
    size_t count = 0;                                                           \
    Tls_##Tapi *it = ls->head->next;                                            \
    for(;it != NULL;it = it->next)                                              \
    {                                                                           \
        if(count == pos) break;                                                 \
        count++;                                                                \
    }                                                                           \
                                                                                \
    new_value->next = it;                                                       \
    new_value->prev = it->prev;                                                 \
    it->prev->next = new_value;                                                 \
    it->prev = new_value;                                                       \
                                                                                \
    ls->size += 1;                                                              \
    ls->alloc(new_value,value);                                                 \
    return 1;                                                                   \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void list_pop_back_##Tapi(Tlist_##Tapi *ls)                              \
{                                                                               \
    if(ls->head == NULL || ls->size == 0) return ;                              \
    ls->size -= 1;                                                              \
                                                                                \
    Tls_##Tapi *end = ls->head->prev;                                           \
    ls->head->prev = end->prev;                                                 \
    end->prev->next = NULL;                                                     \
    ls->free(end);                                                              \
    free(end);                                                                  \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void list_pop_front_##Tapi(Tlist_##Tapi *ls)                             \
{                                                                               \
    if(ls->head == NULL || ls->size == 0) return ;                              \
    ls->size -= 1;                                                              \
                                                                                \
    Tls_##Tapi *begin = NULL;                                                   \
    if(ls->size == 0)                                                           \
    {                                                                           \
        begin = ls->head->next;                                                 \
        ls->head->next = NULL;                                                  \
    }                                                                           \
    else                                                                        \
    {                                                                           \
        begin = ls->head->next;                                                 \
        ls->head->next = begin->next;                                           \
        begin->next->prev = ls->head;                                           \
    }                                                                           \
    ls->free(begin);                                                            \
    free(begin);                                                                \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static int list_erase_##Tapi(Tlist_##Tapi *ls,size_t pos)                       \
{                                                                               \
    if(ls->head == NULL || ls->size == 0 || pos >= ls->size) return 0;          \
    ls->size -= 1;                                                              \
                                                                                \
    size_t count = 0;                                                           \
    Tls_##Tapi *it = ls->head->next;                                            \
    for(;it != NULL;it = it->next)                                              \
    {                                                                           \
        if(count == pos) break;                                                 \
        count++;                                                                \
    }                                                                           \
                                                                                \
    Tls_##Tapi *now = NULL;                                                     \
    if(pos == ls->size || ls->size == 0)                                        \
    {                                                                           \
        now = it;                                                               \
        it->prev->next = NULL;                                                  \
        ls->head->prev = it->prev;                                              \
    }                                                                           \
    else                                                                        \
    {                                                                           \
        now = it;                                                               \
        it->prev->next = it->next;                                              \
        it->next->prev = it->prev;                                              \
                                                                                \
    }                                                                           \
    ls->free(now);                                                              \
    free(now);                                                                  \
    return 1;                                                                   \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void list_clear_##Tapi(Tlist_##Tapi *ls)                                 \
{                                                                               \
    if(ls->head == NULL) return;                                                \
    while(1)                                                                    \
    {                                                                           \
        Tls_##Tapi *begin = ls->head->next;                                     \
        if(begin == NULL) break;                                                \
        ls->head->next = ls->head->next->next;                                  \
        ls->free(begin);                                                        \
        free(begin);                                                            \
    }                                                                           \
    ls->size = 0;                                                               \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static Tlist_##Tapi* Topen_##Tapi                                               \
    (void (*alloc)(Tls_##Tapi *head,const Tvalue value),                        \
     void (*free)(Tls_##Tapi *head))                                            \
{                                                                               \
    Tlist_##Tapi *ls = (Tlist_##Tapi *)malloc(sizeof(Tlist_##Tapi));            \
    ls->head = (Tls_##Tapi*)malloc(sizeof(Tls_##Tapi));                         \
                                                                                \
    ls->alloc       = alloc;                                                    \
    ls->free        = free;                                                     \
    ls->init        = list_init_##Tapi;                                         \
    ls->push_back   = list_push_back_##Tapi;                                    \
    ls->push_front  = list_push_front_##Tapi;                                   \
    ls->insert      = list_insert_##Tapi;                                       \
    ls->pop_back    = list_pop_back_##Tapi;                                     \
    ls->pop_front   = list_pop_front_##Tapi;                                    \
    ls->erase       = list_erase_##Tapi;                                        \
    ls->clear       = list_clear_##Tapi;                                        \
                                                                                \
    ls->size = 0;                                                               \
    ls->init(ls->head);                                                         \
    return ls;                                                                  \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static void Tclose_##Tapi(Tlist_##Tapi *ls)                                     \
{                                                                               \
    ls->clear(ls);                                                              \
    free(ls->head);                                                             \
    free(ls);                                                                   \
}                                                                               \
                                                                                \
__attribute__((unused))                                                         \
static Tlist_##Tapi* Tclone_##Tapi(Tlist_##Tapi *ls)                            \
{                                                                               \
    if(ls == NULL) return NULL;                                                 \
    Tlist_##Tapi *ls_new = Topen_##Tapi(ls->alloc,ls->free);                    \
                                                                                \
    for(Tls_##Tapi *it = ls->head->next;it!=NULL;it=it->next)                   \
    {                                                                           \
        ls_new->push_back(ls_new,it->value);                                    \
    }                                                                           \
    return ls_new;                                                              \
}                                                                               \


//定义生成浅拷贝分配器
#define Tac_Tdefault(Tapi,Tvalue)                                           \
__attribute__((unused))                                                     \
static void Tmalloc_##Tapi(Tls_##Tapi *head,const Tvalue value)             \
{ head->value = (Tvalue)value; }                                            \
__attribute__((unused))                                                     \
static void Tfree_##Tapi(Tls_##Tapi *head)                                  \
{ Tun(head); }                                                              \

//定义生成字符串分配器
#define Tac_Tcharp(Tapi)                                                    \
__attribute__((unused))                                                     \
static void Tmalloc_Tcharp(Tls_##Tapi *head,const char* value)              \
{                                                                           \
    head->value = (char*)malloc(strlen(value) +1);                          \
    strncpy(head->value,value,strlen(value));                               \
    head->value[strlen(value)] = '\0';                                      \
}                                                                           \
__attribute__((unused))                                                     \
static void Tfree_Tcharp(Tls_##Tapi *head)                                  \
{ free(head->value); }                                                      \


//== 定义生成对应类型代码 + 浅拷贝分配器 ==
#define Tls_Tbase(Tapi,Tvalue)                  \
    Tlist_Tbuild(Tapi,Tvalue)                   \
    Tac_Tdefault(Tapi,Tvalue)                   \

//== 定义生成对应类型代码 + 字符串分配器 ==
#define Tls_Tcharp()                            \
    Tlist_Tbuild(Tcharp,char *)                 \
    Tac_Tcharp(Tcharp)                          \

//===== 最终代码生成 =====
//基础类型(浅拷贝存储)
Tls_Tbase(Tchar,char)
Tls_Tbase(Tshort,short)
Tls_Tbase(Tint,int)
Tls_Tbase(Tlong,long)
Tls_Tbase(Tlonglong,long long)
Tls_Tbase(Tfloat,float)
Tls_Tbase(Tdouble,double)

//字符串(深拷贝特例)
Tls_Tcharp()
//===== 最终代码生成 =====

//== 快速构造的工厂宏 ==
#define Tlist_make(Tapi) Topen_##Tapi(Tmalloc_##Tapi,Tfree_##Tapi)

#endif // TLIST_TAPI_H
//! 
//! 测试参考代码
//! 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Tlist_for(it,head) for(Tlist_c *it = head.next;it != NULL;it = it->next)
#define Tlist_for_p(it,head) for(Tlist_c *it = head->next;it != NULL;it = it->next)

//类型宏
#define Tvalue char *
//#define Tvalue int
//#define Tvalue msg

//存放数据的链表
typedef struct Tlist_c Tlist_c;
struct Tlist_c
{
    Tvalue  value;
//    size_t  size;
    Tlist_c *prev;
    Tlist_c *next;
};

//操作结构体--集合操作链表回调函数的数据结构
typedef struct Tlist_ac Tlist_ac;
struct Tlist_ac
{
    void    (*alloc)       (Tlist_c *head,const Tvalue value);
    void    (*free)        (Tlist_c *head);
    void    (*init)        (Tlist_c *head);
    void    (*push_back)   (Tlist_ac *head,const Tvalue value);
    void    (*push_front)  (Tlist_ac *head,const Tvalue value);
    int     (*insert)      (Tlist_ac *head,size_t pos,const Tvalue value);
    void    (*pop_back)    (Tlist_ac *head);
    void    (*pop_front)   (Tlist_ac *head);
    int     (*erase)       (Tlist_ac *head,size_t pos);
    void    (*clear)       (Tlist_ac *head);
//    Tlist_ac (*clone)      (Tlist_ac *head);
//    size_t  (*size)        (Tlist_ac *head);
    size_t  size;
    Tlist_c *head; //链表
};

//链表的初始化函数,使用链表前必须初始化
static void list_init(Tlist_c *head)
{
    if(head == NULL) return;
//    head->size = 0;
    head->prev = NULL;
    head->next = NULL;
}

static void list_push_back(Tlist_ac *ls,const Tvalue value)
{
    //分配空间
    if(ls->head == NULL) return;
    Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
    list_init(new_value);

    //连接到头节点
    if(ls->size == 0)
    {
        //1.头节点的前后指针,指到新节点
        //2.新节点前指针,指到头节点
        ls->head->prev = new_value;
        ls->head->next = new_value;
        new_value->prev = ls->head;
    }
    else
    {
        //1.新节点前节点,指向头节点前指针(头节点前指针等于尾节点)
        //2.尾节点的后指针,指到新节点
        //3.头节点前指针,指到新节点(等于将新节点当做尾节点)
        new_value->prev = ls->head->prev;
        ls->head->prev->next = new_value;
        ls->head->prev = new_value;
    }
    ls->size += 1;              //计数
    ls->alloc(new_value,value); //赋值
}

static void list_push_front(Tlist_ac *ls,const Tvalue value)
{
    //分配空间
    if(ls->head == NULL) return;
    Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
    list_init(new_value);

    //连接到头节点
    if(ls->size == 0)
    {
        //参考: list_push_back
        ls->head->prev = new_value;
        ls->head->next = new_value;
        new_value->prev = ls->head;
    }
    else
    {
        //1.第一个带数据节点的前指针,指向新节点
        //2.新节点的后指针,指向第一个带数据节点
        //3.新节点的前指针,指向头节点
        //4.头节点的后指针,指向新节点
        ls->head->next->prev = new_value;
        new_value->next = ls->head->next;
        new_value->prev = ls->head;
        ls->head->next = new_value;
    }
    ls->size += 1;              //计数
    ls->alloc(new_value,value); //赋值
}

static int list_insert(Tlist_ac *ls,size_t pos,const Tvalue value)
{
    //分配空间
    if(ls->head == NULL || pos >= ls->size) return 0;
    Tlist_c *new_value = (Tlist_c *)malloc(sizeof(Tlist_c));
    list_init(new_value);

    //获取指定的当前节点
    size_t count = 0;
    Tlist_c *it = ls->head->next;
    for(;it != NULL;it = it->next)
    {
        if(count == pos) break;
        count++;
    }

    //1.新节点后指针,指向当前节点
    //2.新节点前指针,指向当前节点的前指针(等于当前节点的前节点)
    //3.当前节点的前节点的后指针,指向新节点
    //4.当前节点前指针,指向新节点
    new_value->next = it;
    new_value->prev = it->prev;
    it->prev->next = new_value;
    it->prev = new_value;

    ls->size += 1;              //计数
    ls->alloc(new_value,value); //赋值
    return 1;
}

static void list_pop_back(Tlist_ac *ls)
{
    if(ls->head == NULL || ls->size == 0) return ;
    ls->size -= 1; //计数移除

    //1.保留尾节点
    //2.头节点的前指针,指向尾节点的前一个
    //3.尾节点的前一个的后指针,指向空(新的尾节点指向空)
    //4.释放尾节点
    Tlist_c *end = ls->head->prev;
    ls->head->prev = end->prev;
    end->prev->next = NULL;
    ls->free(end);
    free(end);

}

static void list_pop_front(Tlist_ac *ls)
{
    if(ls->head == NULL || ls->size == 0) return ;
    ls->size -= 1; //计数移除

    //最后一个节点
    Tlist_c *begin = NULL;
    if(ls->size == 0)
    {
        begin = ls->head->next;
        ls->head->next = NULL;
    }
    else
    {
        //1.保留第一个带数据节点
        //2.头节点的后指针,指向第一个带数据的后指针(等于第二个带数据节点)
        //3.第二个带数据的前指针,指向头节点
        //4.释放第一个带数据节点
        begin = ls->head->next;
        ls->head->next = begin->next;
        begin->next->prev = ls->head;
    }
    ls->free(begin);
    free(begin);
}

static int list_erase(Tlist_ac *ls,size_t pos)
{
    if(ls->head == NULL || ls->size == 0 || pos >= ls->size) return 0;
    ls->size -= 1; //计数移除

    //获取指定的当前节点
    size_t count = 0;
    Tlist_c *it = ls->head->next;
    for(;it != NULL;it = it->next)
    {
        if(count == pos) break;
        count++;
    }

    //删除末尾节点和最后一个元素时,需要特殊处理,避免操作空指针
    Tlist_c *now = NULL;
    if(pos == ls->size || ls->size == 0)
    {
        //1.保留当前节点
        //2.前一个节点的后指针,指向空(新尾节点)
        //3.头节点前指针,指向新尾节点
        //4.释放当前指针
        now = it;
        it->prev->next = NULL;
        ls->head->prev = it->prev;
    }
    else
    {
        //1.保留当前节点
        //2.前一个节点的后指针,指向后节点
        //3.后节点的前指针,指向前节点
        //4.释放当前指针
        now = it;
        it->prev->next = it->next;
        it->next->prev = it->prev;

    }
    ls->free(now);
    free(now);
    return 1;
}

static void list_clear(Tlist_ac *ls)
{
    if(ls->head == NULL) return;
    while(1)
    {
        //1.保存第一个节点,获取下一个,然后依次释放
        Tlist_c *begin = ls->head->next;
        if(begin == NULL) break;
        ls->head->next = ls->head->next->next;
        ls->free(begin);
        free(begin);
    }
    ls->size = 0; //清空计数
}


//启动链表
static Tlist_ac* Tlist_open(void (*alloc)(Tlist_c *head,const Tvalue value),void (*free)(Tlist_c *head))
{
    //分配自身内存和链表的头节点链表
    Tlist_ac *ls = (Tlist_ac *)malloc(sizeof(Tlist_ac));
    ls->head = (Tlist_c*)malloc(sizeof(Tlist_c));

    //注册操作链表的回调函数
    //  alloc和free回调需要用使用者自定义
    //  自定义复杂结构内存的分配和释放
    ls->alloc       = alloc;
    ls->free        = free;
    ls->init        = list_init;
    ls->push_back   = list_push_back;
    ls->push_front  = list_push_front;
    ls->insert      = list_insert;
    ls->pop_back    = list_pop_back;
    ls->pop_front   = list_pop_front;
    ls->erase       = list_erase;
    ls->clear       = list_clear;
    ls->clear       = list_clear;

    //初始化链表
    ls->size = 0;
    ls->init(ls->head);
    return ls;
}

//关闭链表
static void Tlist_close(Tlist_ac *ls)
{
    ls->clear(ls);  //清空带数据节点
    free(ls->head); //清空头节点
    free(ls);       //清空操作结构体
}

//克隆链表
static Tlist_ac* Tlist_clone(Tlist_ac *ls)
{
    if(ls == NULL) return NULL;
    Tlist_ac *ls_new = Tlist_open(ls->alloc,ls->free);

    for(Tlist_c *it = ls->head->next;it!=NULL;it=it->next)
    {
        ls_new->push_back(ls_new,it->value);
    }
    return ls_new;
}


//== 默认分配器 ==
//字符串
static void list_malloc_Tcharp(Tlist_c *head,const char* value)
{
    head->value = (char*)malloc(strlen(value) +1);
    strncpy(head->value,value,strlen(value));
    head->value[strlen(value)] = '\0';
}
static void list_free_Tcharp(Tlist_c *head)
{ free(head->value); }

基本类型
//static void list_malloc_Tbase(Tlist_c *head,Tvalue value)
//{ head->value = value; }
//static void list_free_Tbase(Tlist_c *head)
//{ }
//== 默认分配器 ==

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值