预分配内存fifo实现可变长度字节序列存储

github链接https://github.com/gexin1023/utils/tree/master/fifo

fifo即先进先出队列,可以用链表来实现,在链表头部插入数据,尾部读数据,每次插入新的数据都动态分配一段内存用于数据存储,适用于变长数据的队列实现。也可以用数组实现,用一个数组buf[LEN]作为缓存,用两个整数分别记录写数据和读数据的位置,适用于每次读取相同长度数据的场景。

有的场景中,要避免频繁的malloc/free动态分配释放,与此同时数据长度不定。因此,需要预分配一段空间存储数据,也需要记录每一个数据的长度,方便存取。

fifo数据结构

  1. typedef struct
  2. {
  3. unsigned int pos; // position index in buffer
  4. unsigned int len; // the length of data
  5. list_node_t node;
  6. }pos_t;
  7. typedef struct
  8. {
  9. unsigned char *buffer;
  10. unsigned int size;
  11. unsigned int in;
  12. unsigned int out;
  13. list_node_t pos_head;
  14. } fifo_t;

设计以上的数据结构,buffer即为fifo的存储空间,开始时根据需要预分配,size表示buffer的长度。inout分别记录读写数据的位置,pos_t结构组成的链表用于记录每次写入数据的位置及长度。

fifo接口

  1. fifo_t * fifo_init(unsigned char *buf, unsigned int size);
  2. fifo_t *fifo_alloc(unsigned int size);
  3. void fifo_free(fifo_t *fifo);
  4. /* fifo_put, 向fifo加入数据
  5. * @fifo, 目标fifo
  6. * @buf, 数据
  7. * @len, 数据长度
  8. * 如果空间不够,就删除最旧的数据,新数据覆盖旧数据
  9. */
  10. unsigned int fifo_put(fifo_t *fifo, unsigned char *buf, unsigned int len);
  11. /* fifo_put_tail
  12. * 有时会存在优先级比较高的数据需要放在最先出队的位置
  13. * /
  14. unsigned int fifo_put_tail(fifo_t *fifo, unsigned char *buf, unsigned int len);
  15. /* fifo_get
  16. * 取数据
  17. */
  18. int fifo_get(fifo_t *fifo, unsigned char *buf, unsigned int *p_len);
  19. /* fifo_get_len
  20. * 获取数据长度
  21. */
  22. int fifo_get_len(fifo_t *fifo);

fifo接口的实现如下:


  1. /* fifo_init: create a fifo using a preallocated memory
  2. *
  3. * buf: preallocated memory
  4. * size: the length of the preallocated memory, 取以2为底的整数
  5. */
  6. fifo_t * fifo_init(unsigned char *buf, unsigned int size)
  7. {
  8. fifo_t *fifo = (fifo_t *)malloc(sizeof(fifo_t));
  9. fifo->buffer = buf;
  10. fifo->size = size;
  11. fifo->in = fifo->out = 0;
  12. fifo->pos_head.next = &(fifo->pos_head);
  13. fifo->pos_head.prev = &(fifo->pos_head);
  14. return fifo;
  15. }
  16. /* fifo_alloc: create a fifo
  17. *
  18. * size: the length of the allocated memory
  19. */
  20. fifo_t *fifo_alloc(unsigned int size)
  21. {
  22. unsigned char * buf = (unsigned char *)malloc(size);
  23. return fifo_init(buf, size);
  24. }
  25. /* fifo_free:
  26. *
  27. */
  28. void fifo_free(fifo_t *fifo)
  29. {
  30. free(fifo->buffer);
  31. free(fifo);
  32. }
  33. /* fifo_put, 向fifo加入数据
  34. * @fifo, 目标fifo
  35. * @buf, 数据
  36. * @len, 数据长度
  37. * 如果空间不够,就删除最旧的数据,新数据覆盖旧数据 */
  38. static unsigned int __fifo_put(fifo_t *fifo, unsigned char *buf, unsigned int len)
  39. {
  40. unsigned int l;
  41. /* fifo 空间不足时,删除旧内容,直到可以容纳新的数据 */
  42. while(len>(fifo->size - fifo->in + fifo->out))
  43. {
  44. pos_t *pos = list_entry(fifo->pos_head.prev, pos_t, node);
  45. fifo->out += pos->len;
  46. list_del(fifo->pos_head.prev);
  47. free(pos);
  48. }
  49. /* 首先复制数据从( in % buf_size)位置到buffer结尾 */
  50. l = min(len , fifo->size - (fifo->in & (fifo->size-1)));
  51. memcpy(fifo->buffer + (fifo->in & (fifo->size-1)), buf ,l);
  52. /* 然后复制剩下的数据从buffer开头开始 */
  53. memcpy(fifo->buffer, buf+l, len-l);
  54. /* 加入新的位置节点 */
  55. pos_t *pos = (pos_t *)malloc(sizeof(pos_t));
  56. pos->len=len;
  57. pos->pos=fifo->in;
  58. list_add(&(fifo->pos_head), &(pos->node));
  59. /* 更改写入点索引 */
  60. fifo->in += len;
  61. return len;
  62. }
  63. unsigned int fifo_put(fifo_t *fifo, unsigned char *buf, unsigned int len)
  64. {
  65. return __fifo_put(fifo, buf, len);
  66. }
  67. unsigned int fifo_put_tail(fifo_t *fifo, unsigned char *buf, unsigned int len)
  68. {
  69. unsigned int l;
  70. /* fifo 空间不足时,删除旧内容,直到可以容纳新的数据 */
  71. while(len>(fifo->size - fifo->in + fifo->out))
  72. {
  73. pos_t *pos = list_entry(fifo->pos_head.prev, pos_t, node);
  74. fifo->out += pos->len;
  75. list_del(fifo->pos_head.prev);
  76. free(pos);
  77. }
  78. fifo->out -= len;
  79. /* 首先复制数据从( out % buf_size)位置到buffer结尾 */
  80. l = min(len , fifo->size - (fifo->out & (fifo->size-1)));
  81. memcpy(fifo->buffer + (fifo->out & (fifo->size-1)), buf ,l);
  82. /* 然后复制剩下的数据从buffer开头开始 */
  83. memcpy(fifo->buffer, buf+l, len-l);
  84. /* 加入新的位置节点 */
  85. pos_t *pos = (pos_t *)malloc(sizeof(pos_t));
  86. pos->len=len;
  87. pos->pos=fifo->out;
  88. list_add_tail(&(fifo->pos_head), &(pos->node));
  89. return len;
  90. }
  91. int fifo_get(fifo_t * fifo, unsigned char * buf, unsigned int * p_len)
  92. {
  93. if(fifo->pos_head.next == &(fifo->pos_head))
  94. {
  95. // fifo is emperty
  96. return -1;
  97. }
  98. pos_t *pos = list_entry(fifo->pos_head.prev, pos_t, node);
  99. *p_len = pos->len;
  100. list_del(&(pos->node));
  101. free(pos);
  102. int l = min(*p_len, fifo->size - (fifo->out &(fifo->size-1)));
  103. memcpy(buf, fifo->buffer+(fifo->out & (fifo->size-1)), l);
  104. memcpy(buf+l, fifo->buffer, *p_len-l);
  105. fifo->out += *p_len;
  106. return *p_len;
  107. }
  108. int fifo_get_len(fifo_t * fifo)
  109. {
  110. if(fifo->pos_head.next == &(fifo->pos_head))
  111. {
  112. // fifo is emperty
  113. return -1;
  114. }
  115. pos_t *pos = list_entry(fifo->pos_head.prev, pos_t, node);
  116. return (int)pos->len;
  117. }

预分配内存fifo实现可变长度字节序列存储的更多相关文章

  1. python高级(四)—— 文本和字节序列(编码问题)

    本文主要内容 字符 字节 结构体和内存视图 字符和字节之间的转换——编解码器 BOM鬼符  标准化Unicode字符串 Unicode文本排序 python高级——目录 文中代码均放在github上: ...

  2. Fluent_Python_Part2数据结构,04-text-byte,文本和字节序列

    文本和字节序列 人使用文本,计算机使用字节序列 1. 大纲: 字符.码位和字节表述 bytes.bytearray和memoryview等二进制序列的独特特性 全部Unicode和陈旧字符集的编解码器 ...

  3. Python文本和字节序列

    ASCII码 早期人们用8位二进制来编码英文字母(最前面的一位是0) 也就是说,将英文字母和一些常用的字符和这128种二进制0.1串一一对应起来, 比如:大写字母“A”所对应的二进制位“0100000 ...

  4. 《流畅的Python》第二部分 数据结构 【序列构成的数组】【字典和集合】【文本和字节序列】

    第二部分 数据结构 第2章 序列构成的数组 内置序列类型 序列类型 序列 特点 容器序列 list.tuple.collections.deque - 能存放不同类型的数据:- 存放的是任意类型的对象 ...

  5. Python的文本和字节序列

    一.字符串的表示和存储 字符串是字符的序列,每个字符都有有一个数字作为标识,同时会有一个将标识转换为存储字节的编码方案: s = 'hello world python' for c in s: pr ...

  6. vecor预分配内存溢出2

    vector预分配内存溢出导致原始的 迭代器 失效 consider what happens when you add the one additional object that causes t ...

  7. Python 文本和字节序列

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } Python 3 明确区分了人类可读的文本字符串和原始的字节序列.隐式 ...

  8. matlab运行出现“变量似乎会随着迭代次数改变而变化,请预分配内存,以提高运行速度”问题

    这句话大致意思就是: b = 0;for i = 1:3    a(i) = b;end是说变量的长度是变化的,经常在循环里出现,比如上面这个例子,这样会影响计算速度,最好的办法是预先定义a的长度,比 ...

  9. 流畅的python第四章文本和字节序列学习记录

    字符问题 把码位转化成字节序列的过程是编码,把字节序列转化成码位的过程是解码 把unicode字符串当成人类可读的文本,码位当成机器可读的, 将字节序列编程人类可读是解码,把字符串编码成字节序列是编码 ...

随机推荐

  1. 选择排序_c++

    选择排序_c++ GitHub 文解 选择排序的核心思想是对于 N 个元素进行排序时,对其进行 K = (N - 1) 次排序,每次排序从后(N + 1 - K)个数值中选择最小的元素与以 (K - ...

  2. TCP/IP协议族之链路层(二)

    TCP/IP学习记录,如有错误请指正,谢谢!!! TCP/IP协议族之链路层(二) 链路层是最底层协议,主要有三个目的: 1. 为IP模块发送和接收IP数据报 2. 为ARP模块发送ARP请求和接收A ...

  3. centos7 php7 动态编译mysqlnd: configure: error: Cannot find OpenSSL's <evp.h> 错误解决

    开始以为是没有安装openssl, openssl-devel,安装后发现还是提示这个错误,搜索了一下evp.h,这个文件也存在.GOOGLE 了一下,在stackoverflow,找到了答案,原来是 ...

  4. 安装mysql8.13用Navicat Premium链接本地数据库报2059

    推荐使用已下命令: ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密规则 ALTE ...

  5. openstack之kvm常用操作

    KVM虚拟机的管理主要是通过virsh命令对虚拟机进行管理. 1.   查看KVM虚拟机配置文件及运行状态 KVM虚拟机默认配置文件位置: /etc/libvirt/qemu/ autostart目录 ...

  6. PHPExcel 导入Excel数据 (导出下一篇我们继续讲解)

    一:使用composer下载 phpoffice/phpexcel 或者直接下载安装包 composer require phpoffice/phpexcel 二 1:导入数据 原理:读取文件,获取文 ...

  7. go基础语法-循环语句

    1.基础定义 for语句的条件不需要括号(同if语句) ,golang里的循环只有for,没有while sum := 0 for i=0;i<100;i++ { sum += i } 2.条件 ...

  8. 【转】Odoo开发之:工作流 workflow

    在OpenERP中,工作流是管理一组“所做的事情”(与一些数据模型的记录关联)的人为现象.工作流提供了高级别的方式来组织记录要上做的事情. 具体地说,工作流是一个定向的路径,这里节点称为活动并且弧线称 ...

  9. 封装List集合一个批量导入数据库的工具类

    public class CommonDal { #region 数据导入相关 /// <summary> /// 批量导入数据 /// </summary> /// < ...

  10. Android远程推送笔记

    Android远程推送笔记 Android推送有很多种实现方案,但都没办法和苹果的APNS比拟,这里主要来讲述一下我遇到的问题,和作出的抉择. 首先,为了快速接入,所以就没有自己搭建推送服务器,而是使 ...