使用C语言模拟Node(一) —— 数据结构

本文介绍了使用C语言模拟Node.js的项目,重点关注数据结构的实现,如Number、Boolean、String、Object(HashMap)和Array(双向链表)。项目旨在实现JavaScript的事件循环机制及主要模块,并提供了一个简单的HashMap迭代器接口。
摘要由CSDN通过智能技术生成

文章目录

项目简介

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

数据结构

  1. JavaScript常用的数据类型,先来看下和C语言数据类型的差异和拟定的替代方案:
js c语言 替代方案
number int、double 直接使用
string char * 使用宏
boolean enum 使用枚举类型定义
object struct 定义结构体,或者新建模块HashMap
array [] 新建模块Array
function 函数 函数指针
  1. 基本结构的实现
  • 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类型有很多种情况,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
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值