項目簡介
基於c語言實現的仿node庫,主要實現js的事件循環機制(單線程異步)和幾大主要模塊(event、socket、fs等)。這只是一個練手的項目,不能保證代碼的絕對可靠性,如果發現bug,歡迎提issue,項目地址:https://gitee.com/lyxfj/async。
數據結構
- JavaScript常用的數據類型,先來看下和C語言數據類型的差異和擬定的替代方案:
js | c語言 | 替代方案 |
---|---|---|
number | int | 直接使用 |
string | char * | 字符串數組 |
boolean | enum | 使用枚舉類型定義 |
object | struct | 定義結構體 |
array | [] | 通過動態分配內存解決 |
function | 函數 | 函數指針 |
- 基本結構的實現
-
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類型有很多種情況,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->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結構類型
未完待續…