「游戏引擎Mojoc」(8)C实现泛型ArrayList
来源:互联网 发布:编程培训机构 编辑:程序博客网 时间:2024/06/01 08:16
泛型ArrayList是基础的数据结构,然而在C的标准库里并没有提供,所以需要自己手动实现一个。Mojoc的ArrayList实现经过了实践的测试,达到了稳定和高效的状态,源码ArrayList.h。
本文主要介绍实现思路和一些特性,Mojoc的泛型ArrayList主要完成了以下几个功能:
- 存取放任意数据类型。
- 动态内存扩展。
- 针对栈数据与堆数据不同的存储策略。
- 一组简洁的数据操作接口。
- 利用宏进行了接口简化和特殊调用。
- 一些高效优化的数据操作策略。
ArrayList的数据
typedef struct{ /** * 手动设置内存扩展策略 */ int increase; /** * 数组元素类型大小 */ int elementTypeSize; /** * 元素个数 */ int size; /** * 元素数据内存,使用Array结构存储 */ Array(elementType) elementArray[1];}ArrayList;typedef struct{ /** * 内存指针 */ void* data; /** * 元素个数 */ int length;}Array;
ArrayList 使用 Array结构来存放数据的内存。所以,Array的Length其实是Capacity,而ArrayList的Size是元素的个数。
实现泛型的策略是保存元素类型的大小elementTypeSize,这样在遍历的时候,就可以根据不同类型,进行数据的检索。
elementArray负责存储数据。
使用了realloc来进行内存的扩充,所以elementArray的data指针是会变化的。increase是扩展内存的大小,这里并没有用一般百分比扩容的策略。
ArrayList的构建
// 堆上创建ArrayList* (*Create)(int elementTypeSize);// 栈初始化void (*Init)(int elementTypeSize, ArrayList* outArrayList);// 堆上创建,带有元素个数ArrayList* (*CreateWithSize)(int elementTypeSize, int size);// 栈上初始化,带有元素个数void (*InitWithSize)(int elementTypeSize, int size, ArrayList* outArrayList);// 堆上创建,带有容量ArrayList* (*CreateWithCapacity)(int elementTypeSize, int capacity);// 栈上初始化,带有容量void (*InitWithCapacity)(int elementTypeSize, int capacity, ArrayList* outArrayList);
这里提供了3种策略,2种形式的构建。其中,堆上创建就是malloc内存数据,栈上初始化在于ArrayList是栈对象,比如
ArrayList list[1];
这样的构造形式。或是初始化在其它struct类型中的嵌入ArrayList。Init前缀的函数提过了初始化的功能。elementTypeSize就是泛型中的类型,比如
sizeof(int), sizeof(struct)
等等。
ArrayList的泛型形式
#define ArrayList(elementType) ArrayList
这个简单的宏定义,在实践中却有不可思议的效果,对于明确泛型使用提供了直觉上的便利性和可读性。elementType是一个形式,被替换为不存在,这样就模拟了泛型语法中<>的可读性。
// 栈上 int 类型ArrayList(int) list[1]; Init(sizeof(int), list);// 堆上 int 类型ArrayList(int)* list = Create(sizeof(int));struct Obj{ ArrayList(float) list[1]; ArrayList(float)* otherList;};
ArrayList的数据操作
// 添加元素空间,并返回元素地址void* (*GetAdd)(ArrayList* arrayList);// 插入元素空间,并返回元素地址void* (*GetInsert)(ArrayList* arrayList, int index);// 拷贝元素,并返回元素地址void* (*Add)(ArrayList* arrayList, void* elementPtr);//插入元素,并返回地址void* (*Insert)(ArrayList* arrayList, int index, void* elementPtr);...
一旦确定了elementTypeSize,所有的操作都会基于elementTypeSize。从而实现了不同类型,一套数据类型的操作。当然,也会提供一套宏,来简化API的调用。
#define AArrayList_GetAdd(arrayList, elementType) \ (*(elementType*) AArrayList->GetAdd(arrayList))#define AArrayList_GetInsert(arrayList, index, elementType) \ (*(elementType*) AArrayList->GetInsert(arrayList, index))#define AArrayList_Add(arrayList, element) \ AArrayList->Add(arrayList, &(element))#define AArrayList_Insert(arrayList, index, element) \ AArrayList->Insert(arrayList, index, &(element))...
ArrayList的一些特别的操作
// 弹出一个元素,实现高效的模拟了Stackvoid* (*Pop)(ArrayList* arrayList, void* defaultElementPtr);// 高效的删除一个范围的元素void (*RemoveRange)(ArrayList* arrayList, int fromIndex, int toIndex);// 删除一个元素,并用最后一个元素填充。避免了元素移动,但会打乱元素次序void (*RemoveByLast)(ArrayList* arrayList, int index);// 利用realloc的特点,释放动态增长的多余空间 void (*Shrink)(ArrayList* arrayList);// 初始化常量ArrayList#define AArrayList_Init(elementType, increase) \ { \ increase, \ sizeof(elementType), \ 0, \ { \ NULL, \ 0, \ }, \ }/** * 构建一个固定容量的ArrayList */#define AArayList_InitFix(elementType, capacity, size, ...) \ { \ 0, \ sizeof(elementType), \ size, \ AArray_Init(elementType, capacity, __VA_ARGS__), \ }
还有很多就不一一列举了,很多API的设定,都是在实践中需求的,为了效率,为了优化,为了提高性能特别增加的。
ArrayList的实现
源码的实现,ArrayList.c,可以看到原理很简单,实现清晰明确,这是工程实践的结果。如果曾经手动实现过泛型ArrayList,在来看这份代码实现,就能感受到简洁的力量,没有多余的直接完成目的。
如果用这个代码去写些功能,用的过程中就会发现,所有想要的功能尽在其中,而边界检查效率稳定性都面面俱到。
ArrayList的删除操作
关于删除操作,需要多说一些。删除,需要移动元素。但有一个小技巧,就是倒序遍历删除。
for (int i = arrayList.size - 1; i > -1; i--){ // 删完继续往前走,其它不用操心。 Remove(arrayList[i]);}
但这里还有一个更高效的函数,如果不在意元素顺序的话。
for (int i = arrayList.size - 1; i > -1; i--){ // 这里会删掉元素,使用最后一个元素填充,无需移动其它元素 RemoveByLast(arrayList, i);}
最后
Mojoc的泛型ArrayList的实现,只使用了C语言的标准库,可以拿出来独立使用。更多的使用示例请看scottcgi/Mojoc的源代码,全局搜索ArrayList。
「ArrayList(T)」
- 「游戏引擎Mojoc」(8)C实现泛型ArrayList
- 「游戏引擎Mojoc」(2)C代码风格
- 「游戏引擎Mojoc」(3)C面向对象编程
- 「游戏引擎Mojoc」(7)C使用goto label地址实现协程
- 「游戏引擎Mojoc」(1)简介
- 「游戏引擎Mojoc」(6)NDK替换android_native_app_glue的实现
- 「游戏引擎Mojoc」(5)快速指南
- 「游戏引擎Mojoc」(4)面向组件-状态机-消息驱动3合1编程模型
- C 实现泛型ArrayList数组
- 游戏服务器引擎实现
- 纯c实现ArrayList
- c语言 ---- ArrayList实现
- Win32实现简单游戏引擎
- 游戏引擎剖析 8
- 游戏引擎架构:8
- 8款开源游戏引擎
- 3D游戏引擎设计与实现(8)
- 非典型2D游戏引擎 Orx 源码阅读笔记(6) C语言实现的面向对象
- codeforces896A Nephren gives a riddle (dfs)
- bzoj1319&1420 Sgu261 Discrete Roots (原根+BSGS)
- 北大ACM
- Qt中纯C++项目发布为dll的方法
- fan xing
- 「游戏引擎Mojoc」(8)C实现泛型ArrayList
- 多线程编程学习::POSIX 多线程基础(三)
- 设计模式-单例模式(Singleton Pattern)
- NIO学习一、NIO简介
- 排序之插入排序
- soci开发环境搭建
- 标日初上
- 01学习Linux第一天
- Qt项目文件详解