SDS 模块

适用范围

SDS 模块构建了一个字符串对象抽象, 这个抽象字符串具有以下特性:

  1. 内容可以是二进制安全的
  2. 可以在 O(1) 复杂度内取出字符串的长度
  3. 通过预分配内存来减少连续的追加(append)操作所需的内存重分配次数

如果你的程序需要以上这些特性, 那么可以考虑重用 Redis 的这个 SDS 模块。

SDS 模块的具体定义,以及操作 API ,可以参考 《Redis 设计与实现》 中的相关章节。

准备步骤

  1. 从 Redis 源代码中复制 sds.hsds.czmalloc.hzmalloc.c 四个文件到新建文件夹。
  2. 添加 #include <stddef.h>zamlloc.h ,解决 size_t 未定义的问题。
  3. zamlloc.c 中移除 #include "config.h" ,因为现在已经不需要配置文件了。

测试驱动程序

以下驱动程序展示了如何使用 SDS 模块, 并测试了其中的 sdsnewsdslensdsavailsdsdupsdscat 等函数。

// main.c

#include <assert.h>
#include <string.h>
#include "sds.h"

void create_sds_and_check_its_property(void)
{
    sds s = sdsnew("hello");

    // 验证长度
    assert(
        sdslen(s) == 5
    );

    // 验证空白位置
    assert(
        sdsavail(s) == 0
    );

    // 验证已有内容
    assert(
        memcmp(s, "hello\0", 6) == 0
    );

    // 释放
    sdsfree(s);
}


void test_sdsdup(void)
{
    sds s = sdsnew("hello");

    // 创建 s 的一个副本
    sds another = sdsdup(s);

    // 长度对比
    assert(
        sdslen(s) == sdslen(another)
    );

    // 空间对比
    assert(
        sdsavail(s) == sdsavail(another)
    );

    // 内容对比
    assert(
        memcmp(s, another, 6) == 0
    );

    // 释放
    sdsfree(s);
    sdsfree(another);
}


void test_sdscat(void)
{
    const char const total[] = "hello moto\0";

    sds s = sdsnew("hello");

    // 追加内容
    const char const append[] = " moto";
    sdscat(s, append);

    // 长度对比
    assert(
        sdslen(s) == strlen(total)
    );

    // 空间对比
    assert(
        // 追加之后的字符串
        // 会预留大小相当于现有字符串长度的空间
        sdsavail(s) == sdslen(s)
    );

    // 内容对比
    assert(
        memcmp(s, total, strlen(total)+1) == 0
    );

    // 释放空间
    sdsfree(s);
}


int main(void)
{
    create_sds_and_check_its_property();

    test_sdsdup();

    test_sdscat();
}

完整源码

重用程序的完整代码可以在 这里sds 文件夹中找到。

留言

comments powered by Disqus

Table Of Contents

Previous topic

重用 Redis 模块

Next topic

双端链表