免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1546 | 回复: 0
打印 上一主题 下一主题

[算法] Tokyo Cabinet中变量压缩存取的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-01-14 15:02 |只看该作者 |倒序浏览
在TC中,很多地方为了节约存储空间,在保存变量时不会直接存放变量类型长度的值(比如4字节或8字节的值)到文件中,它会探测变量用来表示值的有效字节数,然后把这些有意义的字节保存起来,在后面读取该变量时,TC会把该变量的所有有效字节都读出来,从而计算出该变量所表示的值。
为了实现这个功能,TC的做法是:把变量的每个字节当成一个有符号数,最高位仅做为符号位使用,前面7位才用来表示真正的值,这样一来,文件中的4个字节的数仅有28位用来保存长度信息,如果我们要保存0xFFFFFFFF这个值,就需要在文件中占用5个字节,然而,这种情况的值毕竟是少数(4字节整型数只有超过2^28时才会在文件中占用5字节,其它情况都会少于或等于4字节),我们一般存放的值都很小,就只需要少于4个字节的存储长度,比如存放小于2^7的所有值只需要1个字节空间,存放2^7到2^14之间的值仅需要2字节等等,通过这中方式节省的空间会远远少于我们浪费的空间,因此这种做法在节省文件空间方面还是很有效的。
上面大概讲了原理,下面我们来看看TC中的代码,看看TC具体怎么实现的,我会在下面的代码中给出注释说明。TC主要通过2个宏来分别完成存放和读取变长变量,这2个宏又分别对应32位版本(最多存取4字节的值)和64位的版本(最多存放8字节的值),我仅分析32位的情况,64位情况类似。
1、  把一个变量按变长方式放到buffer中
/* set a buffer for a variable length number */
#define TCSETVNUMBUF(TC_len, TC_buf, TC_num) / // TC_num为正整数
  do { /
    int _TC_num = (TC_num); /
    if(_TC_num == 0){ /  // 存放的变量为0
      ((signed char *)(TC_buf))[0] = 0; /
      (TC_len) = 1; /  // 返回存放了1个字节长度
    } else { /
      (TC_len) = 0; /
      while(_TC_num > 0){ /  // 变量大于0,就一直循环存放
        int _TC_rem = _TC_num & 0x7f; / // 取变量低7位存放
        _TC_num >>= 7; / // 变量右移7位
        if(_TC_num > 0){ / // 去掉低7位后变量是否还有值?
// 按负数存放取得的变量低7位值,减一确保为负数,因为中间可能有0
          ((signed char *)(TC_buf))[(TC_len)] = -_TC_rem - 1; /         
} else { /  // 保留最后7位,按正数的形式
          ((signed char *)(TC_buf))[(TC_len)] = _TC_rem; /
        } /
        (TC_len)++; / // 存放的长度加1,表示用了多少字节来存放变量
      } /
    } /
  } while(false)
2、  从buffer中读出按变长方式存放的变量值
/* read a variable length buffer */
#define TCREADVNUMBUF(TC_buf, TC_num, TC_step) /
  do { /
    TC_num = 0; /
    int _TC_base = 1; /
    int _TC_i = 0; / // 从buffer第一个成员开始读取
    while(true){ /
      if(((signed char *)(TC_buf))[_TC_i] >= 0){ / // 该字节大于0,则是最后字节
        TC_num += ((signed char *)(TC_buf))[_TC_i] * _TC_base; / // 累加
        break; / // 退出结束
      } /
        // 该字节小于0,则不是最后字节
      TC_num += _TC_base * (((signed char *)(TC_buf))[_TC_i] + 1) * -1; / //累加
      _TC_base <<= 7; /
      _TC_i++; / // 移动buffer
    } /
    (TC_step) = _TC_i + 1; / // 读取长度加1,表示读了多少字节的变量

  } while(false)



以上为原文,有一点不明白,为什么不把变量的每个字节当成无符号来存取,这样不是更减少空间吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP