`
febird
  • 浏览: 246978 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

内嵌变长数据结构范例——trbstrmap<mapped>

    博客分类:
  • C++
阅读更多



  

以前的这篇文章介绍了嵌入的变长数据结构(embeded

 

本文介绍一个使用这种思想实现的通用strmap容器,相当于:

std::map<std::string, Mapped>

 

实现上使用了我以前写的线索红黑树——相比标准map的实现,节省了一半的结点存储开销,而平均查找时间只付出很小的额外开销,并且没有代码膨胀问题。

 

使用

大多数情况下

trbstrmap<MappedType[, Compare]> // Compare是可选的,allocator 总在类范围,可以修改:

trbstrmap<MappedType[, Compare]>::s_vtab.alloc = ....;

 

为了节省空间,trbstrmap使用一个字节存储strkey_length,因此,strlen(strkey)不可超过255,允许长度为0key。最大长度255基本上可以应对绝大多数情况。

key作为变长字段,有一个原因很重要:key一旦插入,就不可改变!因此,整个结点的memblock也就不需要重新分配,可以修改的只有mapped_data

作为一个比较:如果把key作为一个固定长度的结构,而mapped_data作为变长内嵌数据,当需要修改mapped_data时,就需要重新分配该结点,还需要修改该结点的父节点指向该结点的指针,并且,会破坏“node容器的iterator只有在删除该node以后才失效”的语义!

一旦用在多线程环境中,问题就会变得很复杂,因为修改了父节点。就不能仅lock需要修改数据的那个结点,而是需要lock整个tree,使用数据库的术语,就是一下子从记录锁变成了表锁,本来按key查找时,因为key没改变,就不需要加锁,而这样搞,查找时就需要对整个表加锁,严重影响并发性!

注意事项:

1.         trbstrmap::iterator::value_type trbstrmap::value_type都是 mapped_type/Value*iter也是mapped_type;而不是std::mappair<Key,Value>

2.         trbstrmap::key(iter)获得iter对应的key

3.         trbstrmap::klen(iter)获得key_length,当然,strlen(trbstrmap::key(iter))也可以获得key_length,但需要一些时间开销;另外,当key_content中存在\0时,klen就是不可缺少的了(后面将详细介绍这种情况)

4.         再次强调,key_cstr_length最大长度不可超过255,但这个长度不包括末尾的 \0

 

示例代码:

         typedef febird::trbstrmap<int, &trb_compare_tev_inline_cstr_nocase> smap_t;

         smap_t smap, smap2;

 

         smap["1"] = 0;

         smap["2"] = 1;

         smap["3"] = 1;

         smap["4"] = 2;

         smap["1"]++;

         smap["4"] += 2;

         smap.insert("5", 5);

         assert(!smap.insert("5", 6).second);

         // str长度不可超过255

         smap["aabbccddeeffgghhiijjkk====================================="] = 10;

 

         for (typename SMT::iterator i = smap.begin(); i != smap.end(); ++i)

         {

                   printf("smap[%s]=%d, klen=%d\n", smap_t::key(i), *i, smap_t::klen(i));

         }

 

 

在简单的情况下,使用trbstrmap,std::map可以节省50%~70%的内存。使用的方便程度,基本上没差别。

 

数据结构

Mapped Data 是模板参数,可以是任意struct/class,当然也可以内嵌指针,也可以是复杂对象,没有任何限制。

 

 

复杂情形:任意字符串,字符串中可以包含\0

trbstrmap允许加入内容中存在\0的字符串,这种应用比较罕见,但是仍然允许,只是必须遵循以下注意事项:

1.         在这种情况下,需要传入key_content_length参数:
trbstrmap.probe(key,key_content_length)
trbstrmap.insert(key,key_content_length, val)
key_content_length
是整个key_content长度,包括末尾的\0——如果有的话

2.         或者,传入std::string
trbstrmap[std::string(…)] = val;
equal to: trbstrmap.probe(s.c_str(), s.size()+1) = val;

3.         trbstrmap.insert(key, klen, val)

4.         这种情况下,应用一般需要传入一个自定义的Compare

5.         trbstrmap::klen(iter)在任何情况下,返回的都是key_content_length – 1
不管末尾有没有\0

6.         自定义函数需要获取key_content_length时,应该如下:

int

trb_compare_custom ( const struct trb_vtab* TRB_restrict vtab,

                                          const struct trb_tree* TRB_restrict tree,

                                          const void* TRB_restrict x,

                                          const void* TRB_restrict y)

{

     size_t lx = ((unsigned char*)x)[-1] + 1;

     size_t ly = ((unsigned char*)y)[-1] + 1;

int ret = memcmp(x, y, lx<ly?lx:ly); // 仅示例,不一定非用memcmp

     return 0 == ret ? lx – ly : ret;

}

7.         当给trbstrmap::find/lower_bound/equal_range多传入一个key_content_length时,这些函数会将keykey_content_length打包(这些都在库内部完成),应用须知这会有稍微多一些的开销。

必须这么做,因为compare函数需要找到key_content_length,除此之外,别无他法。

8.         貌似很复杂,但始终坚持剃刀原理:在绝大多数情况下,也就是字符串是cstr,末尾包含\0时,函数的行为符合传统惯例并且高效;在罕见情况下也可用,只是效率有一点下降,使用难度也大一些。

9.         当情况复杂时,记住:只要你明确传入了长度,这个长度就是你真实数据的长度

 

测试代码:
  • 大小: 17.7 KB
0
0
分享到:
评论

相关推荐

    The Art of Assembly Language Programming

    The 80x86 MOV Instruction&lt;br&gt;4.8 - Some Final Comments on the MOV Instructions&lt;br&gt;&lt;br&gt;4.9 Laboratory Exercises&lt;br&gt;4.9.1 The UCR Standard Library for 80x86 Assembly Language Programmers&lt;br&gt;4.9.2 ...

    Visual C++ 编程资源大全(英文源码 其它)

    1,01.zip&lt;br&gt;Output&lt;br&gt;显示所有的调试信息(5KB)&lt;END&gt;&lt;br&gt;2,02.zip&lt;br&gt;Some general debugging tips&lt;br&gt;一般的调试技巧(11KB)&lt;END&gt;&lt;br&gt;3,03.zip&lt;br&gt;Debugging ISAPI extension&lt;br&gt;调试ISAPI扩展(4KB)&lt;END&gt;&lt;br&gt;4,04....

    Visual.Studio.Tools.for.Office.Using.C.Sharp.with.Excel.Word.Outlook.and.InfoPath.Sep.2005

    &lt;br&gt; Copyright &lt;br&gt; Praise for Visual Studio Tools for Office &lt;br&gt; Microsoft .NET Development Series &lt;br&gt; Titles in the Series &lt;br&gt; About the Authors &lt;br&gt; Foreword &lt;br&gt; Preface &lt;br&gt; Acknowledgments ...

    Visual.Studio.Tools.for.Office.Using.C.Sharp.with.Excel.Word.Outlook.and.InfoPath.Sep.2005.part2

    &lt;br&gt; Copyright &lt;br&gt; Praise for Visual Studio Tools for Office &lt;br&gt; Microsoft .NET Development Series &lt;br&gt; Titles in the Series &lt;br&gt; About the Authors &lt;br&gt; Foreword &lt;br&gt; Preface &lt;br&gt; Acknowledgments ...

    Visual C++ 编程资源大全(英文源码 DLL)

    1,01.zip&lt;br&gt;Dialogs in DLL&lt;br&gt;在DLL中实现对话框(5KB)&lt;END&gt;&lt;br&gt;2,02.zip&lt;br&gt;Export dialogs in MFC Extension DLLs&lt;br&gt;在MFC扩充DLL中输出对话框(12KB)&lt;END&gt;&lt;br&gt;3,03.zip&lt;br&gt;Remapping resource script ID's&lt;br&gt;...

    Visual C++ 编程资源大全(英文源码 文件)

    1,01.zip&lt;br&gt;Safe file name comparison&lt;br&gt;处理长文件名的比较(5KB)&lt;END&gt;&lt;br&gt;2,02.zip&lt;br&gt;Mapped File Class&lt;br&gt;映像文件类(11KB)&lt;END&gt;&lt;br&gt;3,03.zip&lt;br&gt;Filename Handling Class &lt;br&gt;有关文件名的类(5KB)&lt;END&gt;&lt;br&gt;4...

    Applied ADO.NET: Building Data-Driven Solutions(1)

    Applied ADO.NET: Building Data-Driven Solutions 第一部分&lt;br&gt;Table of Contents &lt;br&gt; Applied ADO.NET—Building Data-Driven Solutions &lt;br&gt; Introduction &lt;br&gt; Chapter 1 - ADO.NET Basics &lt;br&gt; Chapter 2 - ...

    compass学习笔记

    compassHits可以得到scores,resources和mapped objects.&lt;br&gt;&lt;br&gt;Compass也提供了CompassTemplate和CompassCallback类处理会话和事务的处理。CompassTemplate template = new CompassTemplate(compass);&lt;br&gt;&lt;br&gt;

    Designing Software Product Lines with UML: From Use Cases to Pattern-Based Software Architectures(1)

    specific model.&lt;br&gt;&lt;br&gt;Key topics include:&lt;br&gt;&lt;br&gt;Software product line engineering process, which extends the Unified Development Software Process to address software product lines&lt;br&gt;&lt;br&gt;Use case ...

    Designing Software Product Lines with UML: From Use Cases to Pattern-Based Software Architectures(2)

    specific model.&lt;br&gt;&lt;br&gt;Key topics include:&lt;br&gt;&lt;br&gt;Software product line engineering process, which extends the Unified Development Software Process to address software product lines&lt;br&gt;&lt;br&gt;Use case ...

    Process Explorer

    &lt;br&gt;&lt;br&gt;You can obtain equivalent command-line tools, Handle and ListDLLs, at the Sysinternals Web site.&lt;br&gt;&lt;br&gt;Process Explorer does not require administrative privileges to run and works on Windows...

    Delphi7.1 Update

    Cannot access field &lt;fieldname&gt; as type variant.&quot; * TClientDataSet doesn‘t save data to file when FileName is set and there is no existing file on disk (Quality Central 2307). * Using the Delphi...

    iBatis SQL Maps开发指南.pdf

    &lt;properties&gt;元素 &lt;setting&gt;元素 &lt;typeAlias&gt;元素 &lt;transactionManager&gt;元素 &lt;datasource&gt;元素 &lt;sqlMap&gt;元素 SQL Map XML映射文件 Mapped Statements Statement的类型 SQL 语句 自动生成的主键 存储过程 ...

    csv2:适用于Modern C ++的快速CSV解析器和编写器

    目录 CSV阅读器# include &lt; csv2&gt;int main () { csv2::Reader&lt;delimiter&gt;, quote_character&lt; ' " ' &gt;, first_row_is_header&lt; true&gt;, trim_policy::trim_whitespace&gt; csv; if (csv. mmap ( " foo.csv " )) { const...

    supervisord:一个 supervisord Docker 镜像,记录到标准输出,从子镜像导入配置,并且可以通过 supervisorctl 进行检查

    在容器上公开端口 9001,以便您可以通过supervisorctl -s http://&lt;container&gt;:&lt;mapped&gt;在主机上监控应用程序的正常运行时间。 延长吗? 下面是如何通过一个简单的例子扩展它——一个 Go 网络服务器容器: # some...

    j2se项目源码及介绍_last指令

    函数说明 读取所有登录日志,并按登入与登出分类放入数据结构 参数说明 MappedByteBuffer buffer 日志文件的内存缓冲 Vector&lt;LogRecord&gt; logins 日志的登入数据 Vector&lt;LogRecord&gt; logouts 日志的登出数据 返回说明...

    gbasm:基于JavaScript的Gameboy汇编器

    JavaScript Gameboy汇编器gbasm是用于Gameboy... --optimize, -O: Enable instruction optimizations --mapfile, -m &lt;s&gt;: Generates a ASCII overview of the mapped ROM space --symfile, -s &lt;s&gt;: Generates a symbol

    MimicMap:基于std的排序关联容器

    模拟地图 基于模仿std :: map的std :: vector的排序关联容器。 用法 与std :: map几乎相同,但是所有容器元素都存储在单个std :: vector中。... std::vector&lt;value&gt;::const_iterator reverse_iterator std::vector

    react-spinner:基于Material-UI加载微调器

    基于Material-UI加载微调器 安装 npm i -S @flatlinediver/... &lt; div&gt; Mapped data &lt; / div &gt; : &lt; Spinner&gt; } ) 使用悬念的例子 import React from 'react' ; import Spinner from '@flatlinediver/react-spinner'

    eclipse错误解决.rar

    有时struts资源文件添加中文保存时会eclipse出现Some characters cannot be mapped using 'ISO-8859-1' character encoding错误不能保存&lt;br&gt;解决办法

Global site tag (gtag.js) - Google Analytics