`
febird
  • 浏览: 256416 次
  • 性别: 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 ...

    logback所需jar包

    &lt;pattern&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&lt;/pattern&gt; &lt;/encoder&gt; &lt;/appender&gt; &lt;root level="info"&gt; &lt;appender-ref ref="STDOUT" /&gt; &lt;/root&gt; &lt;/configuration&gt; ``` 在这个配置中,...

    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...

    ibatis dynamic 用法

    - **`&lt;dynamic&gt;` 标签内的 `&lt;if&gt;`**:虽然示例中未直接出现 `&lt;if&gt;` 标签,但它同样可以嵌入到 `&lt;dynamic&gt;` 标签内,用于更复杂的条件判断。 #### 七、总结 通过本文的介绍,我们了解了 ibatis 中 Dynamic SQL 的...

    vivi命令详解vivi命令详解

    - **`go&lt;addr&gt;&lt;a0&gt;&lt;a1&gt;&lt;a2&gt;&lt;a3&gt;`**:跳转到指定地址执行代码,并可以传递最多四个参数。 - **`dump&lt;addr&gt;&lt;length&gt;`**:显示(十六进制形式)一段内存区域。 - **`call&lt;addr&gt;&lt;a0&gt;&lt;a1&gt;&lt;a2&gt;&lt;a3&gt;`**:带有返回的跳转至...

    iBATIS-SqlMaps-2_cn.doc

    6. `&lt;datasource&gt;`元素则用于配置数据源,这是连接到数据库的关键部分,可以配置连接池参数,以优化数据库连接的使用。 7. `&lt;sqlMap&gt;`元素包含了具体的SQL语句映射,每个`&lt;sqlMap&gt;`可以有多个`&lt;statement&gt;`元素,...

    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...

    springDataJapDemo

    &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; ...

    前端大厂最新面试题-leetcode-interview-ts.docx

    asyncMethod&lt;T, U&gt;(input: Promise&lt;T&gt;): Promise&lt;Action&lt;U&gt;&gt; syncMethod&lt;T, U&gt;(action: Action&lt;T&gt;): Action&lt;U&gt; ``` 同时,该类还具有两个非函数属性:`count` 和 `message`。问题的要求是编写一个名为 `connect` 的...

    LOG4J2 mdc配置

    LOG4J2的生产环境配置配置案例: 4.日志滚动,避免单个日志过大,可以按小时进行日志分割. ...&lt;Pattern&gt;%d %p %c{1.} [%t] %m%n&lt;/Pattern&gt; &lt;/PatternLayout&gt; &lt;TimeBasedTriggeringPolicy /&gt; &lt;/RollingFile&gt;

    logback.zip

    &lt;pattern&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&lt;/pattern&gt; &lt;/encoder&gt; &lt;/appender&gt; ``` **过滤器** 过滤器允许根据日志级别、MDC(Mapped Diagnostic Context)、日志消息内容等条件过滤...

Global site tag (gtag.js) - Google Analytics