基於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結構類型
    未完待續…

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