OpenHarmony轻量系统服务管理-samgr:common赏析及实现

往期知识点记录:

一、前言

distributedschedule_samgr_lite\interfaces\kits\samgr\common.h文件中提供了简化的vector容器和转换函数。并针对vector容器的操作函数进行设计。下面对相关代码进行分析。

二、头文件分析

vector结构体

typedef struct SimpleVector {
    int16 max;  //可存储的最大数据记录数。
    int16 top;  //存储的数据记录数量的峰值。
    int16 free; //已释放的数据记录数。
    void **data;//数据段指针
    VECTOR_Key key;//函数指针,将数据元素转换为用于比较的键,默认值为NULL
     //1 表示key1大于key2
     //0 表示key1等于key2
     //-1 表示key1小于key2
     //默认值为NULL
    VECTOR_Compare compare;//函数指针,指向相应的键值比较函数
} Vector;

宏定义

//对于T类型的对象,获取它的member成员相较于起始地址的偏移量
#define GET_OFFSIZE(T, member) (long)((char *)&(((T *)(0))->member))
/*
    1.首先获取member对于T的起始地址的偏移量
    2.获取ptr-偏移量的地址值,然后转化为T类型
*/
    @Ptr:成员变量的地址
    @T:目标类型
    @member:将@Ptr的名称指定为T成员变量
#define GET_OBJECT(Ptr, T, member) (T *)(((char *)(Ptr)) - GET_OFFSIZE(T, member))

这里的宏定义非常重要,在后续的代码中频繁的出现,有的小伙伴可能对于文字注释不太理解,所以我以下面一张图来进一步的说明。

首先拟定一个T类型的结构体,包含三个成员a,b和member。一般情况下,它的存储方式如图上半部分,a的地址即结构体的起始地址,并且与0地址间有不定长的距离。而GET_OFFSIZE的作用就是获取member成员相较于结构体起始地址a的偏移量,这里用的巧妙的地方就是直接将0地址转换为T类型,然后member的地址值就是要求的偏移量,如图的下半部分,这样可以避免做减法操作。

GET_OBJECT的作用就显而易见了,即根据member在结构体中的偏移量来获取这个结构体的首地址。实际使用中ptr所指向的对象就是member类型的,所以通过ptr-偏移量就可以得到结构体的首地址。这样我们就可以推断出结构体的全貌。

三、函数实现分析

针对common.h中的函数声明,对它们相应的实现进行分析。实现在模块2-distributedschedule_samgr_lite\samgr\source\common.c文件中。

/*
    函数功能:创建vector对象
    函数参数:@key:函数指针,指向将数据元素转换为键值的函数
            @compare:函数指针,指向比较两个元素的函数
    函数返回:返回一个vector对象
    详细描述:初始化vector的成员,并给函数指针赋值
*/
Vector VECTOR_Make(VECTOR_Key key, VECTOR_Compare compare)
{
    //初始化vector成员,并给函数指针赋值
    Vector vector = {0, 0, 0, NULL, key, compare};
    return vector;
}
/*
    函数功能:清空vector的内容
    函数参数:@vector:vector对象
    详细描述:释放vector的data指向的内存,并将vector对象的各个成员置为初始值。
*/
void VECTOR_Clear(Vector *vector)
{
    //参数检查
    if (vector == NULL) {
        return;
    }
    if (vector->data == NULL) {
        return;
    }
    //释放data指向的内存空间
    SAMGR_Free(vector->data);
    //标记值全部归0
    vector->max = 0;
    vector->top = 0;
    vector->free = 0;
    vector->data = NULL;
}

vector添加元素操作

/*
    函数功能:在vector对象中添加新的元素
    函数参数:@vector: vector对象
            @element: 待添加的元素
    函数返回:成功返回新加入的元素的下标,失败返回INVALID_INDEX
    详细描述:
            1.将元素添加到vector中,首先做参数检查。
            2.判断vector中data是否有空闲空间,如果没有空闲空间,先遍历data中为NULL的元素,
             若找到便将element加入后返回,没找到就申请新的空间。
            3.最后将element加入data中,返回下标。
*/
int16 VECTOR_Add(Vector *vector, void *element)
{
    //参数检查
    if (vector == NULL || element == NULL) {
        return INVALID_INDEX;
    }
    //无空闲空间
    if (vector->top >= vector->max) {
        int16 i;
        //优先使用已释放的数据元素,从后往前遍历
        for (i = vector->top - (int16)1; i >= 0; --i) {
            if (vector->data[i] == NULL) {
                //若找到一个指向==NULL的位置,则将元素插入
                vector->data[i] = element;//data[i]指向element对应的内存空间
                //更新已释放数,减一。代表重用了一块被释放的区域
                vector->free--;
                //返回插入的下标
                return i;
            }
        }
        //不存在可重用的位置,需申请新的空间
        //max占用两个字节,判断增长是否会导致溢出
        if (vector->max + GROW_STEP < 0) {
            //容量达到上限,返回INVALID_INDEX
            return INVALID_INDEX;
        }
        //重新申请新的空间,大小为当前容量max+增长步长GROW_STEP
        void **data = (void **)SAMGR_Malloc(sizeof(void *) * (vector->max + GROW_STEP));
        if (data == NULL) {
            //内存分配失败
            return INVALID_INDEX;
        }
        //若data指向一块内存,则需要拷贝
        if (vector->data != NULL) {
            //将源data中的数据拷贝到新的data中
            (void)memcpy_s(data, sizeof(void *) * (vector->max + GROW_STEP),
                           vector->data, sizeof(void *) * vector->max);
            //释放旧的data
            SAMGR_Free(vector->data);
        }
        vector->data = data;//更新数据段
        vector->max += GROW_STEP;//更新最大容量
    }
    //有空闲空间,将element加入
    vector->data[vector->top] = element;
    return vector->top++;//先返回当前元素的下标,再自增
}

根据下标获取元素

/*
    函数功能:获取vector中指定下标的元素
    函数参数:@vector: vector对象
            @index: 指定下标
    函数返回:成功即返回指定位置的元素,失败则返回NULL
*/
void *VECTOR_At(Vector *vector, int16 index)
{
    //参数检查
    if (vector == NULL || vector->top <= index || index < 0) {
        return NULL;
    }
    //返回指定位置的元素
    return vector->data[index];
}

vector中的元素交换操作,当与NULL交换时可用于删除元素

/*
    函数功能:交换指定下标的元素
    函数参数:@vector: vector对象
            @index: 指定索引
            @element: 指定元素
    函数返回:成功 返回被替换的元素,失败 返回NULL
    详细描述:
            1.函数调用传入三个参数,待操作的vector对象、元素索引下标、当前元素
            2.首先进行参数检查,若检查失败就返回NULL
            3.判断当前元素是否为NULL,若为NULL 则free+1. 
            4.当element指向NULL时,即当前替换操作变为删除指定元素的操作
            5.在替换前先保存旧的元素指针,再替换,并返回旧元素指针。
*/
void *VECTOR_Swap(Vector *vector, int16 index, void *element)
{
    //参数检查
    if (vector == NULL || vector->top <= index || index < 0) {
        return NULL;
    }
    //若当前元素为NULL则free数+1
    if (element == NULL) {
        vector->free++;
    }
    //保存当前索引中对应的旧元素
    void *oldElement = vector->data[index];
    vector->data[index] = element;//交换
    return oldElement;
}

其余函数后续再进一步分析。

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值