项目简介
基于c语言实现的仿node库,主要实现js的事件循环机制(单线程异步)和几大主要模块(event、socket、fs等)。这只是一个练手的项目,不能保证代码的绝对可靠性,如果发现bug,欢迎提issue,项目地址:https://gitee.com/lyxfj/async。
数据结构
- JavaScript常用的数据类型,先来看下和C语言数据类型的差异和拟定的替代方案:
js | c语言 | 替代方案 |
---|---|---|
number | int、double | 直接使用 |
string | char * | 使用宏 |
boolean | enum | 使用枚举类型定义 |
object | struct | 定义结构体,或者新建模块HashMap |
array | [] | 新建模块Array |
function | 函数 | 函数指针 |
- 基本结构的实现
-
Number类型
JavaScript中number类型包括了整型和浮点型两种,C语言中可以直接使用int和double。*注:
float
类型精度不够,所以只采用了double -
Boolean类型
枚举类型解决:enum Boolean { True = 1, False = 0 };
-
字符串类型
宏定义如下:#define string char * #define newString(string) strcpy((char *)malloc(strlen(string) + 1), string)
-
object类型
JavaScript中object类型有很多种情况,null
和undefined
直接使用全局宏NULL
即可,多数情况写可以用关键字struct
定义一个结构体解决,但是当添加属性和删除属性时就会很不方便,所以先实现一个HashMap结构,首先定义键值对结构体Entry
,为了解决哈希冲突添加了一个指针,将冲突值以链表的形式挂在后面:typedef struct entry { void * key; // 键 void * value; // 值 struct entry * next; // 冲突链表 }*Entry; #define newEntry() NEW(struct entry) #define newEntryList(length) (Entry)malloc(length * sizeof(struct entry))
接着定义HashMap结构体,实现思路很简单,建立一个
Entry
数组作为存储空间,然后根据传入的key
计算出一个哈希地址,当做数组的索引存入,读取的时候通过计算出的索引可以在数组中直接取出值,时间复杂度为O(1)
。size
是当前存储键值对的数量,而listSize
是当前数组的大小,数组的每一项其实都是链表的头节点,这就有可能导致size
大于listSize
,当size
大于listSize
的时候一定发生了冲突,所以在调用存储方法hashMap->put
的时候会判断size
是否超过了listSize
,如果超过了会扩充空间,减少冲突,加快索引速度。// 哈希结构 typedef struct hashMap *HashMap; #define newHashMap() NEW(struct hashMap) // 哈希函数类型 typedef int(*HashCode)(HashMap, void * key); // 判等函数类型 typedef Boolean(*Equal)(void * key1, void * key2); // 添加键函数类型 typedef void(*Put)(HashMap hashMap, void * key, void * value); // 获取键对应值的函数类型 typedef void * (*Get)(HashMap hashMap, void * key); // 删除键的函数类型 typedef Boolean(*Remove)(HashMap hashMap, void * key); // 清空Map的函数类型 typedef void(*Clear)(HashMap hashMap); // 判断键值是否存在的函数类型 typedef Boolean(*Exists)(HashMap hashMap, void * key); typedef struct hashMap { int size; // 当前大小 int listSize; // 有效空间大小 HashCode hashCode; // 哈希函数 Equal equal; // 判等函数 Entry list; // 存储区域 Put put; // 添加键的函数 Get get; // 获取键对应值的函数 Remove remove; // 删除键 Clear clear; // 清空Map Exists exists; // 判断键是否存在 }*HashMap; // 默认哈希函数 static int defaultHashCode(HashMap hashMap, void * key); // 默认判断键值是否相等 static Boolean defaultEqual(void * key1, void * key2); // 默认添加键值对 static void defaultPut(HashMap hashMap, void * key, void * value); // 默认获取键对应值 static void * defaultGet(HashMap hashMap, void * key); // 默认删除键 static Boolean defaultRemove(HashMap hashMap, void * key); // 默认判断键是否存在 static Boolean defaultExists(HashMap hashMap, void * key); // 默认清空Map static void defaultClear(HashMap hashMap); // 创建一个哈希结构 HashMap createHashMap(HashCode hashCode, Equal equal);
这里的一些方法定义成了static,为的是在文件外不可访问,只能通过实例化的HashMap的属性去调用他们,这样用户可以随时更换其中的模块而不影响整体功能。
还要给HashMap实现一个iterator接口,这是后续实现对象属性遍历的基础:
// 创建一个哈希结构 HashMap createHashMap(HashCode hashCode, Equal equal); // 创建哈希结构迭代器 Iterator createIterator(HashMap hashMap); // 迭代器是否有下一个 Boolean hasNextIterator(Iterator iterator); // 迭代到下一次 Iterator nextIterator(Iterator iterator); // 释放迭代器内存 void freeIterator(Iterator iterator);
完整的实现如下:
#include"hashMap.h" int defaultHashCode(HashMap hashMap, void * key) { char * k = (char *)key; unsigned long h = 0; while (*k) { h = (h << 4) + *k++; unsigned long g = h & 0xF0000000L; if (g) { h ^= g >> 24; } h &= ~g; } return h % hashMap->listSize; } Boolean defaultEqual(void * key1, void * key2) { return strcmp((char *)key1, (char *)key2) ? False : True; } void defaultPut(HashMap hashMap, void * key, void * value) { int index = hashMap->hashCode(hashMap, key); if (hashMap->list[index].key == NULL) { hashMap->size++; // 该地址为空时直接存储 hashMap->list[index].key = key; hashMap->list[index].value = value; } else { Entry current = &hashMap->list[index]; while (current!= NULL) { if (hashMap->equal(key, current->key)) { // 对于键值已经存在的直接覆盖 hashMap->list[index].value = value; return; } current = current->next; }; // 发生冲突则创建节点挂到相应位置的next上 Entry entry = newEntry(); entry->key = key; entry->value = value; entry->next = hashMap->list[index].next; hashMap->list[index].next = entry; hashMap->size++; } if (hashMap->size > hashMap->listSize) { Entry tempList = newEntryList(hashMap->size); Iterator iterator = createIterator(hashMap); int length = hashMap