基于C语言的单线程异步操作库

项目简介

基于c语言实现的仿node库,主要实现js的事件循环机制(单线程异步)和几大主要模块(event、socket、fs等)。这只是一个练手的项目,不能保证代码的绝对可靠性,如果发现bug,欢迎提issue,项目地址:https://gitee.com/lyxfj/async

数据结构

  1. JavaScript常用的数据类型,先来看下和C语言数据类型的差异和拟定的替代方案:
js c语言 替代方案
number int 直接使用
string char * 字符串数组
boolean enum 使用枚举类型定义
object struct 定义结构体
array [] 通过动态分配内存解决
function 函数 函数指针
  1. 基本结构的实现
  • Number类型
    JavaScript中number类型包括了整型和浮点型两种,而C语言中整型(int)和浮点型(double)是分开的,使用联合类型定义如下:

    typedef union {
        int Int;
        double Double;
    }Number;
    

    *注: float类型精度不够,所以只采用了double

  • Boolean类型

    enum Boolean { True = 1, False = 0 };
    
  • 字符串类型
    实际上就是char *指针类型的别名:

    typedef string char *;
    
  • object类型
    JavaScript中object类型有很多种情况,nullundefined直接使用全局宏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->size;
            for (int index = 0; hasNextIterator(iterator); index++) {
                // 迭代取出所有键值对
                iterator = nextIterator(iterator);
                tempList[index].key = iterator->entry->key;
                tempList[index].value = iterator->entry->value;
                tempList[index].next = NULL;
            }
            freeIterator(iterator);
    
            // 清除原有键值对数据
            hashMap->size = 0;
            for (int i = 0; i < hashMap->listSize; i++) {
                Entry current = &hashMap->list[i];
                current->key = NULL;
                current->value = NULL;
                if (current->next != NULL) {
                    while (current->next != NULL) {
                        Entry temp = current->next->next;
                        free(current->next);
                        current->next = temp;
                    }
                }
            }
    
            // 内存扩充至原来的两倍
            // *注: 扩充时考虑的是当前存储元素数量与存储空间的大小关系,而不是存储空间是否已经存满,
            // 例如: 存储空间为10,存入了10个键值对,但是全部冲突了,所以存储空间空着9个,其余的全部挂在一个上面,
            // 这样检索的时候和遍历查询没有什么区别了,可以简单这样理解,当我存入第11个键值对的时候一定会发生冲突,
            // 这是由哈希函数本身的特性(取模)决定的,冲突就会导致检索变慢,所以这时候扩充存储空间,对原有键值对进行
            // 再次散列,会把冲突的数据再次分散开,加快索引定位速度。
            hashMap->listSize *= 2;
            Entry relist = (Entry)realloc(hashMap->list, hashMap->listSize * sizeof(struct entry));
            if (relist != NULL) {
                hashMap->list = relist;
                relist = NULL;
            }
    
            // 初始化数据
            for (int i = 0; i < hashMap->listSize; i++) {
                hashMap->list[i].key = NULL;
                hashMap->list[i].value = NULL;
                hashMap->list[i].next = NULL;
            }
    
            // 将所有键值对重新写入内存
            for (int i = 0; i < length; i++) {
                hashMap->put(hashMap, tempList[i].key, tempList[i].value);
            }
            free(tempList);
            // 将新键值对写入
            hashMap->put(hashMap, key, value);
        }
    }
    
    void * defaultGet(HashMap hashMap, void * key)
    {
        int index = hashMap->hashCode(hashMap, key);
        Entry entry = &hashMap->list[index];
        while (entry->key != NULL && !hashMap->equal(entry->key, key)) {
            entry = entry->next;
        }
        return entry->value;
    }
    
    Boolean defaultRemove(HashMap hashMap, void * key)
    {
        int index = hashMap->hashCode(hashMap, key);
        Entry entry = &hashMap->list[index];
        if (entry->key == NULL) {
            return False;
        }
        if (hashMap->equal(entry->key, key)) {
            hashMap->size--;
            if (entry->next != NULL) {
                entry->key = entry->next->key;
                entry->value = entry->next->value;
                entry->next = entry->next->next;
                free(entry->next);
            }
            else {
                entry->key = entry->value = NULL;
            }
            return True;
        }
        else {
            Entry p = entry;
            entry = entry->next;
            while (entry != NULL) {
                if (hashMap->equal(entry->key, key)) {
                    hashMap->size--;
                    p->next = entry->next;
                    free(entry);
                    return True;
                }
                p = entry;
                entry = entry->next;
            };
            return False;
        }
    
        if (hashMap->exists(hashMap, key)) {
        }
        else {
            return False;
        }
    }
    
    Boolean defaultExists(HashMap hashMap, void * key)
    {
        int index = hashMap->hashCode(hashMap, key);
        Entry entry = &hashMap->list[index];
        if (entry->key == NULL) {
            return False;
        }
        if (hashMap->equal(entry->key, key)) {
            return True;
        }
        if (entry->next != NULL) {
            do {
                if (hashMap->equal(entry->key, key)) {
                    return True;
                }
                entry = entry->next;
    
            } while (entry != NULL);
            return False;
        }
        else {
            return False;
        }
    }
    
    void defaultClear(HashMap hashMap)
    {
        for (int i = 0; i < hashMap->listSize; i++) {
            // 释放冲突值内存
            Entry entry = hashMap->list[i].next;
            while (entry != NULL) {
                Entry next = entry->next;
                free(entry);
                entry = next;
            }
            hashMap->list[i].next = NULL;
        }
        // 释放存储空间
        free(hashMap->list);
        hashMap->list = NULL;
        hashMap->size = -1;
        hashMap->listSize = 0;
    }
    
    HashMap createHashMap(HashCode hashCode, Equal equal)
    {
        HashMap hashMap = newHashMap();
        hashMap->size = 0;
        hashMap->listSize = 10;
        hashMap->hashCode = hashCode == NULL ? defaultHashCode : hashCode;
        hashMap->equal = equal == NULL ? defaultEqual : equal;
        hashMap->exists = defaultExists;
        hashMap->get = defaultGet;
        hashMap->put = defaultPut;
        hashMap->remove = defaultRemove;
        hashMap->clear = defaultClear;
        
        // 起始分配10个内存空间,溢出时会自动扩充
        hashMap->list = newEntryList(hashMap->listSize);
        Entry p = hashMap->list;
        for (int i = 0; i < hashMap->listSize; i++) {
            p[i].key = p[i].value = p[i].next = NULL;
        }
        return hashMap;
    }
    
    Iterator createIterator(HashMap hashMap)
    {
        Iterator iterator = newIterator();
        iterator->hashMap = hashMap;
        iterator->count = 0;
        iterator->hashCode = -1;
        iterator->entry = NULL;
        return iterator;
    }
    
    Boolean hasNextIterator(Iterator iterator)
    {
        return iterator->count < iterator->hashMap->size ? True : False;
    }
    
    Iterator nextIterator(Iterator iterator)
    {
        if (hasNextIterator(iterator)) {
            if (iterator->entry != NULL && iterator->entry->next != NULL) {
                iterator->count++;
                iterator->entry = iterator->entry->next;
                return iterator;
            }
            while (++iterator->hashCode < iterator->hashMap->listSize) {
                Entry entry = &iterator->hashMap->list[iterator->hashCode];
                if (entry->key != NULL) {
                    iterator->count++;
                    iterator->entry = entry;
                    break;
                }
            }
        }
        return iterator;
    }
    
    void freeIterator(Iterator iterator)
    {
        free(iterator);
    }
    
  • Array结构类型
    未完待续…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章