├── README.md ├── appendix └── 01 │ └── Memory.md ├── chapter ├── 01 │ └── Memory.md └── 02 │ ├── String_I.md │ ├── Vector_I.md │ └── Vector_II.md ├── code ├── 01 │ ├── memory.h │ ├── type.h │ └── unittest.cpp ├── 02 │ ├── memory.h │ ├── type.h │ ├── unittest2.cpp │ └── vector.h ├── 02a │ └── vector.h ├── 02b │ ├── string.h │ └── vector.h └── 03 │ ├── regex.h │ ├── string.h │ └── vector.h ├── codewars └── 7x7-skyscrapers │ └── csharp_solution.cs ├── cover └── cover.pptx ├── learncpp ├── 24736903 ├── 24854976 ├── 24928430 ├── 24953467 ├── 25027543 ├── 25184604 ├── 25189183 ├── 25257863 ├── 25284597 ├── 25401920 ├── 25443704 ├── 25476629 ├── 25489673 ├── 25490952 ├── 25593280 ├── 25593938 ├── 25717640 ├── 25819125 ├── 25867829 ├── 25879478 ├── 25888881 ├── 26010547 ├── 26054925 ├── 26135675 ├── 26142441 ├── 26193530 ├── 26202018 ├── 26331043 ├── 26356924 ├── 26492108 ├── 26553299 ├── 26591115 ├── 26804202 ├── 26880947 ├── 26912674 ├── 27108016 ├── 27299453 ├── 27307738 ├── 27350169 ├── 27433288 ├── 27915133 ├── 27979309 ├── 28540783 ├── 29008180 ├── 29243574 ├── 29589948 ├── 29632312 ├── 30713476 ├── 30864679 ├── 31012319 ├── 31015884 ├── 31017634 ├── 32150887 ├── 32251040 ├── 32486185 ├── 32692408 ├── 33517169 ├── 33752364 ├── 33791772 ├── 33924622 ├── 34896821 ├── 40821579 ├── 41886644 ├── 42413097 ├── 42669063 ├── 42773209 ├── 45520585 ├── 45897626 ├── 46723048 ├── 46993463 ├── 47309037 └── 47569910 ├── projects ├── calc │ ├── CEval.cpp │ ├── CEval.dev │ ├── CEval.h │ ├── CEval.layout │ ├── Makefile.win │ ├── README.md │ ├── RefStringBase.cpp │ ├── RefStringBase.h │ ├── RefStringIterator.cpp │ ├── RefStringIterator.h │ └── main.cpp └── router │ ├── Router.cpp │ ├── Router.h │ └── main.cpp └── script └── dns └── hack_dns.py /README.md: -------------------------------------------------------------------------------- 1 | # 从零开始构建自己的标准库 2 | 3 | ## 序 4 | 5 | > STL庞大而且复杂,很多内容从boost库吸收而来。认识这个庞然大物,非常不容易。 6 | > 7 | > 一开始,我们从远处眺望这座STL大山,感觉高不可攀。然而我们的目标是爬上这座山,心中始终有一个信念:**九层之台,起于垒土;千里之行,始于足下,**。 8 | > 9 | > 从最简单的cout,到vector,到iterator,到transform,……,我们翻过一座座山峦,不断向高峰进发,志在必得! 10 | > 11 | > 最后,站在最高处,回顾之前的点点滴滴,感慨万千。 12 | > 13 | > 用了几年,驾轻就熟,于是一番造轮子就开始了 :) 14 | > 15 | > 不断造轮子,一方面对先前的知识进行巩固、查漏补缺,另一方面锻炼自己的编程能力,更有甚者,让别人也高兴地用上了自己造的轮子。 16 | 17 | ## 目录 18 | 19 | - [第一章:内存管理](https://github.com/bajdcc/learnstl/blob/master/chapter/01/Memory.md) 20 | - [第一章番外:内存](https://github.com/bajdcc/learnstl/blob/master/appendix/01/Memory.md) 21 | - [第二章:变长数组(一)](https://github.com/bajdcc/learnstl/blob/master/chapter/02/Vector_I.md) 22 | 23 | ## 走近STL 24 | 25 | STL的内容很多,有: 26 | 27 | - containers 28 | - iterators 29 | - allocator 30 | - adapter 31 | - algorithm 32 | - functor 33 | - …… 34 | 35 | 我学习任何代码,都是在源代码基础上,从零开始慢慢添加代码,思考为什么这样写。这里有大学问——首先要添加什么代码?所以需要对源码结构进行剖析,先添加最核心的代码,然后补充细枝末节;在整个过程中,debug的时间占了90%,但这恰恰最本质地揭示了自己一步步掌握了代码书写技巧和相关概念。倘若只是死板地读源码,那就是盲人摸象,从未走入代码的心,自然学不到东西。 36 | 37 | ## 学习顺序 38 | 39 | 这个轮子是有难度的,好在有许多优秀代码可以参考。 40 | 41 | 我们从零开始,手写属于自己的STL库,手写属于自己的注释(hey,这是关键哈哈),手写属于自己的细节(我想怎么改就怎么改)。 42 | 43 | 暂时想到的书写顺序有: 44 | 45 | 1. **建立自己的type** 46 | 2. 向量vector,常用操作 47 | 3. 迭代器 48 | 4. 仿函数,各种指针的包装,智能指针 49 | 5. 字符串string,常用操作,其实这属于对vector的实际应用,暂时不处理UTF8 50 | 6. 流及包装 51 | 7. typelists(参考自C++设计新思维) 52 | 8. LINQ 53 | 9. **内存池**,GC垃圾收集 54 | 10. 其他数据结构 55 | 11. 排序算法 56 | 12. 查找算法 57 | 13. 正则表达式 58 | 14. 反射与注解 59 | 15. XML与JSON的解析 60 | 16. Win32的GUI封装(DirectUI) 61 | 17. 对多线程的封装,包括同步与互斥对象 62 | 18. 对socket的封装 63 | 19. 应用:多人游戏(是不是想太多?) 64 | 65 | 理想很丰满 :) 任务很艰巨~ 估计没个几年搞不定哈,不过人不能总在舒适区。路漫漫,朝着目标前进吧~ -------------------------------------------------------------------------------- /appendix/01/Memory.md: -------------------------------------------------------------------------------- 1 | # 第一章番外:内存 2 | 3 | ## 参考 4 | 5 | 这篇参考文章写得很详细:http://blog.codinglabs.org/articles/a-malloc-tutorial.html 6 | 7 | ## 前言 8 | 9 | 本节主要讲述内存的故事。 10 | 11 | 学习C++的过程中,一般书上介绍各种对象各种用法各种注意点各种坑。然而,书上这些代码,究竟能够起到什么作用,这种程序是怎样管理内存的呢?看完书还是一知半解。 12 | 13 | 以几个例子为例:“烫烫烫”和“屯屯屯”是神马一回事?为什么总是出现Access violation?什么是野指针?堆上还是栈上傻傻分不清?内存会不会不够用啊?什么时候要释放这些空间?this指针到底是什么?为毛会有Stack overflow/Segment fault?变量、结构体、对象是内存中的东西吗?内存里面究竟是哪些妖魔鬼怪?………… 14 | 15 | 围绕着内存的问题有很多很多,上面的问题不可能去一一解答。 16 | 17 | ## 内存的故事 18 | 19 | ### 奇怪的仓库 20 | 21 | 整个计算机系统中的各部分协调工作,才是确保电脑不会动不动就蓝屏的关键。同样的,C++乃至整个编程语言世界都是建立在计算机系统的基础上,我们看到的,也只是冰山一角。 22 | 23 | 因此,平常人看内存:“那不就是个放一堆奇奇怪怪东西的空间么”。那么这些“奇怪的东西”是什么呢? 24 | 25 | 首先,要了解这些“奇怪的东西”,就必须明白计算机的运作方式?一般是“冯*·*诺依曼”架构的,如果你对它还不熟悉,那么下面的内容理解起来需要费多一些时间。 26 | 27 | 计算机的运作方式简单起见(表述不太严谨),就是: 28 | 29 | 1. **CPU从内存获取指令** 30 | 2. **CPU执行这个指令,根据这个指令做相应的事情(如读文件、打印输出等)** 31 | 3. **CPU找到下一条指令的位置** 32 | 4. **回到第一步骤** 33 | 34 | 一些问题:CPU读的第一条指令是什么?CPU读错了怎么办?下一条指令在哪里?CPU做什么事情都行吗,能不能和太阳肩并肩(手动滑稽)?这牵扯到操作系统的内容了,这里不展开。 35 | 36 | 现在,从计算机的运作方式中我们可以看出: 37 | 38 | - 内存中应该存放着**指令** 39 | - 内存中应该也存放着**数据** 40 | - 内存中可能还有其他我们不知道的东西(咖喱棒吗) 41 | 42 | 那指令和数据在内存中是怎样存放的呢?会不会是随机打乱着放的呢?当然不会,操作系统其实是个强迫症、整理控,它对指令和数据的存放要求非常严格: 43 | 44 | - 指令就该放在专门的存放指令的地方! 45 | - 数据也应该放在专门的放数据的地方! 46 | 47 | 那么这个要求呢,在操作系统层次上叫作“段”/Segment。 48 | 49 | ### 大叔的日常 50 | 51 | 我们的**大叔(操作系统)**其实是一个疯狂的整理控,它对内存的打理是非常苛刻的。为什么这么苛刻呢?原因在于内存其实空间是有限的,如果那些**小弟(程序)**去外面带了一堆的**杀马特(申请内存)**回来,那么大叔家就会被挤爆,到时候整个系统就挂了。 52 | 53 | 所以大叔会时刻关注家里的情况,计算着目前家里有多少小弟,有多少杀马特,有多少吃的喝的。一旦发现不够用了,大叔立马开启一级警报:谁谁谁,把你的杀马特带出去!你你你,不准再把杀马特带进屋里来!我的天哪,你们把家里搞成啥样了,快把奶嘴都放抽屉里!此时大叔变成了凶残的大妈。 54 | 55 | 上面的例子只是为了形象说明,求轻拍。 56 | 57 | ### 黑客的伎俩 58 | 59 | 刚刚说到内存中有指令有数据,两者分别存放在特定的区域。 60 | 61 | 那么指令跟数据的关系其实很微妙: 62 | 63 | - 如果我恶意修改了数据,那么指令的执行就会受影响 64 | - 如果我恶意修改了指令,那么指令和数据我都可以改掉了 65 | 66 | 所以典型的思路是:我改了一点数据,结果影响了指令的正常运行,指令出现了意料之外的情况。其中一种情况是,**指令会执行到数据的区域上来**。这样,我更改了数据区域,相当于更改了指令区域。更改了指令区域的后果就是:可以让系统与大太阳肩并肩,你可以胡作非为了。 67 | 68 | 那么这里,有一个小小的例子可以说明:http://www.secbox.cn/hacker/program/c/2350.html 。这个例子用VC6.0进行编译,所以程序运行没有报错,若用较新的VS2015编译运行会发现程序运行会报错(它检测到指令被修改)。这个例子就是大名鼎鼎的“**缓冲区溢出漏洞**”。 69 | 70 | 如果我直接去修改指令区域,可能会收到一个Access Violation的手动滑稽表情。 71 | 72 | ## 管理内存 73 | 74 | 前面简单介绍了内存的一系列知识,但内存不是只可远观不可亵玩的,相反地,我们需要自己去管理内存。 75 | 76 | “管理”一般就是简单的CURD(增删改查)。 77 | 78 | ### 内存的申请 79 | 80 | 申请内存是门大学问。 81 | 82 | 前面说了大叔其实是整理控,如果你胡乱地申请内存,大叔便会恼怒,让你的程序越走越慢——这可是你自找的。 83 | 84 | 偌大一片内存,如何管理?常言道不扫一屋何以扫天下,就以一小块内存作为自留地,自己耕耘吧。 85 | 86 | 假设现在手头有块地,大小是1KB。 87 | 88 | - 如果要提供1MB空间,那么不好意思,地不够,不借 89 | - 如果要提供1KB,正好,给你 90 | - 如果要1B,呵呵,免费赠送(为了取整),给你4B;如果要5B,同样,给8B 91 | - 难道工作就这么简单?拿衣服 92 | 93 | 现在情况复杂了,有借有还,再借不难。 94 | 95 | - 之前借的1KB还你了 96 | - 一半地借人了,一半地还了,现在只剩一半地 97 | - 借借还还越来越乱,最后是有半KB空间,但连100B也借不出去! 98 | 99 | 你火了:我要请个整理控来!我要请一堆整理控来! 100 | 101 | - 整理控1:我每次从开头找,只要找到符合你要求大小的,就把它给你 102 | - 整理控2:我全部找一遍,把符合你要求但是空间最小的地给你 103 | - 整理控3:等等等等,我把这些零碎的地全合并到前面去,再把后面的空地给你,但是首先… 104 | - 整理控4:给你零碎的地我想没问题吧……(被一脚踢飞) 105 | - 整理控5:我全部找一遍,把符合你要求但是空间最大的地给你 106 | - 整理控6:我全部找一遍,把符合你要求但是空间适中的地给你 107 | 108 | 最后,你非常开心,然后请了整理控1,并拒绝了后面所有人。 109 | 110 | ### 内存的归还 111 | 112 | 内存的归还还不简单,一个字,还! 113 | 114 | 但其中有玄机:两个空地被归还了,很巧的是这两块地相邻,结果当然是这两块地合并成一块空地了。但是在编程中,并没有此等好事,大叔说:“合并是神马?两个杀马特会自动合并成一个杀马特吗?当然是你来做!” 115 | 116 | 面对前面一块块零零落落的地,你感慨万千:“用什么方法来记录它们比较好呢?” 117 | 118 | 于是你买了几百本数学练习簿,打算记账。直到有一天,你惊讶地发现: 119 | 120 | 它,今天终于的确来还地了。但是,它是第一次向你申请土地的人!它的记录在前面300页!苍天!大地!我找了几宿才找到他!这可恨的! 121 | 122 | 所以,你嘀咕着:“是记载方式出问题了吗?”突然,你想到了什么。 123 | 124 | 你买了一本空白的几千页厚的书,按照土地的总量,计算出一页纸代表多少土地。谁借了,就在那部分纸上写上他的名字。但是显而易见,这种方法出了问题:别人少还了很难找出来。 125 | 126 | 后来,你想了一个办法。谁借了地,在相应的那部分纸的第一张写上他的名字。然后,将这块地相邻的上一块地和下一块地的页码也记在上面,虽然这样的话,这一页纸就没用了,不过好在可以解决问题。 127 | 128 | 最后,这种方法很久都没出问题。这种方法也是比较普遍的方法,详情请看最前面的参考部分。 129 | 130 | ## 总结 131 | 132 | 每个写程序的人都是管理内存的大师,不过这大师要打引号。什么时候,自己成为了一个整理控,有着对内存要求很苛刻的独特癖好,那么这个时候——你就成了大叔。 -------------------------------------------------------------------------------- /chapter/01/Memory.md: -------------------------------------------------------------------------------- 1 | # 第一章:内存管理 2 | 3 | ## 地位 4 | 5 | 程序=数据结构+算法,总体还是围绕内存进行各种操作。偌大的一块内存令人茫然,如同空白的棋盘一样,令人无从下手。然而,下棋有固定的套路,管理内存亦然。管理一块内存,粗看看是简单的活儿,但实际中体会一遍过后就感觉不那么简单。 6 | 7 | 接触C语言,那么对malloc和free一定不陌生,C++中的new和delete同样如此。有了这些方法,变长数组和对象的灵活创建也就成了可能。 8 | 9 | 想一想:假如没有了malloc、free,或是new和delete,哪些程序还能原模原样运行着?这个答案也就暗示着内存管理的地位如何。这部分内容和整个库的联系暗含其中,地位处于库的底层,依赖链条的起始端。因而,本部分是最先可以动手完成的内容。 10 | 11 | ## 基础 12 | 13 | ### 内存 14 | 15 | 所有的`struct`、`class`等内容都位于内存中。通过调用相关的方法可以向操作系统申请特定大小的内存。主要的内存管理操作这里就实现两种:申请和释放,另外还做了一些必要的安全检查。 16 | 17 | ### 内存池 18 | 19 | 这里其实也可以叫作对象池。内存池负责管理一块内存,完成日常的内存申请和释放操作,那么它的任务简不简单?并不简单! 20 | 21 | 申请和释放?一般人想到设个`flag`不就没事了。事实没有那么简单,因为会有一种叫作**内存碎片**的情况出现。 22 | 23 | 假设一开始全部是申请操作,所有内存都申请完了。接着要接二连三释放一半的内存。释放完后,出现一片片的空洞。可用空间还有一半,但是如何从一个个空洞中去找够用的内存块?值得深究。况且,申请的内存大小参差不齐,更加增加了难度。 24 | 25 | ### 实现 26 | 27 | 自己去实现一个内存池很有难度,好在有优秀的方法可以参考。 28 | 29 | 这里就采用**分块法**,即把内存分成一个个块,每个块有自己的属性:是否空闲、大小等。为了使块与块之间能够遍历,需要添加链表指针,这里就采用**双向链表**。内存的查找采用**初次匹配**的原则,而不是最佳匹配,后者需要花更多的时间。内存 的释放附有**合并空闲块**的任务。 30 | 31 | ## 思路 32 | 33 | 1. 建立原始类型`type` 34 | 2. 构建原始内存池`legacy_memory_pool`,无块大小限制,双向链表 35 | 3. 完善`legacy_memory_pool`,实现`allocator`接口,实现`legacy_memory_pool_allocator` 36 | 4. 命名类型`using memory_pool = legacy_memory_pool` 37 | 5. 编写单元测试,除bug 38 | 6. 思考需要改进的地方,这里没有实现`remalloc`和`calloc` 39 | 40 | ## 详解 41 | 42 | ### 一、原始类型 43 | 44 | 这里没有什么难点。需要注意32位和64位的区别。 45 | 46 | 简单起见,库的实现就先照顾32位系统。 47 | 48 | ```c++ 49 | namespace clib 50 | { 51 | namespace type 52 | { 53 | using int8 = signed __int8; 54 | using uint8 = unsigned __int8; 55 | using int16 = signed __int16; 56 | using uint16 = unsigned __int16; 57 | using int32 = signed __int32; 58 | using uint32 = unsigned __int32; 59 | using int64 = signed __int64; 60 | using uint64 = unsigned __int64; 61 | 62 | #ifdef WIN32 63 | using sint = int32; 64 | using uint = uint32; 65 | #else 66 | using sint = int64; 67 | using uint = uint64; 68 | #endif 69 | 70 | using byte = uint8; 71 | using size_t = uint; 72 | } 73 | } 74 | ``` 75 | 76 | ### 二、默认接口 77 | 78 | 这里调用了`new`和`delete`方法,没什么难点。 79 | 80 | 带`args`的方法意味着会调用构造函数。 81 | 82 | ```c++ 83 | template 84 | class default_allocator 85 | { 86 | public: 87 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize; 88 | 89 | template 90 | T* __alloc() 91 | { 92 | return new T; 93 | } 94 | 95 | template 96 | T* __alloc_array(uint size) 97 | { 98 | return new T[size]; 99 | } 100 | 101 | template 102 | T* __alloc_args(TArgs ... args) 103 | { 104 | return new T(args); 105 | } 106 | 107 | template 108 | T* __alloc_array_args(uint size, TArgs ... args) 109 | { 110 | return new T[size]; 111 | } 112 | 113 | template 114 | bool __free(T* t) 115 | { 116 | delete t; 117 | return true; 118 | } 119 | 120 | template 121 | bool __free_array(T* t) 122 | { 123 | delete[] t; 124 | return true; 125 | } 126 | }; 127 | ``` 128 | 129 | ### 三、内存块 130 | 131 | #### 块的属性 132 | 133 | 内存块包含四个数据成员: 134 | 135 | - size:该块后面跟着的数据部分的大小(以块的大小为基本单位) 136 | - flag:参数,比如要设置空闲位`BLOCK_USING` 137 | - prev:前一节点 138 | - next:后一节点 139 | 140 | ```c++ 141 | struct block 142 | { 143 | size_t size; // 数据部分的大小 144 | uint flag; // 参数 145 | block *prev; // 前指针 146 | block *next; // 后指针 147 | }; 148 | 149 | enum block_flag 150 | { 151 | BLOCK_USING = 0 152 | }; 153 | ``` 154 | 155 | #### 块的方法 156 | 157 | 方法有: 158 | 159 | - block_align:块的大小对齐,单位是块的大小(这里是16byte,那么1=16byte) 160 | 161 | - block_init:块的初始化 162 | 163 | - block_connect:块的连接,将A和B连接起来,其中A是原本有的,B是新添加上去的 164 | 165 | - block_merge:块的合并,合并后只有一个头部(块头~) 166 | 167 | - block_set_flag和block_get_flag:设置标志位 168 | 169 | ### 四、内存池 170 | 171 | #### 申请内存 172 | 173 | 构建一个循环遍历指针,不断遍历各个块,如果当前块是空闲的且空间足够,就开辟它! 174 | 175 | 将块分割后,将在当前块后面建立一个新的块。 176 | 177 | ```c++ 178 | // 申请内存 179 | void* _alloc(size_t size) 180 | { 181 | if (size == 0) 182 | return nullptr; 183 | auto old_size = size; 184 | size = block_align(size); 185 | if (size >= block_available_size) 186 | return nullptr; 187 | if (block_current == block_head) 188 | return alloc_free_block(size); 189 | auto blk = block_current; 190 | do 191 | { 192 | if (block_get_flag(blk, BLOCK_USING) == 0 && blk->size >= size) 193 | { 194 | block_current = blk; 195 | return alloc_free_block(size); 196 | } 197 | blk = blk->next; 198 | } while (blk != block_current); 199 | return nullptr; 200 | } 201 | 202 | // 查找空闲块 203 | void* alloc_free_block(size_t size) 204 | { 205 | if (block_current->size == size) // 申请的大小正好是空闲块大小 206 | { 207 | return alloc_cur_block(size + 1); 208 | } 209 | // 申请的空间小于空闲块大小,将空闲块分裂 210 | auto new_size = block_current->size - size - 1; 211 | if (new_size == 0) 212 | return alloc_cur_block(size); // 分裂后的新块空间过低,放弃分裂 213 | block *new_blk = block_current + size + 1; 214 | block_init(new_blk, new_size); 215 | block_connect(block_current, new_blk); 216 | return alloc_cur_block(size); 217 | } 218 | 219 | // 直接使用当前的空闲块 220 | void* alloc_cur_block(size_t size) 221 | { 222 | // 直接使用空闲块 223 | block_set_flag(block_current, BLOCK_USING, 1); // 设置标志为可用 224 | block_current->size = size; 225 | block_available_size -= size + 1; 226 | auto cur = static_cast(block_current + 1); 227 | block_current = block_current->next; // 指向后一个块 228 | return cur; 229 | } 230 | ``` 231 | 232 | #### 释放内存 233 | 234 | 其实这里并不是真正意义上的“释放”,只是清除了标记而已。 235 | 236 | 释放前必须检查地址合法性;释放后要进行空闲块合并的操作。 237 | 238 | ```c++ 239 | // 释放内存 240 | bool _free(void* p) 241 | { 242 | block *blk = static_cast(p); 243 | --blk; // 自减得到块的元信息头 244 | if (!verify_address(blk)) 245 | return false; 246 | if (blk->next == blk) // 只有一个块 247 | { 248 | block_set_flag(blk, BLOCK_USING, 0); 249 | return true; 250 | } 251 | if (blk->prev == blk->next && block_get_flag(blk->prev, BLOCK_USING) == 0) // 只有两个块 252 | { 253 | _init(); // 两个块都空闲,直接初始化 254 | return true; 255 | } 256 | auto is_prev_free = block_get_flag(blk->prev, BLOCK_USING) == 0 && blk->prev < blk; 257 | auto is_next_free = block_get_flag(blk->next, BLOCK_USING) == 0 && blk < blk->next; 258 | auto bit = (is_prev_free << 1) + is_next_free; 259 | switch (bit) 260 | { 261 | case 0: 262 | block_available_size += blk->size + 1; 263 | block_set_flag(blk, BLOCK_USING, 0); 264 | break; 265 | case 1: 266 | block_available_size += block_merge(blk, blk->next); 267 | break; 268 | case 2: 269 | block_available_size += block_merge(blk->prev, blk); 270 | break; 271 | case 3: 272 | block_available_size += block_merge(blk->prev, blk, blk->next); 273 | break; 274 | default: 275 | break; 276 | } 277 | return true; 278 | } 279 | 280 | // 验证地址是否合法 281 | bool verify_address(block *blk) 282 | { 283 | if (blk < block_head || blk > block_head + DEFAULT_ALLOC_MEMORY_SIZE - 1) 284 | return false; 285 | return (blk->next->prev == blk) && (blk->prev->next == blk) && (block_get_flag(blk, BLOCK_USING) == 1); 286 | } 287 | ``` 288 | 289 | ### 五、封装 290 | 291 | 到这里要大功告成了,封装一下! 292 | 293 | ```c++ 294 | // 基于原始内存池的内存分配策略 295 | template, size_t DefaultSize = Allocator::DEFAULT_ALLOC_BLOCK_SIZE> 296 | class legacy_memory_pool_allocator 297 | { 298 | legacy_memory_pool memory_pool; 299 | 300 | public: 301 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize - 2; 302 | 303 | template 304 | T* __alloc() 305 | { 306 | return memory_pool.template alloc(); 307 | } 308 | 309 | template 310 | T* __alloc_array(uint count) 311 | { 312 | return memory_pool.template alloc_array(count); 313 | } 314 | 315 | template 316 | T* __alloc_args(TArgs ... args) 317 | { 318 | return memory_pool.template alloc_args(args...); 319 | } 320 | 321 | template 322 | T* __alloc_array_args(uint count, TArgs ... args) 323 | { 324 | return memory_pool.template alloc_array_args(count, args...); 325 | } 326 | 327 | template 328 | bool __free(T* t) 329 | { 330 | return memory_pool.free(t); 331 | } 332 | 333 | template 334 | bool __free_array(T* t) 335 | { 336 | return memory_pool.free_array(t); 337 | } 338 | }; 339 | 340 | template::DEFAULT_ALLOC_BLOCK_SIZE> 341 | using memory_pool = legacy_memory_pool, DefaultSize>>; 342 | ``` 343 | 344 | 在内存池基础上构建新的内存池,颇有递归的味道。 345 | 346 | ### 六、单元测试 347 | 348 | 进入最后的环节——测试环节。 349 | 350 | 运行测试的过程真是战战兢兢,因为一开始全是未通过。不过测试的过程中也发现了代码中的疏漏。 351 | 352 | ## 源码 353 | 354 | 文章:https://github.com/bajdcc/learnstl/blob/master/chapter/01/Memory.md 355 | 356 | 源码:https://github.com/bajdcc/learnstl/blob/master/code/01/memory.h 357 | 358 | ## 总结 359 | 360 | 万里长征只走了第一步,继续努力!下一章可以实现变长数组`vector`了。 -------------------------------------------------------------------------------- /chapter/02/String_I.md: -------------------------------------------------------------------------------- 1 | # 第二章:字符串(一) 2 | 3 | ## 前言 4 | 5 | 字符串存放的就是字符数组,简而言之,就是Vector\这样的类型。对数组的管理统统交给Vector类去实现。 6 | 7 | 本系列实验,编译器用GCC,IDE用Clion。 8 | 9 | ## 介绍 10 | 11 | **私有数据** 12 | 13 | - 字符数组:Vector\ 14 | 15 | **公有方法** 16 | 17 | - 构造函数 18 | - 无参 19 | - 带裸指针,以\\0结尾 20 | - 带填充字符及长度 21 | - 拷贝构造 22 | - Get方法 23 | - 字符串长度 24 | - 裸指针 25 | - 字符寻址 26 | - Set方法 27 | - 用下标形式修改,如str\[0\] = 1 28 | - 常用方法 29 | - 运算符重载,参考标准库 30 | - compare比较函数 31 | - substr取子串,引申的left、mid、right方法 32 | - add添加字符 33 | - insert插入字符 34 | - remove删除指定位置的字符 35 | - erase清除指定字符 36 | - clear清空 37 | - reserve预留缓冲区空间 38 | - reverse翻转 39 | - split分割 40 | - find系列函数,此处略 41 | 42 | ## 代码 43 | 44 | 由于知乎系统中的405错误,所以此处不贴代码,详情移步: 45 | 46 | - [string.h](https://github.com/bajdcc/learnstl/blob/master/code/02b/string.h) 47 | - [vector.h](https://github.com/bajdcc/learnstl/blob/master/code/02b/vector.h) 48 | 49 | ## 编写中出现的问题 50 | 51 | **打印出多余字符** 52 | 53 | 这是不论新手老手都会忽略的问题,当我们处理出内存的申请与释放后,字符串的修改可以有条不紊进行。然而,当我们要对字符串进行打印输出时,就忽略了字符串的**终止符**。所以恍然大悟:我并没有去考虑终止符! 54 | 55 | 这个问题比较难找,因为当输出一堆无关字符后,我会下意识认为内存管理出错了,然而并没有找到一丝问题。后面才想到终止符的问题。 56 | 57 | 那么我的设计是:当你每次修改完字符串后,就立马设置终止符\\0。操作包括:增加和删除。而字符串拷贝不必做,因为Vector初始化时当将所有内容置0。 58 | 59 | **常函数的问题** 60 | 61 | 这个问题由上面的问题引申而来,当我们要设置\\0时,需要注意,\\0并不在字符串的有效范围中。由abc字符串,现在length是3,并不会包括终止符,因此只能采用开挂的方式解决。 62 | 63 | 按正常处理,当对Vector寻址时,它会做越界检查,因此这方法没用。如果只能用Vector的get_data取得裸指针,将其const属性去除掉,再进行修改。虽然说违反了一些规定,但实现没有办法。一者,我不希望弄个友元类;二者,如果不借助Vector去管内存,而是String类自己管,又会有一些代码重复的事出现。不过一般情况下不会有人用const_cast,就算人家想用,你怎么限制都是木有用的。假如我直接修改内存好了,那些private、const方法没有丝毫限制作用。 64 | 65 | **API设计的问题** 66 | 67 | 关于String类的接口设计,代码中已经说明了,我搞一堆find系列函数就数起来有16个Orz,说不准加起来一堆有128个。。恨不等用宏去搞,然而宏又不便于调试。。 68 | 69 | 所以还是将replace和search独立开来,用专门的正则表达式类去实现。 70 | 71 | ## 代码中涉及的知识 72 | 73 | 掌握等级: 74 | 75 | 1. 基础 76 | 2. 进阶 77 | 3. 高阶 78 | 79 | 列表: 80 | 81 | - C 82 | 1. (Lv.1)ifndef宏 83 | 2. (Lv.1)include 84 | 3. (Lv.1)指针 85 | 4. (Lv.1)static 86 | 5. (Lv.1)sizeof 87 | 6. (Lv.1)移位 <<= 88 | 7. (Lv.2)calloc, free, realloc 89 | 8. (Lv.2)memcpy, memmove 90 | 9. (Lv.2)assert断言 91 | - C++ 92 | 1. (Lv.1)数据与方法 93 | 2. (Lv.1)访问范围 public private 94 | 3. (Lv.1)const修饰 95 | 4. (Lv.1)auto 96 | 5. (Lv.2)引用 97 | 6. (Lv.2)运算符重载,包括下标、比较、四则、赋值、类型转换等,以及友元重载 98 | 7. (Lv.2)\[C++11]委托构造函数 99 | 8. (Lv.2)\[C++11\]using别名 100 | 9. (Lv.3)类模版 101 | 102 | ## 后续目标 103 | 104 | 1. 用string来实现stream 105 | 2. **实现正则表达式** -------------------------------------------------------------------------------- /chapter/02/Vector_I.md: -------------------------------------------------------------------------------- 1 | # 第二章:变长数组(一) 2 | 3 | ## 地位 4 | 5 | 变长数组是比较基础的数据结构,对初学者而言,是它是它就是它! 6 | 7 | 假如没有循环语句去遍历,那么数组也就不会那么广为人知。数组在生活中也有体现,如报表、清单等等,它意味着连续的空间。大家知道内存其实就是一片连续的空间,所以内存也是一个巨大的数组,不过由于某种原因,你只能访问有限的空间。 8 | 9 | 静态分配的定长数组,那没问题,它长度永远不变,在编译期就可以安排好,没毛病。不过定长数组功能有限,假如要读取全班成绩,没读到尾巴之前,谁也不知道有多少个学生。除非知道了大致的学生总数,先分配空间;否则定长数组就无用武之地。 10 | 11 | 为了解决定长数组的局限性,变长数组应运而生。说是变长,其实是“假”变长。先分配好空间,结果空间不够了,这时候就尴尬了:“老大,留还是撤?”。留的话,不知道后面还有没有空间,结果生死未卜;战略转移的话,很有可能找到新家,就这样决定了! 12 | 13 | 怎么个“战略转移”法?就是找处新地方,将原来的数据搬过去。 14 | 15 | ## 基础 16 | 17 | ### 向量 18 | 19 | 在这里,类名是*vector*即向量。 20 | 21 | 了解一下向量的基本操作: 22 | 23 | - 增:插入至头,插入至中间,添加至末尾,插入连续的数据 24 | - 删:删除头、尾、中间、连续区域 25 | - 改:修改数据,修改预设大小 26 | - 查:查询某个位置的数据,获取数组的有效长度 27 | 28 | 本节是第一节,主要介绍vector的基本功能。后续“增删改查”的环节会添加迭代器。 29 | 30 | ## 思路 31 | 32 | 在先前的内存池基础上实现简单的vector。 33 | 34 | ## 详解 35 | 36 | ### 一、再分配 37 | 38 | 补上先前缺少的重新分配内存方法。 39 | 40 | 思路:在内存池中查找指定大小的块,如果没有就报错,如果有的话,就搬运这些数据,最后把原有内存释放。 41 | 42 | ```c++ 43 | // 重新分配内存 44 | void* _realloc(void* p, uint newSize, uint clsSize) 45 | { 46 | block *blk = static_cast(p); 47 | --blk; // 自减得到块的元信息头 48 | if (!verify_address(blk)) 49 | return nullptr; 50 | auto size = block_align(newSize * clsSize); // 计算新的内存大小 51 | auto _new = _alloc(size); 52 | if (!_new) 53 | { 54 | // 空间不足 55 | _free(blk); 56 | return nullptr; 57 | } 58 | auto oldSize = blk->size; 59 | memmove(_new, p, sizeof(block) * __min(oldSize, size)); // 移动内存 60 | _free(p); 61 | return _new; 62 | } 63 | ``` 64 | 65 | ### 二、设置参数 66 | 67 | 设置一些参数。 68 | 69 | ```c++ 70 | namespace vector_config 71 | { 72 | // 最大空间 73 | static const size_t FULL_SIZE = 0x100000; 74 | // 共用内存池 75 | static memory::memory_pool mem; 76 | 77 | // 默认总容量 78 | static const size_t DEF_SIZE = 0x10; 79 | // 默认递增容量 80 | static const size_t ACC_SIZE = 0x10; 81 | } 82 | ``` 83 | 84 | ### 三、向量 85 | 86 | 目前只实现了向量的核心部分。 87 | 88 | 往向量中添加数据的时候,如果可用空间不够了,就去向内存池申请更大的一片空间。 89 | 90 | ```c++ 91 | // 向量(变长数组) 92 | template 93 | class vector 94 | { 95 | using data_t = T; 96 | 97 | size_t capacity; // 所有空间 98 | size_t used; // 已用空间 99 | size_t acc; // 每次递增大小 100 | 101 | data_t *data; // 数据 102 | 103 | void extend() 104 | { 105 | capacity += acc; 106 | // 注意:扩充容量时,原有数据失效! 107 | data = vector_config::mem.realloc(data, capacity); 108 | } 109 | 110 | public: 111 | 112 | vector() 113 | : capacity(vector_config::DEF_SIZE) 114 | , used(0) 115 | , acc(vector_config::ACC_SIZE) 116 | { 117 | data = vector_config::mem.alloc_array(capacity); 118 | } 119 | 120 | // 添加新元素至末尾 121 | void push(T&& obj) 122 | { 123 | if (used >= capacity) 124 | { 125 | extend(); 126 | } 127 | data[used++] = obj; // T类型的赋值拷贝 128 | } 129 | 130 | // 弹出末尾的元素 131 | T&& pop() 132 | { 133 | if (used == 0) 134 | throw "Empty vector"; 135 | return std::forward(data[--used]); // 返回右值引用 136 | } 137 | 138 | // 获取元素 139 | T&& get(size_t index) const 140 | { 141 | if (index >= used) 142 | throw "Invalid index"; 143 | return std::forward(data[index]); // 返回右值引用 144 | } 145 | 146 | // 获取最末尾元素 147 | T&& top() const 148 | { 149 | return get(used - 1); 150 | } 151 | 152 | // 得到大小 153 | size_t size() const 154 | { 155 | return used; 156 | } 157 | }; 158 | ``` 159 | 160 | ### 六、单元测试 161 | 162 | 测试了添加和寻址功能,目前没啥问题。 163 | 164 | ## 源码 165 | 166 | 文章:https://github.com/bajdcc/learnstl/blob/master/chapter/02/Vector_I.md 167 | 168 | 源码:https://github.com/bajdcc/learnstl/blob/master/code/02/vector.h 169 | 170 | ## 总结 171 | 172 | `vector`的编写过程还算轻松~ -------------------------------------------------------------------------------- /chapter/02/Vector_II.md: -------------------------------------------------------------------------------- 1 | # 第二章:变长数组(二) 2 | 3 | ## 前言 4 | 5 | 先前的vector是建立在memory pool的基础上的,带有点实验的性质。那么我们将重写vector,就用calloc等来实现。 6 | 7 | ## 介绍 8 | 9 | **私有数据** 10 | 11 | - 数据指针:data 12 | - 有效长度:length 13 | - 当前容量:capacity 14 | 15 | **公有方法** 16 | 17 | - 构造函数 18 | - 无参:初始化长度为4的数组 19 | - 带指定长度:按照指定长度初始化 20 | - 带指定长度和初始化值:按照指定长度以指定值初始化 21 | - Get方法 22 | - 对应三个私有数据的Get方法 23 | - 数组寻址:返回index所在位置的元素 24 | - Set方法 25 | - 设置index所在位置上的元素 26 | - 常用方法 27 | - resize 重新设置大小:如果新值依然小于容量,则pass;如果不小于容量,则扩张。扩张的方法:设当前大小为size,找到大于size的最小的2的幂,设成capacity。由于data是calloc来的,所以先用realloc尝试一下,如果不行,再重新calloc并搬运数据。 28 | - add 在末尾添加 29 | - insert 在指定位置插入:插入前要进行部分数组移动的操作 30 | - remove 删除指定位置元素,可以设定删除的那批元素的长度 31 | 32 | ## 代码 33 | 34 | ```c++ 35 | #ifndef _VECTOR_H 36 | #define _VECTOR_H 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | /** 44 | * 变长数组 45 | * @tparam T 数据类型 46 | */ 47 | template 48 | class Vector { 49 | private: 50 | T *data; // 数据 51 | int length; // 使用的长度 52 | int capacity; // 容量 53 | 54 | static const int INIT_SIZE = 4; // 一开始的大小 55 | 56 | private: 57 | /** 58 | * 用t填充初始化后的数组 59 | * @param t 填充值 60 | */ 61 | void fill(const T &t) { 62 | for (int i = 0; i < length; ++i) { 63 | data[i] = t; 64 | } 65 | } 66 | 67 | void print_info() const { 68 | std::cerr << "[VECTOR INFO] capacity: " << capacity << ", length: " << length << std::endl; 69 | } 70 | 71 | void error_index(const char *str, int index) const { 72 | std::cerr << "[VECTOR ERROR] " << str << ": invalid index " << index << std::endl; 73 | print_info(); 74 | assert(!"ERROR"); 75 | exit(-1); 76 | } 77 | 78 | public: 79 | Vector() : data((T *) calloc(INIT_SIZE, sizeof(T))), capacity(INIT_SIZE), length(0) {} 80 | 81 | Vector(int size) : Vector() { resize(size); } 82 | 83 | Vector(int size, const T &t) : Vector(size) { fill(t); } 84 | 85 | ~Vector() { free(data); } 86 | 87 | int get_size() const { return length; } 88 | 89 | int get_capacity() const { return capacity; } 90 | 91 | T *get_data() const { return data; } 92 | 93 | /** 94 | * 更改数组大小 95 | * @param size 新的大小 96 | */ 97 | void resize(int size) { 98 | if (size >= capacity) { // 容量不够 就进行扩张 99 | auto n = size / capacity; // 算几倍 100 | n <<= 1; // 增长一倍 101 | capacity *= n; 102 | auto new_size = sizeof(T) * capacity; 103 | auto new_data = (T *) realloc(data, new_size); // 重新申请 104 | if (!new_data) { 105 | new_data = (T *) calloc(capacity, sizeof(T)); // realloc失败 重新申请 手动拷贝 106 | assert(new_data); // 再次失败则gameover 107 | memcpy(new_data, data, new_size); // 拷贝数据 108 | free(data); // 释放原来的数组 109 | } 110 | data = new_data; 111 | } 112 | length = size; 113 | } 114 | 115 | /** 116 | * 添加数据 117 | * @param t 新增在数组末尾的数据 118 | */ 119 | void add(const T &t) { 120 | data[length] = t; 121 | length++; 122 | resize(length); // 确保容量够用 123 | } 124 | 125 | /** 126 | * 插入数据 127 | * @param index 位置 128 | * @param t 插入到指定位置的数据 129 | */ 130 | void insert(int index, const T &t) { 131 | if (index < 0 || index > length) { 132 | error_index("insert(index)", index); 133 | } 134 | if (index == length) { // 相当于add 135 | add(t); 136 | return; 137 | } 138 | memmove(&data[index + 1], &data[index], sizeof(T) * (length - index)); // 移动部分数组,腾出空间 139 | data[index] = t; // 放置数据 140 | length++; 141 | resize(length); // 确保容量够用 142 | } 143 | 144 | /** 145 | * 删除数据 146 | * @param index 要删除的位置 147 | */ 148 | void remove(int index) { 149 | remove(index, 1); 150 | } 151 | 152 | /** 153 | * 删除数据 154 | * @param index 要删除的位置 155 | * @param len 删除的片段长度 156 | */ 157 | void remove(int index, int len) { 158 | if (index < 0 || index >= length) { 159 | error_index("remove(index)", index); 160 | } 161 | if (len <= 0 || index + len > length) { // 判断len合法 162 | error_index("remove(len)", len); 163 | } 164 | memmove(&data[index], &data[index + len], sizeof(T) * (length - index - len)); // 搬运数组 165 | length -= len; 166 | } 167 | 168 | /** 169 | * 获取数据 170 | * @param index 位置 171 | * @return 数据 172 | */ 173 | const T &get(int index) const { 174 | if (index < 0 || index >= length) { 175 | error_index("get", index); 176 | } 177 | return data[index]; 178 | } 179 | 180 | /** 181 | * 设置数据 182 | * @param index 位置 183 | * @param t 数据 184 | */ 185 | void set(int index, const T &t) const { 186 | if (index < 0 || index >= length) { 187 | error_index("set", index); 188 | } 189 | data[index] = t; 190 | } 191 | }; 192 | 193 | #endif 194 | ``` 195 | 196 | ## 代码中涉及的知识 197 | 198 | 掌握等级: 199 | 200 | 1. 基础 201 | 2. 进阶 202 | 3. 高阶 203 | 204 | 列表: 205 | 206 | - C 207 | 1. (Lv.1)ifndef宏 208 | 2. (Lv.1)include 209 | 3. (Lv.1)指针 210 | 4. (Lv.1)static 211 | 5. (Lv.1)sizeof 212 | 6. (Lv.1)移位 <<= 213 | 7. (Lv.2)calloc, free, realloc 214 | 8. (Lv.2)memcpy, memmove 215 | 9. (Lv.2)assert断言 216 | - C++ 217 | 1. (Lv.1)数据与方法 218 | 2. (Lv.1)访问范围 public private 219 | 3. (Lv.1)const修饰 220 | 4. (Lv.2)引用 221 | 5. (Lv.2)[C++11]委托构造函数 222 | 6. (Lv.3)类模版 223 | 224 | PS:只讲究实用,没必要把C++一大堆特性塞进去。 225 | 226 | 如果要完善一下代码的话,可以再加些: 227 | 1. 拷贝构造 228 | 2. 初始化列表构造 229 | 3. delete修饰 230 | 4. 运算符重载 231 | 5. ... 232 | 233 | ## 后续目标 234 | 235 | 1. 用vector来实现string 236 | 2. 用string来实现stream 237 | 3. 实现LINQ类似的数组查询方式 -------------------------------------------------------------------------------- /code/01/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __STD_MEMORY_H 2 | #define __STD_MEMORY_H 3 | 4 | #include "type.h" 5 | 6 | namespace clib 7 | { 8 | namespace memory 9 | { 10 | using namespace type; 11 | 12 | // 默认的内存分配策略 13 | template 14 | class default_allocator 15 | { 16 | public: 17 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize; 18 | 19 | template 20 | T* __alloc() 21 | { 22 | return new T; 23 | } 24 | 25 | template 26 | T* __alloc_array(uint size) 27 | { 28 | return new T[size]; 29 | } 30 | 31 | template 32 | T* __alloc_args(TArgs ... args) 33 | { 34 | return new T(args); 35 | } 36 | 37 | template 38 | T* __alloc_array_args(uint size, TArgs ... args) 39 | { 40 | return new T[size]; 41 | } 42 | 43 | template 44 | bool __free(T* t) 45 | { 46 | delete t; 47 | return true; 48 | } 49 | 50 | template 51 | bool __free_array(T* t) 52 | { 53 | delete[] t; 54 | return true; 55 | } 56 | }; 57 | 58 | // 原始内存池 59 | template 60 | class legacy_memory_pool 61 | { 62 | // 块 63 | struct block 64 | { 65 | size_t size; // 数据部分的大小 66 | uint flag; // 参数 67 | block *prev; // 前指针 68 | block *next; // 后指针 69 | }; 70 | 71 | // 块参数 72 | enum block_flag 73 | { 74 | BLOCK_USING = 0 75 | }; 76 | 77 | // 内存管理接口 78 | Allocator allocator; 79 | 80 | // 块的元信息部分的大小 81 | static const size_t BLOCK_SIZE = sizeof(block); 82 | // 块大小掩码 83 | static const uint BLOCK_SIZE_MASK = BLOCK_SIZE - 1; 84 | 85 | // 块链表头指针 86 | block *block_head; 87 | // 用于循环遍历的指针 88 | block *block_current; 89 | // 空闲块数 90 | size_t block_available_size; 91 | 92 | // ------------------------ // 93 | 94 | // 块大小对齐 95 | static size_t block_align(size_t size) 96 | { 97 | if ((size & BLOCK_SIZE_MASK) == 0) 98 | return size / BLOCK_SIZE; 99 | return (size / BLOCK_SIZE) + 1; 100 | } 101 | 102 | // 块初始化 103 | static void block_init(block *blk, size_t size) 104 | { 105 | blk->size = size; 106 | blk->flag = 0; 107 | blk->prev = nullptr; 108 | blk->next = nullptr; 109 | } 110 | 111 | // 块连接 112 | static void block_connect(block *blk, block *new_blk) 113 | { 114 | new_blk->prev = blk; 115 | new_blk->next = blk->next; 116 | new_blk->next->prev = new_blk; 117 | blk->next = new_blk; 118 | } 119 | 120 | // 二块合并 121 | static size_t block_merge(block *blk, block *next) 122 | { 123 | auto tmp = next->size + 1; 124 | next->prev = blk; 125 | blk->size += tmp; 126 | blk->next = next->next; 127 | return tmp; 128 | } 129 | 130 | // 三块合并 131 | static size_t block_merge(block *prev, block *blk, block *next) 132 | { 133 | auto tmp = blk->size + next->size + 2; 134 | next->prev = prev; 135 | prev->size += tmp; 136 | prev->next = next->next; 137 | return tmp; 138 | } 139 | 140 | // 块设置参数 141 | static void block_set_flag(block *blk, block_flag flag, uint value) 142 | { 143 | if (value) 144 | { 145 | blk->flag |= 1 << flag; 146 | } 147 | else 148 | { 149 | blk->flag &= ~(1 << flag); 150 | } 151 | } 152 | 153 | // 块获取参数 154 | static uint block_get_flag(block *blk, block_flag flag) 155 | { 156 | return (blk->flag & (1 << flag)) != 0 ? 1 : 0; 157 | } 158 | 159 | // ------------------------ // 160 | 161 | // 创建内存池 162 | void _create() 163 | { 164 | block_head = allocator.template __alloc_array(DEFAULT_ALLOC_BLOCK_SIZE); 165 | _init(); 166 | } 167 | 168 | // 初始化内存池 169 | void _init() 170 | { 171 | block_available_size = DEFAULT_ALLOC_BLOCK_SIZE - 1; 172 | block_init(block_head, block_available_size); 173 | block_head->prev = block_head->next = block_head; 174 | block_current = block_head; 175 | } 176 | 177 | // 销毁内存池 178 | void _destroy() 179 | { 180 | allocator.__free_array(block_head); 181 | } 182 | 183 | // 申请内存 184 | void* _alloc(size_t size) 185 | { 186 | if (size == 0) 187 | return nullptr; 188 | auto old_size = size; 189 | size = block_align(size); 190 | if (size >= block_available_size) 191 | return nullptr; 192 | if (block_current == block_head) 193 | return alloc_free_block(size); 194 | auto blk = block_current; 195 | do 196 | { 197 | if (block_get_flag(blk, BLOCK_USING) == 0 && blk->size >= size) 198 | { 199 | block_current = blk; 200 | return alloc_free_block(size); 201 | } 202 | blk = blk->next; 203 | } while (blk != block_current); 204 | return nullptr; 205 | } 206 | 207 | // 查找空闲块 208 | void* alloc_free_block(size_t size) 209 | { 210 | if (block_current->size == size) // 申请的大小正好是空闲块大小 211 | { 212 | return alloc_cur_block(size + 1); 213 | } 214 | // 申请的空间小于空闲块大小,将空闲块分裂 215 | auto new_size = block_current->size - size - 1; 216 | if (new_size == 0) 217 | return alloc_cur_block(size); // 分裂后的新块空间过低,放弃分裂 218 | block *new_blk = block_current + size + 1; 219 | block_init(new_blk, new_size); 220 | block_connect(block_current, new_blk); 221 | return alloc_cur_block(size); 222 | } 223 | 224 | // 直接使用当前的空闲块 225 | void* alloc_cur_block(size_t size) 226 | { 227 | // 直接使用空闲块 228 | block_set_flag(block_current, BLOCK_USING, 1); // 设置标志为可用 229 | block_current->size = size; 230 | block_available_size -= size + 1; 231 | auto cur = static_cast(block_current + 1); 232 | block_current = block_current->next; // 指向后一个块 233 | return cur; 234 | } 235 | 236 | // 释放内存 237 | bool _free(void* p) 238 | { 239 | block *blk = static_cast(p); 240 | --blk; // 自减得到块的元信息头 241 | if (!verify_address(blk)) 242 | return false; 243 | if (blk->next == blk) // 只有一个块 244 | { 245 | block_set_flag(blk, BLOCK_USING, 0); 246 | return true; 247 | } 248 | if (blk->prev == blk->next && block_get_flag(blk->prev, BLOCK_USING) == 0) // 只有两个块 249 | { 250 | _init(); // 两个块都空闲,直接初始化 251 | return true; 252 | } 253 | auto is_prev_free = block_get_flag(blk->prev, BLOCK_USING) == 0 && blk->prev < blk; 254 | auto is_next_free = block_get_flag(blk->next, BLOCK_USING) == 0 && blk < blk->next; 255 | auto bit = (is_prev_free << 1) + is_next_free; 256 | switch (bit) 257 | { 258 | case 0: 259 | block_available_size += blk->size + 1; 260 | block_set_flag(blk, BLOCK_USING, 0); 261 | break; 262 | case 1: 263 | block_available_size += block_merge(blk, blk->next); 264 | break; 265 | case 2: 266 | block_available_size += block_merge(blk->prev, blk); 267 | break; 268 | case 3: 269 | block_available_size += block_merge(blk->prev, blk, blk->next); 270 | break; 271 | default: 272 | break; 273 | } 274 | return true; 275 | } 276 | 277 | // 验证地址是否合法 278 | bool verify_address(block *blk) 279 | { 280 | if (blk < block_head || blk > block_head + DEFAULT_ALLOC_MEMORY_SIZE - 1) 281 | return false; 282 | return (blk->next->prev == blk) && (blk->prev->next == blk) && (block_get_flag(blk, BLOCK_USING) == 1); 283 | } 284 | 285 | public: 286 | 287 | // 默认的块总数 288 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize; 289 | // 默认的内存总量 290 | static const size_t DEFAULT_ALLOC_MEMORY_SIZE = BLOCK_SIZE * DEFAULT_ALLOC_BLOCK_SIZE; 291 | 292 | legacy_memory_pool() 293 | { 294 | _create(); 295 | } 296 | 297 | ~legacy_memory_pool() 298 | { 299 | _destroy(); 300 | } 301 | 302 | template 303 | T* alloc() 304 | { 305 | return static_cast(_alloc(sizeof(T))); 306 | } 307 | 308 | template 309 | T* alloc_array(uint count) 310 | { 311 | return static_cast(_alloc(count * sizeof(T))); 312 | } 313 | 314 | template 315 | T* alloc_args(TArgs... args) 316 | { 317 | T* obj = static_cast(_alloc(sizeof(T))); 318 | (*obj)(args...); 319 | return obj; 320 | } 321 | 322 | template 323 | T* alloc_array_args(uint count, TArgs... args) 324 | { 325 | T* obj = static_cast(_alloc(count * sizeof(T))); 326 | for (uint i = 0; i < count; ++i) 327 | { 328 | (obj[i])(args...); 329 | } 330 | return obj; 331 | } 332 | 333 | template 334 | bool free(T* obj) 335 | { 336 | return _free(obj); 337 | } 338 | 339 | template 340 | bool free_array(T* obj) 341 | { 342 | return _free(obj); 343 | } 344 | 345 | size_t available() const 346 | { 347 | return block_available_size; 348 | } 349 | }; 350 | 351 | // 基于原始内存池的内存分配策略 352 | template, size_t DefaultSize = Allocator::DEFAULT_ALLOC_BLOCK_SIZE> 353 | class legacy_memory_pool_allocator 354 | { 355 | legacy_memory_pool memory_pool; 356 | 357 | public: 358 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize - 2; 359 | 360 | template 361 | T* __alloc() 362 | { 363 | return memory_pool.template alloc(); 364 | } 365 | 366 | template 367 | T* __alloc_array(uint count) 368 | { 369 | return memory_pool.template alloc_array(count); 370 | } 371 | 372 | template 373 | T* __alloc_args(TArgs ... args) 374 | { 375 | return memory_pool.template alloc_args(args...); 376 | } 377 | 378 | template 379 | T* __alloc_array_args(uint count, TArgs ... args) 380 | { 381 | return memory_pool.template alloc_array_args(count, args...); 382 | } 383 | 384 | template 385 | bool __free(T* t) 386 | { 387 | return memory_pool.free(t); 388 | } 389 | 390 | template 391 | bool __free_array(T* t) 392 | { 393 | return memory_pool.free_array(t); 394 | } 395 | }; 396 | 397 | template::DEFAULT_ALLOC_BLOCK_SIZE> 398 | using memory_pool = legacy_memory_pool, DefaultSize>>; 399 | } 400 | } 401 | 402 | #endif -------------------------------------------------------------------------------- /code/01/type.h: -------------------------------------------------------------------------------- 1 | #ifndef __STD_TYPE_H 2 | #define __STD_TYPE_H 3 | 4 | namespace clib 5 | { 6 | namespace type 7 | { 8 | using int8 = signed __int8; 9 | using uint8 = unsigned __int8; 10 | using int16 = signed __int16; 11 | using uint16 = unsigned __int16; 12 | using int32 = signed __int32; 13 | using uint32 = unsigned __int32; 14 | using int64 = signed __int64; 15 | using uint64 = unsigned __int64; 16 | 17 | #ifdef WIN32 18 | using sint = int32; 19 | using uint = uint32; 20 | #else 21 | using sint = int64; 22 | using uint = uint64; 23 | #endif 24 | 25 | using byte = uint8; 26 | using size_t = uint; 27 | } 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /code/01/unittest.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "../Learncpp/memory.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace UnitTest 8 | { 9 | TEST_CLASS(UnitTest_Memory) 10 | { 11 | public: 12 | 13 | TEST_METHOD(TestAllocAndFree1) 14 | { 15 | clib::memory::memory_pool<10> m; 16 | auto i = m.alloc(); 17 | *i = 100; 18 | Assert::IsTrue(m.free(i), L"Success free"); 19 | Assert::IsFalse(m.free(i), L"Dup free"); 20 | Assert::IsFalse(m.free(nullptr), L"Free null"); 21 | Assert::IsNull(m.alloc_array(0x100000), L"Alloc much"); 22 | Assert::AreEqual(i, m.alloc(), L"Alloc equal"); 23 | Assert::AreEqual(100, *i, L"Alloc equal"); 24 | auto j = m.alloc(); 25 | Assert::AreEqual(8, j - i, L"Alloc equal"); 26 | auto k = m.alloc(); 27 | Assert::AreEqual(8, k - j, L"Alloc equal"); 28 | Assert::IsNull(m.alloc(), L"No enough memory"); 29 | } 30 | 31 | TEST_METHOD(TestAllocAndFree2) 32 | { 33 | clib::memory::memory_pool<16> m; 34 | int* i[] = 35 | { 36 | m.alloc(), 37 | m.alloc_array(5), 38 | m.alloc(), 39 | m.alloc_array(5), 40 | m.alloc(), 41 | }; 42 | *(i[0]) = 1; 43 | *(i[1]) = 2; 44 | *(i[2]) = 3; 45 | *(i[3]) = 4; 46 | *(i[4]) = 5; 47 | Assert::IsNull(m.alloc_array(8)); 48 | Assert::AreEqual(true, m.free(i[1])); 49 | Assert::AreEqual(true, m.free(i[3])); 50 | Assert::AreEqual(true, m.free(i[2])); 51 | i[1] = m.alloc_array(5); 52 | Assert::IsNotNull(i[1]); 53 | Assert::AreEqual(2, *(i[1])); 54 | i[2] = m.alloc_array(5); 55 | Assert::IsNotNull(i[2]); 56 | Assert::AreEqual(3, *(i[2])); 57 | i[3] = m.alloc(); 58 | Assert::IsNotNull(i[3]); 59 | } 60 | }; 61 | } -------------------------------------------------------------------------------- /code/02/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __STD_MEMORY_H 2 | #define __STD_MEMORY_H 3 | 4 | #include "type.h" 5 | 6 | namespace clib 7 | { 8 | namespace memory 9 | { 10 | using namespace type; 11 | 12 | // 默认的内存分配策略 13 | template 14 | class default_allocator 15 | { 16 | public: 17 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize; 18 | 19 | template 20 | T* __alloc() 21 | { 22 | return new T; 23 | } 24 | 25 | template 26 | T* __alloc_array(uint size) 27 | { 28 | return new T[size]; 29 | } 30 | 31 | template 32 | T* __alloc_args(const TArgs&& ... args) 33 | { 34 | return new T(std::forward(args)...); 35 | } 36 | 37 | template 38 | T* __alloc_array_args(uint size, const TArgs&& ... args) 39 | { 40 | return new T[size]; 41 | } 42 | 43 | template 44 | bool __free(T* t) 45 | { 46 | delete t; 47 | return true; 48 | } 49 | 50 | template 51 | bool __free_array(T* t) 52 | { 53 | delete[] t; 54 | return true; 55 | } 56 | }; 57 | 58 | // 原始内存池 59 | template 60 | class legacy_memory_pool 61 | { 62 | // 块 63 | struct block 64 | { 65 | size_t size; // 数据部分的大小 66 | uint flag; // 参数 67 | block *prev; // 前指针 68 | block *next; // 后指针 69 | }; 70 | 71 | // 块参数 72 | enum block_flag 73 | { 74 | BLOCK_USING = 0 75 | }; 76 | 77 | // 内存管理接口 78 | Allocator allocator; 79 | 80 | // 块的元信息部分的大小 81 | static const size_t BLOCK_SIZE = sizeof(block); 82 | // 块大小掩码 83 | static const uint BLOCK_SIZE_MASK = BLOCK_SIZE - 1; 84 | 85 | // 块链表头指针 86 | block *block_head; 87 | // 用于循环遍历的指针 88 | block *block_current; 89 | // 空闲块数 90 | size_t block_available_size; 91 | 92 | // ------------------------ // 93 | 94 | // 块大小对齐 95 | static size_t block_align(size_t size) 96 | { 97 | if ((size & BLOCK_SIZE_MASK) == 0) 98 | return size / BLOCK_SIZE; 99 | return (size / BLOCK_SIZE) + 1; 100 | } 101 | 102 | // 块初始化 103 | static void block_init(block *blk, size_t size) 104 | { 105 | blk->size = size; 106 | blk->flag = 0; 107 | blk->prev = nullptr; 108 | blk->next = nullptr; 109 | } 110 | 111 | // 块连接 112 | static void block_connect(block *blk, block *new_blk) 113 | { 114 | new_blk->prev = blk; 115 | new_blk->next = blk->next; 116 | new_blk->next->prev = new_blk; 117 | blk->next = new_blk; 118 | } 119 | 120 | // 二块合并 121 | static size_t block_merge(block *blk, block *next) 122 | { 123 | auto tmp = next->size + 1; 124 | next->prev = blk; 125 | blk->size += tmp; 126 | blk->next = next->next; 127 | return tmp; 128 | } 129 | 130 | // 三块合并 131 | static size_t block_merge(block *prev, block *blk, block *next) 132 | { 133 | auto tmp = blk->size + next->size + 2; 134 | next->prev = prev; 135 | prev->size += tmp; 136 | prev->next = next->next; 137 | return tmp; 138 | } 139 | 140 | // 块设置参数 141 | static void block_set_flag(block *blk, block_flag flag, uint value) 142 | { 143 | if (value) 144 | { 145 | blk->flag |= 1 << flag; 146 | } 147 | else 148 | { 149 | blk->flag &= ~(1 << flag); 150 | } 151 | } 152 | 153 | // 块获取参数 154 | static uint block_get_flag(block *blk, block_flag flag) 155 | { 156 | return (blk->flag & (1 << flag)) != 0 ? 1 : 0; 157 | } 158 | 159 | // ------------------------ // 160 | 161 | // 创建内存池 162 | void _create() 163 | { 164 | block_head = allocator.template __alloc_array(DEFAULT_ALLOC_BLOCK_SIZE); 165 | _init(); 166 | } 167 | 168 | // 初始化内存池 169 | void _init() 170 | { 171 | block_available_size = DEFAULT_ALLOC_BLOCK_SIZE - 1; 172 | block_init(block_head, block_available_size); 173 | block_head->prev = block_head->next = block_head; 174 | block_current = block_head; 175 | } 176 | 177 | // 销毁内存池 178 | void _destroy() 179 | { 180 | allocator.__free_array(block_head); 181 | } 182 | 183 | // 申请内存 184 | void* _alloc(size_t size) 185 | { 186 | if (size == 0) 187 | return nullptr; 188 | auto old_size = size; 189 | size = block_align(size); 190 | if (size >= block_available_size) 191 | return nullptr; 192 | if (block_current == block_head) 193 | return alloc_free_block(size); 194 | auto blk = block_current; 195 | do 196 | { 197 | if (block_get_flag(blk, BLOCK_USING) == 0 && blk->size >= size) 198 | { 199 | block_current = blk; 200 | return alloc_free_block(size); 201 | } 202 | blk = blk->next; 203 | } while (blk != block_current); 204 | return nullptr; 205 | } 206 | 207 | // 查找空闲块 208 | void* alloc_free_block(size_t size) 209 | { 210 | if (block_current->size == size) // 申请的大小正好是空闲块大小 211 | { 212 | return alloc_cur_block(size + 1); 213 | } 214 | // 申请的空间小于空闲块大小,将空闲块分裂 215 | auto new_size = block_current->size - size - 1; 216 | if (new_size == 0) 217 | return alloc_cur_block(size); // 分裂后的新块空间过低,放弃分裂 218 | block *new_blk = block_current + size + 1; 219 | block_init(new_blk, new_size); 220 | block_connect(block_current, new_blk); 221 | return alloc_cur_block(size); 222 | } 223 | 224 | // 直接使用当前的空闲块 225 | void* alloc_cur_block(size_t size) 226 | { 227 | // 直接使用空闲块 228 | block_set_flag(block_current, BLOCK_USING, 1); // 设置标志为可用 229 | block_current->size = size; 230 | block_available_size -= size + 1; 231 | auto cur = static_cast(block_current + 1); 232 | block_current = block_current->next; // 指向后一个块 233 | return cur; 234 | } 235 | 236 | // 释放内存 237 | bool _free(void* p) 238 | { 239 | block *blk = static_cast(p); 240 | --blk; // 自减得到块的元信息头 241 | if (!verify_address(blk)) 242 | return false; 243 | if (blk->next == blk) // 只有一个块 244 | { 245 | block_set_flag(blk, BLOCK_USING, 0); 246 | return true; 247 | } 248 | if (blk->prev == blk->next && block_get_flag(blk->prev, BLOCK_USING) == 0) // 只有两个块 249 | { 250 | _init(); // 两个块都空闲,直接初始化 251 | return true; 252 | } 253 | auto is_prev_free = block_get_flag(blk->prev, BLOCK_USING) == 0 && blk->prev < blk; 254 | auto is_next_free = block_get_flag(blk->next, BLOCK_USING) == 0 && blk < blk->next; 255 | auto bit = (is_prev_free << 1) + is_next_free; 256 | switch (bit) 257 | { 258 | case 0: 259 | block_available_size += blk->size + 1; 260 | block_set_flag(blk, BLOCK_USING, 0); 261 | break; 262 | case 1: 263 | block_available_size += block_merge(blk, blk->next); 264 | break; 265 | case 2: 266 | block_available_size += block_merge(blk->prev, blk); 267 | break; 268 | case 3: 269 | block_available_size += block_merge(blk->prev, blk, blk->next); 270 | break; 271 | default: 272 | break; 273 | } 274 | return true; 275 | } 276 | 277 | // 验证地址是否合法 278 | bool verify_address(block *blk) 279 | { 280 | if (blk < block_head || blk > block_head + DEFAULT_ALLOC_MEMORY_SIZE - 1) 281 | return false; 282 | return (blk->next->prev == blk) && (blk->prev->next == blk) && (block_get_flag(blk, BLOCK_USING) == 1); 283 | } 284 | 285 | // 重新分配内存 286 | void* _realloc(void* p, uint newSize, uint clsSize) 287 | { 288 | block *blk = static_cast(p); 289 | --blk; // 自减得到块的元信息头 290 | if (!verify_address(blk)) 291 | return nullptr; 292 | auto size = block_align(newSize * clsSize); // 计算新的内存大小 293 | auto _new = _alloc(size); 294 | if (!_new) 295 | { 296 | // 空间不足 297 | _free(blk); 298 | return nullptr; 299 | } 300 | auto oldSize = blk->size; 301 | memmove(_new, p, sizeof(block) * __min(oldSize, size)); // 移动内存 302 | _free(p); 303 | return _new; 304 | } 305 | 306 | public: 307 | 308 | // 默认的块总数 309 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize; 310 | // 默认的内存总量 311 | static const size_t DEFAULT_ALLOC_MEMORY_SIZE = BLOCK_SIZE * DEFAULT_ALLOC_BLOCK_SIZE; 312 | 313 | legacy_memory_pool() 314 | { 315 | _create(); 316 | } 317 | 318 | ~legacy_memory_pool() 319 | { 320 | _destroy(); 321 | } 322 | 323 | template 324 | T* alloc() 325 | { 326 | return static_cast(_alloc(sizeof(T))); 327 | } 328 | 329 | template 330 | T* alloc_array(uint count) 331 | { 332 | return static_cast(_alloc(count * sizeof(T))); 333 | } 334 | 335 | template 336 | T* alloc_args(const TArgs&& ... args) 337 | { 338 | T* obj = static_cast(_alloc(sizeof(T))); 339 | (*obj)(std::forward(args)...); 340 | return obj; 341 | } 342 | 343 | template 344 | T* alloc_array_args(uint count, const TArgs&& ... args) 345 | { 346 | T* obj = static_cast(_alloc(count * sizeof(T))); 347 | for (uint i = 0; i < count; ++i) 348 | { 349 | (obj[i])(std::forward(args)...); 350 | } 351 | return obj; 352 | } 353 | 354 | template 355 | T* realloc(T* obj, uint newSize) 356 | { 357 | return static_cast(_realloc(obj, newSize, sizeof(T))); 358 | } 359 | 360 | template 361 | bool free(T* obj) 362 | { 363 | return _free(obj); 364 | } 365 | 366 | template 367 | bool free_array(T* obj) 368 | { 369 | return _free(obj); 370 | } 371 | 372 | size_t available() const 373 | { 374 | return block_available_size; 375 | } 376 | }; 377 | 378 | // 基于原始内存池的内存分配策略 379 | template, size_t DefaultSize = Allocator::DEFAULT_ALLOC_BLOCK_SIZE> 380 | class legacy_memory_pool_allocator 381 | { 382 | legacy_memory_pool memory_pool; 383 | 384 | public: 385 | static const size_t DEFAULT_ALLOC_BLOCK_SIZE = DefaultSize - 2; 386 | 387 | template 388 | T* __alloc() 389 | { 390 | return memory_pool.template alloc(); 391 | } 392 | 393 | template 394 | T* __alloc_array(uint count) 395 | { 396 | return memory_pool.template alloc_array(count); 397 | } 398 | 399 | template 400 | T* __alloc_args(const TArgs&& ... args) 401 | { 402 | return memory_pool.template alloc_args(std::forward(args)...); 403 | } 404 | 405 | template 406 | T* __alloc_array_args(uint count, const TArgs&& ... args) 407 | { 408 | return memory_pool.template alloc_array_args(count, std::forward(args)...); 409 | } 410 | 411 | template 412 | T* __realloc(T* t, uint oldSize, uint newSize) 413 | { 414 | return memory_pool.template realloc(t, oldSize, newSize); 415 | } 416 | 417 | template 418 | bool __free(T* t) 419 | { 420 | return memory_pool.free(t); 421 | } 422 | 423 | template 424 | bool __free_array(T* t) 425 | { 426 | return memory_pool.free_array(t); 427 | } 428 | }; 429 | 430 | template::DEFAULT_ALLOC_BLOCK_SIZE> 431 | using memory_pool = legacy_memory_pool, DefaultSize>>; 432 | } 433 | } 434 | 435 | #endif -------------------------------------------------------------------------------- /code/02/type.h: -------------------------------------------------------------------------------- 1 | #ifndef __STD_TYPE_H 2 | #define __STD_TYPE_H 3 | 4 | #include 5 | 6 | namespace clib 7 | { 8 | namespace type 9 | { 10 | using int8 = signed __int8; 11 | using uint8 = unsigned __int8; 12 | using int16 = signed __int16; 13 | using uint16 = unsigned __int16; 14 | using int32 = signed __int32; 15 | using uint32 = unsigned __int32; 16 | using int64 = signed __int64; 17 | using uint64 = unsigned __int64; 18 | 19 | #ifdef WIN32 20 | using sint = int32; 21 | using uint = uint32; 22 | #else 23 | using sint = int64; 24 | using uint = uint64; 25 | #endif 26 | 27 | using byte = uint8; 28 | using size_t = uint; 29 | } 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /code/02/unittest2.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CppUnitTest.h" 3 | #include "../Learncpp/vector.h" 4 | 5 | using namespace Microsoft::VisualStudio::CppUnitTestFramework; 6 | 7 | namespace UnitTest 8 | { 9 | TEST_CLASS(UnitTest_Vector) 10 | { 11 | public: 12 | 13 | TEST_METHOD(Vector1) 14 | { 15 | clib::collections::vector vec; 16 | vec.push(100); 17 | Assert::AreEqual(100, vec.top()); 18 | vec.push(200); 19 | Assert::AreEqual(200, vec.get(1)); 20 | Assert::AreEqual(2U, vec.size()); 21 | vec.pop(); 22 | Assert::AreEqual(100, vec.top()); 23 | Assert::AreEqual(1U, vec.size()); 24 | vec.pop(); 25 | Assert::AreEqual(0U, vec.size()); 26 | for (auto i = 0; i < 0x20; i++) 27 | { 28 | vec.push(std::forward(i)); 29 | } 30 | for (auto i = 0; i < 0x20; i++) 31 | { 32 | Assert::AreEqual(i, vec.get(i)); 33 | } 34 | } 35 | }; 36 | } -------------------------------------------------------------------------------- /code/02/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef __STD_VECTOR_H 2 | #define __STD_VECTOR_H 3 | 4 | #include "memory.h" 5 | 6 | namespace clib 7 | { 8 | namespace collections 9 | { 10 | using namespace type; 11 | 12 | namespace vector_config 13 | { 14 | // 最大空间 15 | static const size_t FULL_SIZE = 0x100000; 16 | // 共用内存池 17 | static memory::memory_pool mem; 18 | 19 | // 默认总容量 20 | static const size_t DEF_SIZE = 0x10; 21 | // 默认递增容量 22 | static const size_t ACC_SIZE = 0x10; 23 | } 24 | 25 | // 向量(变长数组) 26 | template 27 | class vector 28 | { 29 | using data_t = T; 30 | 31 | size_t capacity; // 所有空间 32 | size_t used; // 已用空间 33 | size_t acc; // 每次递增大小 34 | 35 | data_t *data; // 数据 36 | 37 | void extend() 38 | { 39 | capacity += acc; 40 | // 注意:扩充容量时,原有数据失效! 41 | data = vector_config::mem.realloc(data, capacity); 42 | } 43 | 44 | public: 45 | 46 | vector() 47 | : capacity(vector_config::DEF_SIZE) 48 | , used(0) 49 | , acc(vector_config::ACC_SIZE) 50 | { 51 | data = vector_config::mem.alloc_array(capacity); 52 | } 53 | 54 | // 添加新元素至末尾 55 | void push(T&& obj) 56 | { 57 | if (used >= capacity) 58 | { 59 | extend(); 60 | } 61 | data[used++] = obj; // T类型的赋值拷贝 62 | } 63 | 64 | // 弹出末尾的元素 65 | T&& pop() 66 | { 67 | if (used == 0) 68 | throw "Empty vector"; 69 | return std::forward(data[--used]); // 返回右值引用 70 | } 71 | 72 | // 获取元素 73 | T&& get(size_t index) const 74 | { 75 | if (index >= used) 76 | throw "Invalid index"; 77 | return std::forward(data[index]); // 返回右值引用 78 | } 79 | 80 | // 获取最末尾元素 81 | T&& top() const 82 | { 83 | return get(used - 1); 84 | } 85 | 86 | // 得到大小 87 | size_t size() const 88 | { 89 | return used; 90 | } 91 | }; 92 | } 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /code/02a/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H 2 | #define _VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /** 10 | * 变长数组 11 | * @tparam T 数据类型 12 | */ 13 | template 14 | class Vector { 15 | private: 16 | T *data; // 数据 17 | int length; // 使用的长度 18 | int capacity; // 容量 19 | 20 | static const int INIT_SIZE = 4; // 一开始的大小 21 | 22 | private: 23 | /** 24 | * 用t填充初始化后的数组 25 | * @param t 填充值 26 | */ 27 | void fill(const T &t) { 28 | for (int i = 0; i < length; ++i) { 29 | data[i] = t; 30 | } 31 | } 32 | 33 | void print_info() const { 34 | std::cerr << "[VECTOR INFO] capacity: " << capacity << ", length: " << length << std::endl; 35 | } 36 | 37 | void error_index(const char *str, int index) const { 38 | std::cerr << "[VECTOR ERROR] " << str << ": invalid index " << index << std::endl; 39 | print_info(); 40 | assert(!"ERROR"); 41 | exit(-1); 42 | } 43 | 44 | public: 45 | Vector() : data((T *) calloc(INIT_SIZE, sizeof(T))), capacity(INIT_SIZE), length(0) {} 46 | 47 | Vector(int size) : Vector() { resize(size); } 48 | 49 | Vector(int size, const T &t) : Vector(size) { fill(t); } 50 | 51 | ~Vector() { free(data); } 52 | 53 | int get_size() const { return length; } 54 | 55 | int get_capacity() const { return capacity; } 56 | 57 | T *get_data() const { return data; } 58 | 59 | /** 60 | * 更改数组大小 61 | * @param size 新的大小 62 | */ 63 | void resize(int size) { 64 | if (size >= capacity) { // 容量不够 就进行扩张 65 | auto n = size / capacity; // 算几倍 66 | n <<= 1; // 增长一倍 67 | capacity *= n; 68 | auto new_size = sizeof(T) * capacity; 69 | auto new_data = (T *) realloc(data, new_size); // 重新申请 70 | if (!new_data) { 71 | new_data = (T *) calloc(capacity, sizeof(T)); // realloc失败 重新申请 手动拷贝 72 | assert(new_data); // 再次失败则gameover 73 | memcpy(new_data, data, new_size); // 拷贝数据 74 | free(data); // 释放原来的数组 75 | } 76 | data = new_data; 77 | } 78 | length = size; 79 | } 80 | 81 | /** 82 | * 添加数据 83 | * @param t 新增在数组末尾的数据 84 | */ 85 | void add(const T &t) { 86 | data[length] = t; 87 | length++; 88 | resize(length); // 确保容量够用 89 | } 90 | 91 | /** 92 | * 插入数据 93 | * @param index 位置 94 | * @param t 插入到指定位置的数据 95 | */ 96 | void insert(int index, const T &t) { 97 | if (index < 0 || index > length) { 98 | error_index("insert(index)", index); 99 | } 100 | if (index == length) { // 相当于add 101 | add(t); 102 | return; 103 | } 104 | memmove(&data[index + 1], &data[index], sizeof(T) * (length - index)); // 移动部分数组,腾出空间 105 | data[index] = t; // 放置数据 106 | length++; 107 | resize(length); // 确保容量够用 108 | } 109 | 110 | /** 111 | * 删除数据 112 | * @param index 要删除的位置 113 | */ 114 | void remove(int index) { 115 | remove(index, 1); 116 | } 117 | 118 | /** 119 | * 删除数据 120 | * @param index 要删除的位置 121 | * @param len 删除的片段长度 122 | */ 123 | void remove(int index, int len) { 124 | if (index < 0 || index >= length) { 125 | error_index("remove(index)", index); 126 | } 127 | if (len <= 0 || index + len > length) { // 判断len合法 128 | error_index("remove(len)", len); 129 | } 130 | memmove(&data[index], &data[index + len], sizeof(T) * (length - index - len)); // 搬运数组 131 | length -= len; 132 | } 133 | 134 | /** 135 | * 获取数据 136 | * @param index 位置 137 | * @return 数据 138 | */ 139 | const T &get(int index) const { 140 | if (index < 0 || index >= length) { 141 | error_index("get", index); 142 | } 143 | return data[index]; 144 | } 145 | 146 | /** 147 | * 设置数据 148 | * @param index 位置 149 | * @param t 数据 150 | */ 151 | void set(int index, const T &t) const { 152 | if (index < 0 || index >= length) { 153 | error_index("set", index); 154 | } 155 | data[index] = t; 156 | } 157 | }; 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /code/02b/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "vector.h" 5 | 6 | /** 7 | * 字符串 8 | * @tparam T 字符类型 9 | */ 10 | template 11 | class String { 12 | private: 13 | Vector data; // 字符数组 14 | 15 | static const int CHAR_SIZE = sizeof(T); // 字符大小 16 | 17 | private: 18 | /** 19 | * 从字符串指针中创建对象 20 | * @param str 字符串指针 21 | */ 22 | void copy(const T *str) { 23 | T c; 24 | while (c = *str++) { 25 | data.add(c); 26 | } 27 | } 28 | 29 | /** 30 | * 设置最后一个字符为零 31 | */ 32 | void set_end() const { 33 | const_cast(get_data())[get_length()] = '\0'; // 由于边界检查,只好出此下策 :( 34 | } 35 | 36 | public: 37 | String() {} 38 | 39 | String(const T *str) { copy(str); } 40 | 41 | String(int size, const T &t) : data(size, t) {} 42 | 43 | String(const String &s) : data(s.data) {} 44 | 45 | int get_length() const { return data.get_size(); } 46 | 47 | int is_empty() const { return data.get_size() == 0; } 48 | 49 | const T *get_data() const { 50 | return data.get_data(); 51 | } 52 | 53 | String &operator+(const T &t) { // string + char 54 | return (data.add(t), *this); 55 | } 56 | 57 | friend String &operator+(const T &t, const String &s) { // char + string 58 | return s + t; 59 | } 60 | 61 | String &operator+=(const T &t) { // string += char 62 | return *this + t; 63 | } 64 | 65 | String &operator=(const String &s) { // string = string2 66 | return (data = s.data, *this); 67 | } 68 | 69 | String &operator=(const T *str) { // string = "abc" 70 | return (copy(str), *this); 71 | } 72 | 73 | bool operator==(const String &s) { 74 | return compare(s) == 0; 75 | } 76 | 77 | bool operator!=(const String &s) { 78 | return compare(s) != 0; 79 | } 80 | 81 | bool operator>(const String &s) { 82 | return compare(s) > 0; 83 | } 84 | 85 | bool operator<(const String &s) { 86 | return compare(s) < 0; 87 | } 88 | 89 | bool operator>=(const String &s) { 90 | return compare(s) >= 0; 91 | } 92 | 93 | bool operator<=(const String &s) { 94 | return compare(s) <= 0; 95 | } 96 | 97 | operator const T *() const { // 便于格式转换 98 | return get_data(); 99 | } 100 | 101 | T &operator[](int index) { // 允许修改 102 | return data[index]; 103 | } 104 | 105 | /** 106 | * 字符串比较 107 | * @param s 要比较的字符串 108 | * @return 相等为0,小于为-1,大于为1 109 | */ 110 | int compare(const String &s) const { 111 | auto a_len = get_length(); 112 | auto b_len = s.get_length(); 113 | auto min_len = a_len > b_len ? b_len : a_len; 114 | for (auto i = 0; i < min_len; ++i) { 115 | if ((*this)[i] < s[i]) { 116 | return -1; 117 | } else if ((*this)[i] > s[i]) { 118 | return 1; 119 | } 120 | } 121 | if (a_len < b_len) { 122 | return -1; 123 | } else if (a_len > b_len) { 124 | return 1; 125 | } 126 | return 0; 127 | } 128 | 129 | /** 130 | * 生成子串 131 | * @param start 起始位置 132 | * @param length 子串长度 133 | * @return 子串 134 | */ 135 | String substr(int start, int length = -1) const { 136 | /* (GCC) 注意,这里编译器进行NRVO优化 137 | * 如果我这么做: 138 | * auto a = String("hello world"); 139 | * auto b = a.substr(4,4); 140 | * 则自始至终,只有a和b分别调用一次默认构造函数 141 | * 不会调用拷贝构造以及赋值构造 142 | * 因此一般情况下没有必要涉及移动语义 143 | */ 144 | String s; 145 | if (length == -1) length = get_length(); 146 | auto end = (start + length) > get_length() ? get_length() : (start + length); 147 | for (auto i = start; i < end; ++i) { 148 | s += (*this)[i]; 149 | } 150 | s += '\0'; 151 | s.remove(s.get_length() - 1); // 末尾置零 152 | return s; // 优化掉了,不会调用构造函数 153 | } 154 | 155 | /** 156 | * 生成从左开始的子串 157 | * @param length 子串长度 158 | * @return 子串 159 | */ 160 | String left(int length) const { 161 | return substr(0, length); 162 | } 163 | 164 | /** 165 | * 生成中间的子串 166 | * @param start 起始位置 167 | * @param end 结束位置 168 | * @return 子串 169 | */ 170 | String mid(int start, int end) const { 171 | return substr(start, end - start + 1); 172 | } 173 | 174 | /** 175 | * 生成从右开始的子串 176 | * @param length 子串长度 177 | * @return 子串 178 | */ 179 | String right(int length) const { 180 | return substr(get_length() - length); 181 | } 182 | 183 | /** 184 | * 查询字符 185 | * @param index 位置 186 | * @return 指定位置的字符 187 | */ 188 | const T &get(int index) const { // 禁止修改 189 | return data.get(index); 190 | } 191 | 192 | /** 193 | * 添加字符 194 | * @param t 字符 195 | */ 196 | void add(const T &t) { 197 | (*this) += t; 198 | set_end(); 199 | } 200 | 201 | /** 202 | * 插入字符 203 | * @param index 位置 204 | * @param t 插入到指定位置的字符 205 | */ 206 | void insert(int index, const T &t) { 207 | data.insert(index, t); 208 | } 209 | 210 | /** 211 | * 删除指定位置的字符 212 | * @param index 要删除的位置 213 | */ 214 | void remove(int index) { 215 | data.remove(index); 216 | set_end(); 217 | } 218 | 219 | /** 220 | * 删除指定位置的连续字符 221 | * @param index 要删除的位置 222 | * @param len 删除的字符串长度 223 | */ 224 | void remove(int index, int len) { 225 | data.remove(index, len); 226 | set_end(); 227 | } 228 | 229 | /** 230 | * 清除指定字符 231 | * @param t 字符 232 | */ 233 | void erase(const T &t) { 234 | for (auto i = get_length() - 1; i >= 0; --i) { 235 | if ((*this)[i] == t) { 236 | remove(i); 237 | } 238 | } 239 | } 240 | 241 | /** 242 | * 清空字符串 243 | */ 244 | void clear() { 245 | if (!is_empty()) { 246 | data.clear(); 247 | set_end(); 248 | } 249 | } 250 | 251 | /** 252 | * 事先预留一定空间来存放字符数组 253 | * @param size 字符数组大小 254 | */ 255 | void reserve(int size) { 256 | data.resize(size); 257 | } 258 | 259 | /** 260 | * 字符串翻转 261 | * @return 翻转后的字符串 262 | */ 263 | String reverse() { 264 | auto s(*this); 265 | auto length = get_length(); 266 | for (int i = 0; i < (length + 1) / 2; ++i) { 267 | s[i] = s[length - i - 1]; 268 | } 269 | return s; 270 | } 271 | 272 | /** 273 | * 字符串分割 274 | * @param t 分隔符 275 | * @return 字符串数组 276 | */ 277 | Vector> split(const T &t) const { 278 | Vector> v; 279 | auto start = 0; 280 | auto length = 0; 281 | for (auto i = 0; i < get_length(); ++i) { 282 | if ((*this)[i] == t) { 283 | if (length > 0) { 284 | v += substr(start, length); 285 | length = 0; 286 | } 287 | start = i + 1; 288 | } else { 289 | length++; 290 | } 291 | } 292 | if (length > 0) 293 | v += substr(start, length); 294 | return v; 295 | } 296 | 297 | // ------------------------------------------------- 298 | 299 | // PS: 更加高级的find和replace用正则表达式实现 300 | 301 | /** 302 | * 查找第一次出现的指定字符位置 303 | * @param t 字符 304 | * @return 位置,-1则不存在 305 | */ 306 | int find(const T &t) const { 307 | for (auto i = 0; i < get_length(); ++i) { 308 | if ((*this)[i] == t) 309 | return i; 310 | } 311 | return -1; 312 | } 313 | 314 | /** 315 | * 查找最后一次出现的指定字符位置 316 | * @param t 字符 317 | * @return 位置,-1则不存在 318 | */ 319 | int find_last(const T &t) const { 320 | auto index = -1; 321 | for (auto i = 0; i < get_length(); ++i) { 322 | if ((*this)[i] == t) 323 | index = i; 324 | } 325 | return index; 326 | } 327 | 328 | /** 329 | * 查找除指定字符以外的第一次出现的字符位置 330 | * @param t 字符 331 | * @return 位置,-1则不存在 332 | */ 333 | int find_not(const T &t) const { 334 | for (auto i = 0; i < get_length(); ++i) { 335 | if ((*this)[i] != t) 336 | return i; 337 | } 338 | return -1; 339 | } 340 | 341 | /** 342 | * 查找除指定字符以外的最后一次出现的字符位置 343 | * @param t 字符 344 | * @return 位置,-1则不存在 345 | */ 346 | int find_last_not(const T &t) const { 347 | auto index = -1; 348 | for (auto i = 0; i < get_length(); ++i) { 349 | if ((*this)[i] != t) 350 | index = i; 351 | } 352 | return index; 353 | } 354 | 355 | /** 356 | * 查找第一次出现的指定字符位置(从右往左) 357 | * @param t 字符 358 | * @return 位置,-1则不存在 359 | */ 360 | int findr(const T &t) const { 361 | for (auto i = get_length() - 1; i >= 0; --i) { 362 | if ((*this)[i] == t) 363 | return i; 364 | } 365 | return -1; 366 | } 367 | 368 | /** 369 | * 查找最后一次出现的指定字符位置(从右往左) 370 | * @param t 字符 371 | * @return 位置,-1则不存在 372 | */ 373 | int findr_last(const T &t) const { 374 | auto index = -1; 375 | for (auto i = get_length() - 1; i >= 0; --i) { 376 | if ((*this)[i] == t) 377 | index = i; 378 | } 379 | return index; 380 | } 381 | 382 | /** 383 | * 查找最后一次出现的指定字符位置(从右往左) 384 | * @param t 字符 385 | * @return 位置,-1则不存在 386 | */ 387 | int findr_not(const T &t) const { 388 | for (auto i = get_length() - 1; i >= 0; --i) { 389 | if ((*this)[i] == t) 390 | return i; 391 | } 392 | return -1; 393 | } 394 | 395 | /** 396 | * 查找除指定字符以外的最后一次出现的字符位置(从右往左) 397 | * @param t 字符 398 | * @return 位置,-1则不存在 399 | */ 400 | int findr_last_not(const T &t) const { 401 | auto index = -1; 402 | for (auto i = get_length() - 1; i >= 0; --i) { 403 | if ((*this)[i] != t) 404 | index = i; 405 | } 406 | return index; 407 | } 408 | 409 | // ------------------------------------------------- 410 | 411 | /** 412 | * 查找第一次出现的指定字符位置 413 | * @param t 字符 414 | * @param start 起始查找位置 415 | * @return 位置,-1则不存在 416 | */ 417 | int find(const T &t, int start) const { 418 | for (auto i = start; i < get_length(); ++i) { 419 | if ((*this)[i] == t) 420 | return i; 421 | } 422 | return -1; 423 | } 424 | 425 | /** 426 | * 查找最后一次出现的指定字符位置 427 | * @param t 字符 428 | * @param start 起始查找位置 429 | * @return 位置,-1则不存在 430 | */ 431 | int find_last(const T &t, int start) const { 432 | auto index = -1; 433 | for (auto i = start; i < get_length(); ++i) { 434 | if ((*this)[i] == t) 435 | index = i; 436 | } 437 | return index; 438 | } 439 | 440 | /** 441 | * 查找除指定字符以外的第一次出现的字符位置 442 | * @param t 字符 443 | * @param start 起始查找位置 444 | * @return 位置,-1则不存在 445 | */ 446 | int find_not(const T &t, int start) const { 447 | for (auto i = start; i < get_length(); ++i) { 448 | if ((*this)[i] != t) 449 | return i; 450 | } 451 | return -1; 452 | } 453 | 454 | /** 455 | * 查找除指定字符以外的最后一次出现的字符位置 456 | * @param t 字符 457 | * @param start 起始查找位置 458 | * @return 位置,-1则不存在 459 | */ 460 | int find_last_not(const T &t, int start) const { 461 | auto index = -1; 462 | for (auto i = start; i < get_length(); ++i) { 463 | if ((*this)[i] != t) 464 | index = i; 465 | } 466 | return index; 467 | } 468 | 469 | /** 470 | * 查找第一次出现的指定字符位置(从右往左) 471 | * @param t 字符 472 | * @param start 起始查找位置(从右往左数) 473 | * @return 位置,-1则不存在 474 | */ 475 | int findr(const T &t, int start) const { 476 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 477 | if ((*this)[i] == t) 478 | return i; 479 | } 480 | return -1; 481 | } 482 | 483 | /** 484 | * 查找最后一次出现的指定字符位置(从右往左) 485 | * @param t 字符 486 | * @param start 起始查找位置(从右往左数) 487 | * @return 位置,-1则不存在 488 | */ 489 | int findr_last(const T &t, int start) const { 490 | auto index = -1; 491 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 492 | if ((*this)[i] == t) 493 | index = i; 494 | } 495 | return index; 496 | } 497 | 498 | /** 499 | * 查找最后一次出现的指定字符位置(从右往左) 500 | * @param t 字符 501 | * @param start 起始查找位置(从右往左数) 502 | * @return 位置,-1则不存在 503 | */ 504 | int findr_not(const T &t, int start) const { 505 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 506 | if ((*this)[i] == t) 507 | return i; 508 | } 509 | return -1; 510 | } 511 | 512 | /** 513 | * 查找除指定字符以外的最后一次出现的字符位置(从右往左) 514 | * @param t 字符 515 | * @param start 起始查找位置(从右往左数) 516 | * @return 位置,-1则不存在 517 | */ 518 | int findr_last_not(const T &t, int start) const { 519 | auto index = -1; 520 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 521 | if ((*this)[i] != t) 522 | index = i; 523 | } 524 | return index; 525 | } 526 | 527 | // ------------------------------------------------- 528 | }; 529 | 530 | using StringA = String; 531 | using StringW = String; 532 | 533 | #endif 534 | -------------------------------------------------------------------------------- /code/02b/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H 2 | #define _VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef INTSIZEOF 10 | #define INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) 11 | #endif 12 | 13 | /** 14 | * 变长数组 15 | * @tparam T 数据类型 16 | */ 17 | template 18 | class Vector { 19 | private: 20 | T *data; // 数据 21 | int length; // 使用的长度 22 | size_t capacity; // 容量 23 | 24 | static const int INIT_SIZE = 4; // 一开始的大小 25 | static const size_t N_SIZE = INTSIZEOF(T); // 对齐的T结构大小 26 | 27 | private: 28 | /** 29 | * 用t填充初始化后的数组 30 | * @param t 填充值 31 | */ 32 | void fill(const T &t) { 33 | for (int i = 0; i < length; ++i) { 34 | data[i] = t; 35 | } 36 | } 37 | 38 | void print_info() const { 39 | std::cerr << "[VECTOR INFO] capacity: " << capacity << ", length: " << length << std::endl; 40 | } 41 | 42 | void error_index(const char *str, int index) const { 43 | std::cerr << "[VECTOR ERROR] " << str << ": invalid index " << index << std::endl; 44 | print_info(); 45 | assert(!"ERROR"); 46 | exit(-1); 47 | } 48 | 49 | public: 50 | Vector() : data((T *) calloc(INIT_SIZE, N_SIZE)), capacity(INIT_SIZE), length(0) {} 51 | 52 | Vector(int size) : Vector() { resize(size); } 53 | 54 | Vector(int size, const T &t) : Vector(size) { fill(t); } 55 | 56 | Vector(const Vector &v) : data((T *) calloc(v.capacity, N_SIZE)), capacity(v.capacity), length(v.length) { 57 | memcpy(data, v.data, N_SIZE * length); 58 | } 59 | 60 | ~Vector() { remove(0, length); free(data); } 61 | 62 | int get_size() const { return length; } 63 | 64 | size_t get_capacity() const { return capacity; } 65 | 66 | const T *get_data() const { return data; } 67 | 68 | Vector &operator+=(const T &t) { 69 | return (add(t), *this); 70 | } 71 | 72 | Vector &operator=(const Vector &v) { 73 | free(data); 74 | data = ((T *) calloc(v.capacity, N_SIZE)); 75 | capacity = v.capacity; 76 | length = v.length; 77 | memcpy(data, v.data, N_SIZE * length); 78 | return *this; 79 | } 80 | 81 | T &operator[](int index) { 82 | if (index < 0 || index >= length) { 83 | error_index("get", index); 84 | } 85 | return data[index]; 86 | } 87 | 88 | /** 89 | * 更改数组大小 90 | * @param size 新的大小 91 | */ 92 | void resize(int size) { 93 | if (size >= capacity) { // 容量不够 就进行扩张 94 | auto n = size / capacity; // 算几倍 95 | n <<= 1; // 增长一倍 96 | capacity *= n; 97 | auto new_size = N_SIZE * capacity; 98 | auto new_data = (T *) realloc(data, new_size); // 重新申请 99 | if (!new_data) { 100 | new_data = (T *) calloc(capacity, N_SIZE); // realloc失败 重新申请 手动拷贝 101 | assert(new_data); 102 | memcpy(new_data, data, new_size); // 拷贝数据 103 | free(data); // 释放原来的数组 104 | } 105 | data = new_data; 106 | } 107 | length = size; 108 | } 109 | 110 | /** 111 | * 添加数据 112 | * @param t 新增在数组末尾的数据 113 | */ 114 | void add(const T &t) { 115 | data[length] = t; 116 | length++; 117 | resize(length); // 确保容量够用 118 | } 119 | 120 | /** 121 | * 插入数据 122 | * @param index 位置 123 | * @param t 插入到指定位置的数据 124 | */ 125 | void insert(int index, const T &t) { 126 | if (index < 0 || index > length) { 127 | error_index("insert(index)", index); 128 | } 129 | if (index == length) { // 相当于add 130 | add(t); 131 | return; 132 | } 133 | memmove(&data[index + 1], &data[index], N_SIZE * (length - index)); // 移动部分数组,腾出空间 134 | data[index] = t; // 放置数据 135 | length++; 136 | resize(length); // 确保容量够用 137 | } 138 | 139 | /** 140 | * 删除数据 141 | * @param index 要删除的位置 142 | */ 143 | void remove(int index) { 144 | remove(index, 1); 145 | } 146 | 147 | /** 148 | * 删除数据 149 | * @param index 要删除的位置 150 | * @param len 删除的片段长度 151 | */ 152 | void remove(int index, int len) { 153 | if (index < 0 || index >= length) { 154 | error_index("remove(index)", index); 155 | } 156 | if (len <= 0 || index + len > length) { // 判断len合法 157 | error_index("remove(len)", len); 158 | } 159 | for (auto i = 0; i < len; ++i) { 160 | data[index + i].~T(); 161 | } 162 | memmove(&data[index], &data[index + len], N_SIZE * (length - index - len)); // 搬运数组 163 | length -= len; 164 | } 165 | 166 | /** 167 | * 获取数据 168 | * @param index 位置 169 | * @return 数据 170 | */ 171 | const T &get(int index) const { 172 | if (index < 0 || index >= length) { 173 | error_index("get", index); 174 | } 175 | return data[index]; 176 | } 177 | 178 | /** 179 | * 设置数据 180 | * @param index 位置 181 | * @param t 数据 182 | */ 183 | void set(int index, const T &t) const { 184 | if (index < 0 || index >= length) { 185 | error_index("set", index); 186 | } 187 | data[index] = t; 188 | } 189 | 190 | /** 191 | * 清空所有内容 192 | */ 193 | void clear() { 194 | for (auto i = 0; i < length; ++i) { 195 | data[i].~T(); 196 | } 197 | length = 0; 198 | } 199 | }; 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /code/03/regex.h: -------------------------------------------------------------------------------- 1 | #ifndef _REGEX_H 2 | #define _REGEX_H 3 | 4 | #include "string.h" 5 | 6 | /** 7 | * 正则表达式 8 | * @tparam T 字符类型 9 | */ 10 | template 11 | class Regex { 12 | private: 13 | String pat; // 正则表达式字符串 14 | int local{-1}; // 当前字符 15 | bool spec{false}; // 是否关键字 16 | int index{0}; // pat遍历下标 17 | int length; // pat长度 18 | 19 | enum recls_t { 20 | rc_dight = -10, 21 | rc_nondight = -11, 22 | rc_word = -20, 23 | rc_nonword = -21, 24 | rc_space = -30, 25 | rc_nonspace = -31, 26 | rc_end = -1, 27 | }; 28 | 29 | enum nfacls_t { 30 | nc_nil = -1, 31 | nc_start = -2, 32 | nc_end = -3, 33 | }; 34 | 35 | struct nfa_t { 36 | int begin, end, index, reserved; 37 | }; 38 | 39 | Vector nfa; // nfa 40 | 41 | int nfa_start, nfa_end; 42 | 43 | private: 44 | void build_regex() { 45 | start(); 46 | parse(); 47 | } 48 | 49 | void start() { 50 | nfa += nfa_t{nc_nil, 2, nc_start, nc_nil}; 51 | nfa += nfa_t{3, nc_nil, nc_end, nc_nil}; 52 | nfa += nfa_t{0, nc_nil, nc_nil, nc_nil}; // start 53 | nfa += nfa_t{nc_nil, 1, nc_nil, nc_nil}; // end 54 | nfa_start = 2; 55 | nfa_end = 3; 56 | } 57 | 58 | void error(const char *str) const { 59 | std::cerr << "[REGEX ERROR] " << str << std::endl; 60 | assert(!"ERROR"); 61 | exit(-1); 62 | } 63 | 64 | void parse() { 65 | next(); 66 | while (local != rc_end) { 67 | if (spec) { 68 | if (local == '(') { 69 | // match group start 70 | parse(); 71 | } else if (local == ')') { 72 | next(); 73 | // match group end 74 | } else if (local == '?') { 75 | next(); 76 | // match repeat 77 | parse_repeat(0, 1); 78 | } else if (local == '*') { 79 | next(); 80 | // match repeat 81 | parse_repeat(0, -1); 82 | if (spec && local == '?') 83 | next(); 84 | } else if (local == '+') { 85 | next(); 86 | // match repeat 87 | parse_repeat(1, -1); 88 | if (spec && local == '?') 89 | next(); 90 | } else if (local == '{') { 91 | next(); 92 | // match repeat 93 | auto begin = 0, end = -1; 94 | if (!isdigit(local)) error("invalid begin in {begin, end}"); 95 | do 96 | { 97 | begin = begin * 10 + (local - '0'); 98 | next(); 99 | } while (isdigit(local)); 100 | if (local == ',') { 101 | next(); 102 | if (isdigit(local)) { 103 | end = 0; 104 | do 105 | { 106 | end = end * 10 + (local - '0'); 107 | next(); 108 | } while (isdigit(local)); 109 | } 110 | } 111 | if (spec && local == '}') { 112 | next(); 113 | parse_repeat(begin, end); 114 | } else { 115 | error("invalid number in {begin, end}"); 116 | } 117 | parse_repeat(begin, end); 118 | if (spec && local == '?') 119 | next(); 120 | } else if (local == '[') { 121 | next(); 122 | // match range 123 | bool inv = false; 124 | if (spec && local == '^') { 125 | inv = true; 126 | next(); 127 | } 128 | while (!(spec && local == ']')) 129 | { 130 | next(); 131 | }; 132 | next(); 133 | } else if (local == '|') { 134 | next(); 135 | } else { 136 | error("invalid special character"); 137 | } 138 | } else { 139 | next(); 140 | // match char 141 | } 142 | } 143 | } 144 | 145 | void parse_repeat(int begin, int end) { 146 | 147 | } 148 | 149 | void next() { 150 | if (index >= length) { 151 | local = rc_end; 152 | return; 153 | } 154 | local = (int) pat[index++]; 155 | if (local == '\\') { 156 | spec = false; 157 | if (index < length) { 158 | local = pat[index++]; 159 | switch (local) { 160 | case 'r': 161 | local = '\r'; 162 | break; 163 | case 'n': 164 | local = '\n'; 165 | break; 166 | case 'b': 167 | local = '\b'; 168 | break; 169 | case 'v': 170 | local = '\v'; 171 | break; 172 | case 'f': 173 | local = '\f'; 174 | break; 175 | case '\\': 176 | local = '\\'; 177 | break; 178 | case 'd': 179 | local = rc_dight; 180 | break; 181 | case 'w': 182 | local = rc_word; 183 | break; 184 | case 's': 185 | local = rc_space; 186 | break; 187 | case 'D': 188 | local = rc_nondight; 189 | break; 190 | case 'W': 191 | local = rc_nonword; 192 | break; 193 | case 'S': 194 | local = rc_nonspace; 195 | break; 196 | default: 197 | break; 198 | } 199 | } 200 | } else { 201 | switch (local) { 202 | case '|': 203 | case '.': 204 | case '*': 205 | case '+': 206 | case '?': 207 | case '(': 208 | case ')': 209 | case '[': 210 | case ']': 211 | case '{': 212 | case '}': 213 | spec = true; 214 | break; 215 | default: 216 | spec = false; 217 | break; 218 | } 219 | } 220 | } 221 | 222 | public: 223 | explicit Regex(const String &str) : pat(str), length(str.get_length()) { build_regex(); } 224 | }; 225 | 226 | #endif 227 | -------------------------------------------------------------------------------- /code/03/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "vector.h" 5 | 6 | /** 7 | * 字符串 8 | * @tparam T 字符类型 9 | */ 10 | template 11 | class String { 12 | private: 13 | Vector data; // 字符数组 14 | 15 | static const int CHAR_SIZE = sizeof(T); // 字符大小 16 | 17 | private: 18 | /** 19 | * 从字符串指针中创建对象 20 | * @param str 字符串指针 21 | */ 22 | void copy(const T *str) { 23 | T c; 24 | while (c = *str++) { 25 | data.add(c); 26 | } 27 | } 28 | 29 | /** 30 | * 设置最后一个字符为零 31 | */ 32 | void set_end() const { 33 | const_cast(get_data())[get_length()] = '\0'; // 由于边界检查,只好出此下策 :( 34 | } 35 | 36 | public: 37 | String() {} 38 | 39 | String(const T *str) { copy(str); } 40 | 41 | String(int size, const T &t) : data(size, t) {} 42 | 43 | String(const String &s) : data(s.data) {} 44 | 45 | int get_length() const { return data.get_size(); } 46 | 47 | int is_empty() const { return data.get_size() == 0; } 48 | 49 | const T *get_data() const { 50 | return data.get_data(); 51 | } 52 | 53 | String &operator+(const T &t) { // string + char 54 | return (data.add(t), *this); 55 | } 56 | 57 | friend String &operator+(const T &t, const String &s) { // char + string 58 | return s + t; 59 | } 60 | 61 | String &operator+=(const T &t) { // string += char 62 | return *this + t; 63 | } 64 | 65 | String &operator=(const String &s) { // string = string2 66 | return (data = s.data, *this); 67 | } 68 | 69 | String &operator=(const T *str) { // string = "abc" 70 | return (copy(str), *this); 71 | } 72 | 73 | bool operator==(const String &s) { 74 | return compare(s) == 0; 75 | } 76 | 77 | bool operator!=(const String &s) { 78 | return compare(s) != 0; 79 | } 80 | 81 | bool operator>(const String &s) { 82 | return compare(s) > 0; 83 | } 84 | 85 | bool operator<(const String &s) { 86 | return compare(s) < 0; 87 | } 88 | 89 | bool operator>=(const String &s) { 90 | return compare(s) >= 0; 91 | } 92 | 93 | bool operator<=(const String &s) { 94 | return compare(s) <= 0; 95 | } 96 | 97 | operator const T *() const { // 便于格式转换 98 | return get_data(); 99 | } 100 | 101 | T &operator[](int index) { // 允许修改 102 | return data[index]; 103 | } 104 | 105 | /** 106 | * 字符串比较 107 | * @param s 要比较的字符串 108 | * @return 相等为0,小于为-1,大于为1 109 | */ 110 | int compare(const String &s) const { 111 | auto a_len = get_length(); 112 | auto b_len = s.get_length(); 113 | auto min_len = a_len > b_len ? b_len : a_len; 114 | for (auto i = 0; i < min_len; ++i) { 115 | if ((*this)[i] < s[i]) { 116 | return -1; 117 | } else if ((*this)[i] > s[i]) { 118 | return 1; 119 | } 120 | } 121 | if (a_len < b_len) { 122 | return -1; 123 | } else if (a_len > b_len) { 124 | return 1; 125 | } 126 | return 0; 127 | } 128 | 129 | /** 130 | * 生成子串 131 | * @param start 起始位置 132 | * @param length 子串长度 133 | * @return 子串 134 | */ 135 | String substr(int start, int length = -1) const { 136 | /* (GCC) 注意,这里编译器进行NRVO优化 137 | * 如果我这么做: 138 | * auto a = String("hello world"); 139 | * auto b = a.substr(4,4); 140 | * 则自始至终,只有a和b分别调用一次默认构造函数 141 | * 不会调用拷贝构造以及赋值构造 142 | * 因此一般情况下没有必要涉及移动语义 143 | */ 144 | String s; 145 | if (length == -1) length = get_length(); 146 | auto end = (start + length) > get_length() ? get_length() : (start + length); 147 | for (auto i = start; i < end; ++i) { 148 | s += (*this)[i]; 149 | } 150 | s += '\0'; 151 | s.remove(s.get_length() - 1); // 末尾置零 152 | return s; // 优化掉了,不会调用构造函数 153 | } 154 | 155 | /** 156 | * 生成从左开始的子串 157 | * @param length 子串长度 158 | * @return 子串 159 | */ 160 | String left(int length) const { 161 | return substr(0, length); 162 | } 163 | 164 | /** 165 | * 生成中间的子串 166 | * @param start 起始位置 167 | * @param end 结束位置 168 | * @return 子串 169 | */ 170 | String mid(int start, int end) const { 171 | return substr(start, end - start + 1); 172 | } 173 | 174 | /** 175 | * 生成从右开始的子串 176 | * @param length 子串长度 177 | * @return 子串 178 | */ 179 | String right(int length) const { 180 | return substr(get_length() - length); 181 | } 182 | 183 | /** 184 | * 查询字符 185 | * @param index 位置 186 | * @return 指定位置的字符 187 | */ 188 | const T &get(int index) const { // 禁止修改 189 | return data.get(index); 190 | } 191 | 192 | /** 193 | * 添加字符 194 | * @param t 字符 195 | */ 196 | void add(const T &t) { 197 | (*this) += t; 198 | set_end(); 199 | } 200 | 201 | /** 202 | * 插入字符 203 | * @param index 位置 204 | * @param t 插入到指定位置的字符 205 | */ 206 | void insert(int index, const T &t) { 207 | data.insert(index, t); 208 | } 209 | 210 | /** 211 | * 删除指定位置的字符 212 | * @param index 要删除的位置 213 | */ 214 | void remove(int index) { 215 | data.remove(index); 216 | set_end(); 217 | } 218 | 219 | /** 220 | * 删除指定位置的连续字符 221 | * @param index 要删除的位置 222 | * @param len 删除的字符串长度 223 | */ 224 | void remove(int index, int len) { 225 | data.remove(index, len); 226 | set_end(); 227 | } 228 | 229 | /** 230 | * 清除指定字符 231 | * @param t 字符 232 | */ 233 | void erase(const T &t) { 234 | for (auto i = get_length() - 1; i >= 0; --i) { 235 | if ((*this)[i] == t) { 236 | remove(i); 237 | } 238 | } 239 | } 240 | 241 | /** 242 | * 清空字符串 243 | */ 244 | void clear() { 245 | if (!is_empty()) { 246 | data.clear(); 247 | set_end(); 248 | } 249 | } 250 | 251 | /** 252 | * 事先预留一定空间来存放字符数组 253 | * @param size 字符数组大小 254 | */ 255 | void reserve(int size) { 256 | data.resize(size); 257 | } 258 | 259 | /** 260 | * 字符串翻转 261 | * @return 翻转后的字符串 262 | */ 263 | String reverse() { 264 | auto s(*this); 265 | auto length = get_length(); 266 | for (int i = 0; i < (length + 1) / 2; ++i) { 267 | s[i] = s[length - i - 1]; 268 | } 269 | return s; 270 | } 271 | 272 | /** 273 | * 字符串分割 274 | * @param t 分隔符 275 | * @return 字符串数组 276 | */ 277 | Vector> split(const T &t) const { 278 | Vector> v; 279 | auto start = 0; 280 | auto length = 0; 281 | for (auto i = 0; i < get_length(); ++i) { 282 | if ((*this)[i] == t) { 283 | if (length > 0) { 284 | v += substr(start, length); 285 | length = 0; 286 | } 287 | start = i + 1; 288 | } else { 289 | length++; 290 | } 291 | } 292 | if (length > 0) 293 | v += substr(start, length); 294 | return v; 295 | } 296 | 297 | // ------------------------------------------------- 298 | 299 | // PS: 更加高级的find和replace用正则表达式实现 300 | 301 | /** 302 | * 查找第一次出现的指定字符位置 303 | * @param t 字符 304 | * @return 位置,-1则不存在 305 | */ 306 | int find(const T &t) const { 307 | for (auto i = 0; i < get_length(); ++i) { 308 | if ((*this)[i] == t) 309 | return i; 310 | } 311 | return -1; 312 | } 313 | 314 | /** 315 | * 查找最后一次出现的指定字符位置 316 | * @param t 字符 317 | * @return 位置,-1则不存在 318 | */ 319 | int find_last(const T &t) const { 320 | auto index = -1; 321 | for (auto i = 0; i < get_length(); ++i) { 322 | if ((*this)[i] == t) 323 | index = i; 324 | } 325 | return index; 326 | } 327 | 328 | /** 329 | * 查找除指定字符以外的第一次出现的字符位置 330 | * @param t 字符 331 | * @return 位置,-1则不存在 332 | */ 333 | int find_not(const T &t) const { 334 | for (auto i = 0; i < get_length(); ++i) { 335 | if ((*this)[i] != t) 336 | return i; 337 | } 338 | return -1; 339 | } 340 | 341 | /** 342 | * 查找除指定字符以外的最后一次出现的字符位置 343 | * @param t 字符 344 | * @return 位置,-1则不存在 345 | */ 346 | int find_last_not(const T &t) const { 347 | auto index = -1; 348 | for (auto i = 0; i < get_length(); ++i) { 349 | if ((*this)[i] != t) 350 | index = i; 351 | } 352 | return index; 353 | } 354 | 355 | /** 356 | * 查找第一次出现的指定字符位置(从右往左) 357 | * @param t 字符 358 | * @return 位置,-1则不存在 359 | */ 360 | int findr(const T &t) const { 361 | for (auto i = get_length() - 1; i >= 0; --i) { 362 | if ((*this)[i] == t) 363 | return i; 364 | } 365 | return -1; 366 | } 367 | 368 | /** 369 | * 查找最后一次出现的指定字符位置(从右往左) 370 | * @param t 字符 371 | * @return 位置,-1则不存在 372 | */ 373 | int findr_last(const T &t) const { 374 | auto index = -1; 375 | for (auto i = get_length() - 1; i >= 0; --i) { 376 | if ((*this)[i] == t) 377 | index = i; 378 | } 379 | return index; 380 | } 381 | 382 | /** 383 | * 查找最后一次出现的指定字符位置(从右往左) 384 | * @param t 字符 385 | * @return 位置,-1则不存在 386 | */ 387 | int findr_not(const T &t) const { 388 | for (auto i = get_length() - 1; i >= 0; --i) { 389 | if ((*this)[i] == t) 390 | return i; 391 | } 392 | return -1; 393 | } 394 | 395 | /** 396 | * 查找除指定字符以外的最后一次出现的字符位置(从右往左) 397 | * @param t 字符 398 | * @return 位置,-1则不存在 399 | */ 400 | int findr_last_not(const T &t) const { 401 | auto index = -1; 402 | for (auto i = get_length() - 1; i >= 0; --i) { 403 | if ((*this)[i] != t) 404 | index = i; 405 | } 406 | return index; 407 | } 408 | 409 | // ------------------------------------------------- 410 | 411 | /** 412 | * 查找第一次出现的指定字符位置 413 | * @param t 字符 414 | * @param start 起始查找位置 415 | * @return 位置,-1则不存在 416 | */ 417 | int find(const T &t, int start) const { 418 | for (auto i = start; i < get_length(); ++i) { 419 | if ((*this)[i] == t) 420 | return i; 421 | } 422 | return -1; 423 | } 424 | 425 | /** 426 | * 查找最后一次出现的指定字符位置 427 | * @param t 字符 428 | * @param start 起始查找位置 429 | * @return 位置,-1则不存在 430 | */ 431 | int find_last(const T &t, int start) const { 432 | auto index = -1; 433 | for (auto i = start; i < get_length(); ++i) { 434 | if ((*this)[i] == t) 435 | index = i; 436 | } 437 | return index; 438 | } 439 | 440 | /** 441 | * 查找除指定字符以外的第一次出现的字符位置 442 | * @param t 字符 443 | * @param start 起始查找位置 444 | * @return 位置,-1则不存在 445 | */ 446 | int find_not(const T &t, int start) const { 447 | for (auto i = start; i < get_length(); ++i) { 448 | if ((*this)[i] != t) 449 | return i; 450 | } 451 | return -1; 452 | } 453 | 454 | /** 455 | * 查找除指定字符以外的最后一次出现的字符位置 456 | * @param t 字符 457 | * @param start 起始查找位置 458 | * @return 位置,-1则不存在 459 | */ 460 | int find_last_not(const T &t, int start) const { 461 | auto index = -1; 462 | for (auto i = start; i < get_length(); ++i) { 463 | if ((*this)[i] != t) 464 | index = i; 465 | } 466 | return index; 467 | } 468 | 469 | /** 470 | * 查找第一次出现的指定字符位置(从右往左) 471 | * @param t 字符 472 | * @param start 起始查找位置(从右往左数) 473 | * @return 位置,-1则不存在 474 | */ 475 | int findr(const T &t, int start) const { 476 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 477 | if ((*this)[i] == t) 478 | return i; 479 | } 480 | return -1; 481 | } 482 | 483 | /** 484 | * 查找最后一次出现的指定字符位置(从右往左) 485 | * @param t 字符 486 | * @param start 起始查找位置(从右往左数) 487 | * @return 位置,-1则不存在 488 | */ 489 | int findr_last(const T &t, int start) const { 490 | auto index = -1; 491 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 492 | if ((*this)[i] == t) 493 | index = i; 494 | } 495 | return index; 496 | } 497 | 498 | /** 499 | * 查找最后一次出现的指定字符位置(从右往左) 500 | * @param t 字符 501 | * @param start 起始查找位置(从右往左数) 502 | * @return 位置,-1则不存在 503 | */ 504 | int findr_not(const T &t, int start) const { 505 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 506 | if ((*this)[i] == t) 507 | return i; 508 | } 509 | return -1; 510 | } 511 | 512 | /** 513 | * 查找除指定字符以外的最后一次出现的字符位置(从右往左) 514 | * @param t 字符 515 | * @param start 起始查找位置(从右往左数) 516 | * @return 位置,-1则不存在 517 | */ 518 | int findr_last_not(const T &t, int start) const { 519 | auto index = -1; 520 | for (auto i = get_length() - 1 - start; i >= 0; --i) { 521 | if ((*this)[i] != t) 522 | index = i; 523 | } 524 | return index; 525 | } 526 | 527 | // ------------------------------------------------- 528 | }; 529 | 530 | using StringA = String; 531 | using StringW = String; 532 | 533 | #endif 534 | -------------------------------------------------------------------------------- /code/03/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _VECTOR_H 2 | #define _VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef INTSIZEOF 10 | #define INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)) 11 | #endif 12 | 13 | /** 14 | * 变长数组 15 | * @tparam T 数据类型 16 | */ 17 | template 18 | class Vector { 19 | private: 20 | T *data; // 数据 21 | int length; // 使用的长度 22 | size_t capacity; // 容量 23 | 24 | static const int INIT_SIZE = 4; // 一开始的大小 25 | static const size_t N_SIZE = INTSIZEOF(T); // 对齐的T结构大小 26 | 27 | private: 28 | /** 29 | * 用t填充初始化后的数组 30 | * @param t 填充值 31 | */ 32 | void fill(const T &t) { 33 | for (int i = 0; i < length; ++i) { 34 | data[i] = t; 35 | } 36 | } 37 | 38 | void print_info() const { 39 | std::cerr << "[VECTOR INFO] capacity: " << capacity << ", length: " << length << std::endl; 40 | } 41 | 42 | void error_index(const char *str, int index) const { 43 | std::cerr << "[VECTOR ERROR] " << str << ": invalid index " << index << std::endl; 44 | print_info(); 45 | assert(!"ERROR"); 46 | exit(-1); 47 | } 48 | 49 | public: 50 | Vector() : data((T *) calloc(INIT_SIZE, N_SIZE)), capacity(INIT_SIZE), length(0) {} 51 | 52 | Vector(int size) : Vector() { resize(size); } 53 | 54 | Vector(int size, const T &t) : Vector(size) { fill(t); } 55 | 56 | Vector(const Vector &v) : data((T *) calloc(v.capacity, N_SIZE)), capacity(v.capacity), length(v.length) { 57 | memcpy(data, v.data, N_SIZE * length); 58 | } 59 | 60 | ~Vector() { free(data); } 61 | 62 | int get_size() const { return length; } 63 | 64 | size_t get_capacity() const { return capacity; } 65 | 66 | const T *get_data() const { return data; } 67 | 68 | Vector &operator+=(const T &t) { 69 | return (add(t), *this); 70 | } 71 | 72 | Vector &operator=(const Vector &v) { 73 | free(data); 74 | data = ((T *) calloc(v.capacity, N_SIZE)); 75 | capacity = v.capacity; 76 | length = v.length; 77 | memcpy(data, v.data, N_SIZE * length); 78 | return *this; 79 | } 80 | 81 | T &operator[](int index) { 82 | if (index < 0 || index >= length) { 83 | error_index("get", index); 84 | } 85 | return data[index]; 86 | } 87 | 88 | /** 89 | * 更改数组大小 90 | * @param size 新的大小 91 | */ 92 | void resize(int size) { 93 | if (size >= capacity) { // 容量不够 就进行扩张 94 | auto n = size / capacity; // 算几倍 95 | n <<= 1; // 增长一倍 96 | capacity *= n; 97 | auto new_size = N_SIZE * capacity; 98 | auto new_data = (T *) realloc(data, new_size); // 重新申请 99 | if (!new_data) { 100 | new_data = (T *) calloc(capacity, N_SIZE); // realloc失败 重新申请 手动拷贝 101 | assert(new_data); 102 | memcpy(new_data, data, new_size); // 拷贝数据 103 | free(data); // 释放原来的数组 104 | } 105 | data = new_data; 106 | } 107 | length = size; 108 | } 109 | 110 | /** 111 | * 添加数据 112 | * @param t 新增在数组末尾的数据 113 | */ 114 | void add(const T &t) { 115 | data[length] = t; 116 | length++; 117 | resize(length); // 确保容量够用 118 | } 119 | 120 | /** 121 | * 插入数据 122 | * @param index 位置 123 | * @param t 插入到指定位置的数据 124 | */ 125 | void insert(int index, const T &t) { 126 | if (index < 0 || index > length) { 127 | error_index("insert(index)", index); 128 | } 129 | if (index == length) { // 相当于add 130 | add(t); 131 | return; 132 | } 133 | memmove(&data[index + 1], &data[index], N_SIZE * (length - index)); // 移动部分数组,腾出空间 134 | data[index] = t; // 放置数据 135 | length++; 136 | resize(length); // 确保容量够用 137 | } 138 | 139 | /** 140 | * 删除数据 141 | * @param index 要删除的位置 142 | */ 143 | void remove(int index) { 144 | remove(index, 1); 145 | } 146 | 147 | /** 148 | * 删除数据 149 | * @param index 要删除的位置 150 | * @param len 删除的片段长度 151 | */ 152 | void remove(int index, int len) { 153 | if (index < 0 || index >= length) { 154 | error_index("remove(index)", index); 155 | } 156 | if (len <= 0 || index + len > length) { // 判断len合法 157 | error_index("remove(len)", len); 158 | } 159 | for (auto i = 0; i < len; ++i) { 160 | data[index + i].~T(); 161 | } 162 | memmove(&data[index], &data[index + len], N_SIZE * (length - index - len)); // 搬运数组 163 | length -= len; 164 | } 165 | 166 | /** 167 | * 获取数据 168 | * @param index 位置 169 | * @return 数据 170 | */ 171 | const T &get(int index) const { 172 | if (index < 0 || index >= length) { 173 | error_index("get", index); 174 | } 175 | return data[index]; 176 | } 177 | 178 | /** 179 | * 设置数据 180 | * @param index 位置 181 | * @param t 数据 182 | */ 183 | void set(int index, const T &t) const { 184 | if (index < 0 || index >= length) { 185 | error_index("set", index); 186 | } 187 | data[index] = t; 188 | } 189 | 190 | /** 191 | * 清空所有内容 192 | */ 193 | void clear() { 194 | for (auto i = 0; i < length; ++i) { 195 | data[i].~T(); 196 | } 197 | length = 0; 198 | } 199 | }; 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /cover/cover.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bajdcc/learnstl/8550863e387f4dd640b3dbfced4a18a6108a17d2/cover/cover.pptx -------------------------------------------------------------------------------- /learncpp/25027543: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 【游戏框架系列】开篇 - 知乎专栏 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /learncpp/25184604: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 【游戏框架系列】初见成效 - 知乎专栏 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /learncpp/25189183: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 【源码众读】json11学习计划 - 知乎专栏 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /learncpp/27979309: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 【D3.js】建堆动画 - 知乎专栏 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /learncpp/29589948: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 【CEval系列】简介 - 知乎专栏 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /projects/calc/CEval.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bajdcc/learnstl/8550863e387f4dd640b3dbfced4a18a6108a17d2/projects/calc/CEval.cpp -------------------------------------------------------------------------------- /projects/calc/CEval.dev: -------------------------------------------------------------------------------- 1 | [Project] 2 | FileName=CEval.dev 3 | Name=CEval 4 | Type=1 5 | Ver=2 6 | ObjFiles= 7 | Includes= 8 | Libs= 9 | PrivateResource= 10 | ResourceIncludes= 11 | MakeIncludes= 12 | Compiler= 13 | CppCompiler= 14 | Linker= 15 | IsCpp=1 16 | Icon= 17 | ExeOutput= 18 | ObjectOutput= 19 | LogOutput= 20 | LogOutputEnabled=0 21 | OverrideOutput=0 22 | OverrideOutputName= 23 | HostApplication= 24 | UseCustomMakefile=0 25 | CustomMakefile= 26 | CommandLine= 27 | Folders= 28 | IncludeVersionInfo=0 29 | SupportXPThemes=0 30 | CompilerSet=3 31 | CompilerSettings=0000000100000000000000000 32 | UnitCount=7 33 | 34 | [VersionInfo] 35 | Major=1 36 | Minor=0 37 | Release=0 38 | Build=0 39 | LanguageID=1033 40 | CharsetID=1252 41 | CompanyName= 42 | FileVersion= 43 | FileDescription=Developed using the Dev-C++ IDE 44 | InternalName= 45 | LegalCopyright= 46 | LegalTrademarks= 47 | OriginalFilename= 48 | ProductName= 49 | ProductVersion= 50 | AutoIncBuildNr=0 51 | SyncProduct=1 52 | 53 | [Unit1] 54 | FileName=main.cpp 55 | CompileCpp=1 56 | Folder= 57 | Compile=1 58 | Link=1 59 | Priority=1000 60 | OverrideBuildCmd=0 61 | BuildCmd= 62 | 63 | [Unit2] 64 | FileName=CEval.cpp 65 | CompileCpp=1 66 | Folder= 67 | Compile=1 68 | Link=1 69 | Priority=1000 70 | OverrideBuildCmd=0 71 | BuildCmd= 72 | 73 | [Unit3] 74 | FileName=CEval.h 75 | CompileCpp=1 76 | Folder= 77 | Compile=1 78 | Link=1 79 | Priority=1000 80 | OverrideBuildCmd=0 81 | BuildCmd= 82 | 83 | [Unit4] 84 | FileName=RefStringBase.cpp 85 | CompileCpp=1 86 | Folder= 87 | Compile=1 88 | Link=1 89 | Priority=1000 90 | OverrideBuildCmd=0 91 | BuildCmd= 92 | 93 | [Unit5] 94 | FileName=RefStringBase.h 95 | CompileCpp=1 96 | Folder= 97 | Compile=1 98 | Link=1 99 | Priority=1000 100 | OverrideBuildCmd=0 101 | BuildCmd= 102 | 103 | [Unit6] 104 | FileName=RefStringIterator.cpp 105 | CompileCpp=1 106 | Folder= 107 | Compile=1 108 | Link=1 109 | Priority=1000 110 | OverrideBuildCmd=0 111 | BuildCmd= 112 | 113 | [Unit7] 114 | FileName=RefStringIterator.h 115 | CompileCpp=1 116 | Folder= 117 | Compile=1 118 | Link=1 119 | Priority=1000 120 | OverrideBuildCmd=0 121 | BuildCmd= 122 | 123 | -------------------------------------------------------------------------------- /projects/calc/CEval.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bajdcc/learnstl/8550863e387f4dd640b3dbfced4a18a6108a17d2/projects/calc/CEval.h -------------------------------------------------------------------------------- /projects/calc/CEval.layout: -------------------------------------------------------------------------------- 1 | [Editor_0] 2 | CursorCol=1 3 | CursorRow=1 4 | TopLine=1 5 | LeftChar=1 6 | [Editor_4] 7 | CursorCol=27 8 | CursorRow=13 9 | TopLine=1 10 | LeftChar=1 11 | [Editor_3] 12 | CursorCol=1 13 | CursorRow=1 14 | TopLine=1 15 | LeftChar=1 16 | [Editor_7] 17 | CursorCol=2 18 | CursorRow=12 19 | TopLine=1 20 | LeftChar=1 21 | [Editor_2] 22 | CursorCol=1 23 | CursorRow=1 24 | TopLine=160 25 | LeftChar=1 26 | [Editor_6] 27 | CursorCol=18 28 | CursorRow=3 29 | TopLine=1 30 | LeftChar=1 31 | [Editors] 32 | Order=0,4,3,5,6,0,1,0,0,0,2,0,0 33 | Focused=0 34 | [Editor_1] 35 | CursorCol=1 36 | CursorRow=1 37 | TopLine=1 38 | LeftChar=1 39 | [Editor_5] 40 | CursorCol=2 41 | CursorRow=1 42 | TopLine=1 43 | LeftChar=1 44 | -------------------------------------------------------------------------------- /projects/calc/Makefile.win: -------------------------------------------------------------------------------- 1 | # Project: CEval 2 | # Makefile created by Dev-C++ 5.11 3 | 4 | CPP = g++.exe 5 | CC = gcc.exe 6 | WINDRES = windres.exe 7 | OBJ = main.o CEval.o RefStringBase.o RefStringIterator.o 8 | LINKOBJ = main.o CEval.o RefStringBase.o RefStringIterator.o 9 | LIBS = -L"D:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/lib32" -static-libgcc -m32 10 | INCS = -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/include" -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include" 11 | CXXINCS = -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/include" -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/x86_64-w64-mingw32/include" -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include" -I"D:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++" 12 | BIN = CEval.exe 13 | CXXFLAGS = $(CXXINCS) -m32 -std=c++11 14 | CFLAGS = $(INCS) -m32 -std=c++11 15 | RM = rm.exe -f 16 | 17 | .PHONY: all all-before all-after clean clean-custom 18 | 19 | all: all-before $(BIN) all-after 20 | 21 | clean: clean-custom 22 | ${RM} $(OBJ) $(BIN) 23 | 24 | $(BIN): $(OBJ) 25 | $(CPP) $(LINKOBJ) -o $(BIN) $(LIBS) 26 | 27 | main.o: main.cpp 28 | $(CPP) -c main.cpp -o main.o $(CXXFLAGS) 29 | 30 | CEval.o: CEval.cpp 31 | $(CPP) -c CEval.cpp -o CEval.o $(CXXFLAGS) 32 | 33 | RefStringBase.o: RefStringBase.cpp 34 | $(CPP) -c RefStringBase.cpp -o RefStringBase.o $(CXXFLAGS) 35 | 36 | RefStringIterator.o: RefStringIterator.cpp 37 | $(CPP) -c RefStringIterator.cpp -o RefStringIterator.o $(CXXFLAGS) 38 | -------------------------------------------------------------------------------- /projects/calc/README.md: -------------------------------------------------------------------------------- 1 | # 四则运算器(C++) 2 | 3 | - 参见:https://zhuanlan.zhihu.com/p/29632312 4 | - 参见:https://github.com/bajdcc/CEval 5 | 6 | 本目录下面的文件是方便Dev-Cpp编译的。 -------------------------------------------------------------------------------- /projects/calc/RefStringBase.cpp: -------------------------------------------------------------------------------- 1 | #include "RefStringBase.h" 2 | 3 | 4 | namespace cc_ref_string_base 5 | { 6 | Object::Object() 7 | { 8 | } 9 | 10 | Object::~Object() 11 | { 12 | } 13 | 14 | string Object::toString() 15 | { 16 | return "None"; 17 | } 18 | 19 | cc_exception::cc_exception(string reason): reason(reason) 20 | { 21 | } 22 | 23 | cc_exception::cc_exception(const cc_exception& e) : reason(e.reason) 24 | { 25 | } 26 | 27 | string cc_exception::toString() 28 | { 29 | return reason; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /projects/calc/RefStringBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | namespace cc_ref_string_base 8 | { 9 | class Object 10 | { 11 | public: 12 | Object(); 13 | virtual ~Object(); 14 | 15 | virtual string toString(); 16 | }; 17 | 18 | class cc_exception : public Object 19 | { 20 | private: 21 | string reason; 22 | 23 | public: 24 | explicit cc_exception(string reason); 25 | cc_exception(const cc_exception& e); 26 | 27 | string toString() override; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /projects/calc/RefStringIterator.cpp: -------------------------------------------------------------------------------- 1 | #include "RefStringIterator.h" 2 | 3 | 4 | namespace cc_ref_string_iterator 5 | { 6 | RefStringIteratorDecorator::RefStringIteratorDecorator() 7 | { 8 | } 9 | 10 | shared_ptr RefStringIteratorDecorator::lookAhead() 11 | { 12 | return make_shared(shared_from_this()); 13 | } 14 | 15 | RefString::RefString(string ref): ref(ref), start(0), end(ref.length()) 16 | { 17 | } 18 | 19 | int RefString::getStart() const 20 | { 21 | return start; 22 | } 23 | 24 | void RefString::setStart(int start) 25 | { 26 | this->start = start; 27 | } 28 | 29 | int RefString::getEnd() const 30 | { 31 | return end; 32 | } 33 | 34 | void RefString::setEnd(int end) 35 | { 36 | this->end = end; 37 | } 38 | 39 | void RefString::normalize() 40 | { 41 | if (start > end) 42 | { 43 | int tmp = start; 44 | start = end - 1; 45 | end = tmp + 1; 46 | } 47 | } 48 | 49 | char RefString::charAt(int index) const 50 | { 51 | if (index < length()) 52 | { 53 | return ref[start + index]; 54 | } 55 | return 0; 56 | } 57 | 58 | int RefString::length() const 59 | { 60 | return end - start; 61 | } 62 | 63 | shared_ptr RefString::iterator() 64 | { 65 | return make_shared(shared_from_this()); 66 | } 67 | 68 | string RefString::toString() 69 | { 70 | return ref.substr(start, end - start + 1); 71 | } 72 | 73 | RefStringIterator::RefStringIterator(shared_ptr ref): ref(ref), length(ref->length()) 74 | { 75 | } 76 | 77 | int RefStringIterator::index() 78 | { 79 | return ptr; 80 | } 81 | 82 | char RefStringIterator::current() 83 | { 84 | return ref->charAt(ptr); 85 | } 86 | 87 | char RefStringIterator::ahead() 88 | { 89 | return 0; 90 | } 91 | 92 | bool RefStringIterator::available() 93 | { 94 | return ptr < length; 95 | } 96 | 97 | void RefStringIterator::next() 98 | { 99 | if (ptr < length) 100 | { 101 | ptr++; 102 | } 103 | } 104 | 105 | RefStringIteratorBase::RefStringIteratorBase(shared_ptr iterator): iter(iterator) 106 | { 107 | } 108 | 109 | LookAheadOneIterator::LookAheadOneIterator(shared_ptr iterator): RefStringIteratorBase(iterator) 110 | { 111 | idx = this->iter->index(); 112 | chCurrent = this->iter->current(); 113 | iter->next(); 114 | chNext = this->iter->current(); 115 | } 116 | 117 | int LookAheadOneIterator::index() 118 | { 119 | return idx; 120 | } 121 | 122 | char LookAheadOneIterator::current() 123 | { 124 | return chCurrent; 125 | } 126 | 127 | char LookAheadOneIterator::ahead() 128 | { 129 | return chNext; 130 | } 131 | 132 | void LookAheadOneIterator::next() 133 | { 134 | idx = iter->index(); 135 | chCurrent = chNext; 136 | iter->next(); 137 | chNext = iter->current(); 138 | } 139 | 140 | bool LookAheadOneIterator::available() 141 | { 142 | return chCurrent != 0 || chNext != 0; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /projects/calc/RefStringIterator.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bajdcc/learnstl/8550863e387f4dd640b3dbfced4a18a6108a17d2/projects/calc/RefStringIterator.h -------------------------------------------------------------------------------- /projects/calc/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "RefStringBase.h" 5 | #include "CEval.h" 6 | 7 | #define TEST_PARSER 8 | #define TEST_DOUBLE 9 | #define TEST_OTHER 10 | 11 | using namespace cc_eval; 12 | 13 | int main() 14 | { 15 | try 16 | { 17 | #ifdef TEST_PARSER 18 | { 19 | CEval eval; 20 | assert(eval.eval_output("1") == "1"); 21 | assert(eval.eval_output("1.") == "1"); 22 | assert(eval.eval_output("1 + 2") == "3"); 23 | assert(eval.eval_output("1 -2") == "Error"); 24 | assert(eval.eval_output("1 - 2") == "-1"); 25 | assert(eval.eval_output("1 * -2") == "-2"); 26 | assert(eval.eval_output("5 / 2") == "2"); 27 | assert(eval.eval_output("5 / 0") == "Error"); 28 | assert(eval.eval_output("1 +") == "Error"); 29 | assert(eval.eval_output("e") == "Error"); 30 | assert(eval.eval_output("()") == "Error"); 31 | assert(eval.eval_output("\"") == "Error"); 32 | assert(eval.eval_output("\"aa\"") == "aa"); 33 | assert(eval.eval_output("\"aa\" + 123") == "aa123"); 34 | assert(eval.eval_output("\"aa\" + 123.4") == "aa123.4"); 35 | assert(eval.eval_output("1+ 123.4") == "124.4"); 36 | assert(eval.eval_output("1+ 4* 7") == "29"); 37 | assert(eval.eval_output("1+ 4* 7 -6*0") == "Error"); 38 | assert(eval.eval_output("1+ 4* 7 - 6*0") == "29"); 39 | assert(eval.eval_output("1+ 4* 7 - 6*") == "Error"); 40 | assert(eval.eval_output("1+ 4* 7 * -2 / 2 - -3* -3 *-3") == "0"); 41 | assert(eval.eval_output("25 - 6* 1 + 3") == "22"); 42 | assert(eval.eval_output("(1 + 2)") == "3"); 43 | assert(eval.eval_output("(1)") == "1"); 44 | assert(eval.eval_output("(1 + )") == "Error"); 45 | assert(eval.eval_output("2 * (1 + 2)") == "6"); 46 | assert(eval.eval_output("(1 + 2) * 2") == "6"); 47 | assert(eval.eval_output("(1 + 2) * 2 - (3 - 1)") == "4"); 48 | assert(eval.eval_output("1+ 4* (7 * 1 - 1)") == "25"); 49 | assert(eval.eval_output("1+ 4* (7 * 1 - 1) - 6* (0 + 1) /2 + 3") == "25"); 50 | assert(eval.eval_output("(3 + 6)*(8 - -1)") == "81"); 51 | //TODO: need more test!!! 52 | } 53 | #endif 54 | #ifdef TEST_DOUBLE 55 | { CEvalLexer lexer("123"); assert(lexer.next() == v_int); assert(lexer.getInt() == 123); } 56 | { CEvalLexer lexer("123."); assert(lexer.next() == v_double); assert(lexer.getDouble() == 123.0); } 57 | { CEvalLexer lexer("123.4"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 123.4); } 58 | { CEvalLexer lexer("-123"); assert(lexer.next() == v_int); assert(lexer.getInt() == -123); } 59 | { CEvalLexer lexer("-123."); assert(lexer.next() == v_double); assert(lexer.getDouble() == -123.0); } 60 | { CEvalLexer lexer("-123.4"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -123.4); } 61 | { CEvalLexer lexer("123e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 1230.0); } 62 | { CEvalLexer lexer("123.e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 1230.0); } 63 | { CEvalLexer lexer("123.4e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 1234.0); } 64 | { CEvalLexer lexer("-123e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -1230.0); } 65 | { CEvalLexer lexer("-123.e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -1230.0); } 66 | { CEvalLexer lexer("-123.4e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -1234.0); } 67 | { CEvalLexer lexer("123e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 12.3); } 68 | { CEvalLexer lexer("123.e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 12.3); } 69 | { CEvalLexer lexer("123.4e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 12.34); } 70 | { CEvalLexer lexer("-123e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -12.3); } 71 | { CEvalLexer lexer("-123.e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -12.3); } 72 | { CEvalLexer lexer("-123.4e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -12.34); } 73 | { CEvalLexer lexer("12345678987654321"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 12345678987654321.0); } 74 | { CEvalLexer lexer("-"); assert(lexer.next() == v_oper); } 75 | { CEvalLexer lexer(".1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == .1); } 76 | { CEvalLexer lexer("-.1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == -.1); } 77 | { CEvalLexer lexer(".e1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 0.0); } 78 | { CEvalLexer lexer("-.e-1"); assert(lexer.next() == v_double); assert(lexer.getDouble() == 0.0); } 79 | { CEvalLexer lexer("-123e"); assert(lexer.next() == v_error); } 80 | { CEvalLexer lexer("-123e-"); assert(lexer.next() == v_error); } 81 | #endif 82 | #ifdef TEST_OTHER 83 | { CEvalLexer lexer("+"); assert(lexer.next() == v_oper); assert(lexer.getOper() == op_add); } 84 | { CEvalLexer lexer("_a"); assert(lexer.next() == v_id); assert(lexer.getId() == "_a"); } 85 | { CEvalLexer lexer("\""); assert(lexer.next() == v_error); } 86 | { CEvalLexer lexer("\"\""); assert(lexer.next() == v_string); assert(lexer.getString() == ""); } 87 | { CEvalLexer lexer("\"aaa\""); assert(lexer.next() == v_string); assert(lexer.getString() == "aaa"); } 88 | { CEvalLexer lexer("\"\n\""); assert(lexer.next() == v_string); assert(lexer.getString() == "\n"); } 89 | { CEvalLexer lexer("\"\\n\""); assert(lexer.next() == v_string); assert(lexer.getString() == "\n"); } 90 | { CEvalLexer lexer("\"\\0\""); assert(lexer.next() == v_string); assert(lexer.getString() == ""); } 91 | { CEvalLexer lexer("\"\\x30\\x41\\x61\""); assert(lexer.next() == v_string); assert(lexer.getString() == "0Aa"); } 92 | #endif 93 | } 94 | catch (cc_exception& e) { 95 | cerr << "Error: " << e.toString() << endl; 96 | } 97 | return 0; 98 | } 99 | 100 | -------------------------------------------------------------------------------- /projects/router/Router.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Router.h" 3 | 4 | Router::Router() 5 | { 6 | } 7 | 8 | Router::~Router() 9 | { 10 | } 11 | 12 | int Router::add_name(const std::string& name) 13 | { 14 | assert(names.find(name) == names.end()); 15 | adj.push_back(std::unordered_map{}); 16 | auto id = (int)names.size(); 17 | names[name] = id; 18 | namesList.push_back(name); 19 | return id; 20 | } 21 | 22 | void Router::connect(int from, int to, int cost) 23 | { 24 | assert(from >= 0 && from < (int)adj.size()); 25 | assert(to >= 0 && to < (int)adj.size()); 26 | adj[from][to] = cost; 27 | adj[to][from] = cost; 28 | } 29 | 30 | void Router::connect(const std::string& from, const std::string& to, int cost) 31 | { 32 | adj[get_id_by_name(from)][get_id_by_name(to)] = cost; 33 | adj[get_id_by_name(to)][get_id_by_name(from)] = cost; 34 | } 35 | 36 | bool Router::is_direct(int from, int to) const 37 | { 38 | return adj[from].find(to) != adj[from].end(); 39 | } 40 | 41 | int Router::get_id_by_name(const std::string& name) const 42 | { 43 | auto id = names.find(name); 44 | assert(id != names.end()); 45 | return id->second; 46 | } 47 | 48 | const char* Router::get_name_by_id(int id) const 49 | { 50 | assert(id >= 0 && id < (int)names.size()); 51 | return namesList[id].c_str(); 52 | } 53 | 54 | void Router::run() 55 | { 56 | auto count = (int)names.size(); 57 | recv.clear(); 58 | tasks.clear(); 59 | data.clear(); 60 | delivery.clear(); 61 | msgQueue.clear(); 62 | flags.clear(); 63 | times.clear(); 64 | recv.resize(names.size()); 65 | tasks.resize(names.size()); 66 | data.resize(names.size()); 67 | delivery.resize(names.size()); 68 | flags.resize(names.size(), true); 69 | times.resize(names.size()); 70 | task _task; 71 | _task.type = task_start; 72 | _task.value = nullptr; 73 | running_tasks = count; 74 | for (auto& task : tasks) 75 | { 76 | task.push(_task); 77 | } 78 | for (; running_tasks; ++time) 79 | { 80 | auto iter = msgQueue.begin(); 81 | while (iter != msgQueue.end()) 82 | { 83 | if (--iter->delay < 0) 84 | { 85 | delivery[iter->router].push_back(*iter); 86 | iter = msgQueue.erase(iter); 87 | } 88 | else 89 | { 90 | ++iter; 91 | } 92 | } 93 | for (auto i = 0; i < count; ++i) 94 | { 95 | if (flags[i]) 96 | handle(i); 97 | } 98 | } 99 | } 100 | 101 | void Router::new_task(task_t type, int id, void* value) 102 | { 103 | tasks[id].push(task{ type, value }); 104 | times[id].push_back(time); 105 | } 106 | 107 | void Router::pop_task(int id) 108 | { 109 | tasks[id].pop(); 110 | times[id].pop_back(); 111 | } 112 | 113 | void Router::send_msg(msg_t type, int from, int to, int ttl, unsigned long data) 114 | { 115 | printf("[%04d] Message: type=%d, %s -> %s\n", time, type, get_name_by_id(from), get_name_by_id(to)); 116 | auto router = get_router(from, to); 117 | auto dist = router == -1 ? adj[from][to] : adj[from][router]; 118 | msgQueue.push_back(msg{ type, from, to, from, ttl, dist, time, data }); 119 | } 120 | 121 | void Router::deliver_msg(int id) 122 | { 123 | for (auto& m : delivery[id]) 124 | { 125 | if (m.ttl == 0) 126 | continue; 127 | if (m.to == id) 128 | { 129 | recv[id].push(m); 130 | } 131 | else 132 | { 133 | m.ttl--; 134 | // router works 135 | auto router = get_router(id, m.to); 136 | if (router != -1) 137 | { 138 | m.router = router; 139 | m.delay = adj[router][m.to]; 140 | msgQueue.push_back(m); 141 | printf("[%04d] Transmit: type=%d, router=%s, %s -> %s, time=%d, delay=%d\n", time, m.type, 142 | get_name_by_id(router), get_name_by_id(m.from), get_name_by_id(m.to), m.time, m.delay); 143 | } 144 | else if (is_direct(m.from, m.to)) 145 | { 146 | delivery[m.to].push_back(m); 147 | } 148 | } 149 | } 150 | delivery[id].clear(); 151 | } 152 | 153 | int Router::get_router(int from, int to) 154 | { 155 | auto distance = (task::map_int_long *)data[from][data_router]; 156 | if (distance) 157 | { 158 | auto d = distance->find(to); 159 | if (d != distance->end()) 160 | { 161 | return d->second; 162 | } 163 | } 164 | return -1; 165 | } 166 | 167 | void Router::handle(int id) 168 | { 169 | switch (tasks[id].top().type) 170 | { 171 | case task_start: 172 | handle_start(id); 173 | printf("[%04d] Start: %s\n", time, get_name_by_id(id)); 174 | break; 175 | case task_sleep: 176 | handle_sleep(id); 177 | break; 178 | case task_init: 179 | handle_init(id); 180 | break; 181 | case task_init_resp: 182 | handle_init_resp(id); 183 | break; 184 | case task_init_run: 185 | handle_init_run(id); 186 | break; 187 | case task_init_run_resp: 188 | handle_init_run_resp(id); 189 | break; 190 | case task_running: 191 | handle_running(id); 192 | break; 193 | case task_exit: 194 | handle_exit(id); 195 | default: 196 | break; 197 | } 198 | deliver_msg(id); 199 | } 200 | 201 | void Router::handle_start(int id) 202 | { 203 | auto& current_task = tasks[id].top(); 204 | auto unreq_list = new task::set_int{}; 205 | current_task.type = task_init; 206 | current_task.value = unreq_list; 207 | for (auto& unreq : adj[id]) 208 | unreq_list->insert(unreq.first); 209 | data[id][data_init_dist] = new task::map_int_long{}; 210 | } 211 | 212 | void Router::handle_sleep(int id) 213 | { 214 | auto& current_task = tasks[id].top(); 215 | auto& t = (int&)current_task.value; 216 | if (t-- < 0) 217 | { 218 | pop_task(id); 219 | } 220 | } 221 | 222 | void Router::handle_init(int id) 223 | { 224 | auto& current_task = tasks[id].top(); 225 | auto distance = (task::map_int_long *)data[id][data_init_dist]; 226 | auto unreq_list = (task::set_int *)current_task.value; 227 | if (unreq_list->empty()) 228 | { 229 | delete unreq_list; 230 | current_task.type = task_init_run; 231 | data[id][data_router] = new task::map_int_long; 232 | new_task(task_sleep, id, (void*)100); 233 | return; 234 | } 235 | for (auto& unreq : *unreq_list) 236 | { 237 | send_msg(msg_init_req, id, unreq, ttl, time); 238 | (*distance)[unreq] = time; 239 | } 240 | new_task(task_init_resp, id, (void *)unreq_list); 241 | } 242 | 243 | void Router::handle_init_resp(int id) 244 | { 245 | auto& current_task = tasks[id].top(); 246 | auto unreq_list = (task::set_int *)current_task.value; 247 | if (recv[id].empty()) 248 | { 249 | auto span = time - times[id].back(); 250 | if (span % timed_out == 0) 251 | { 252 | for (auto& unreq : *unreq_list) 253 | send_msg(msg_init_req, id, unreq, ttl, time); 254 | } 255 | return; 256 | } 257 | auto distance = (task::map_int_long *)data[id][data_init_dist]; 258 | auto recv_msg = recv[id].front(); 259 | recv[id].pop(); 260 | switch (recv_msg.type) 261 | { 262 | case msg_init_req: 263 | if (recv_msg.to == id) 264 | send_msg(msg_init_resp, id, recv_msg.from, ttl, time); 265 | break; 266 | case msg_init_resp: 267 | (*distance)[recv_msg.from] = time - (*distance)[recv_msg.from]; 268 | printf("[%04d] Distance: dist=%d, %s -> %s\n", time, (*distance)[recv_msg.from], get_name_by_id(id), get_name_by_id(recv_msg.from)); 269 | unreq_list->erase(recv_msg.from); 270 | if (unreq_list->empty()) 271 | pop_task(id); 272 | break; 273 | default: 274 | break; 275 | } 276 | } 277 | 278 | void Router::handle_init_run(int id) 279 | { 280 | auto& current_task = tasks[id].top(); 281 | auto distance = (task::map_int_long *)data[id][data_init_dist]; 282 | for (auto& dist : *distance) 283 | send_msg(msg_init_router_req, id, dist.first, ttl, (unsigned long)distance); 284 | new_task(task_init_run_resp, id, distance); 285 | } 286 | 287 | void Router::handle_init_run_resp(int id) 288 | { 289 | auto& current_task = tasks[id].top(); 290 | auto distance = (task::map_int_long *)data[id][data_init_dist]; 291 | auto router = (task::map_int_long *)data[id][data_router]; 292 | if (recv[id].empty()) 293 | { 294 | if (time - times[id].front() > 600) 295 | { 296 | printf("---- Routing Table @ %s ----\n", get_name_by_id(id)); 297 | for (auto& d : *distance) 298 | { 299 | if (d.first == id) 300 | continue; 301 | auto r = router->find(d.first); 302 | if (r != router->end()) 303 | printf("%s, jump=%s, dist=%d\n", get_name_by_id(d.first), get_name_by_id(r->second), d.second); 304 | else 305 | printf("%s, DIRECT, dist=%d\n", get_name_by_id(d.first), d.second); 306 | } 307 | printf("---- Routing Table @ %s ----\n", get_name_by_id(id)); 308 | current_task.type = task_running; 309 | times[id].front() = time; 310 | } 311 | return; 312 | } 313 | auto recv_msg = recv[id].front(); 314 | recv[id].pop(); 315 | auto distance2 = (task::map_int_long *)recv_msg.data; 316 | for (auto& dist : *distance2) 317 | { 318 | if (dist.first == id) 319 | continue; 320 | auto d = distance->find(dist.first); 321 | if (d == distance->end()) 322 | { 323 | (*distance)[dist.first] = dist.second; 324 | (*router)[dist.first] = recv_msg.from; 325 | } 326 | else 327 | { 328 | auto& old_dist = (*distance)[dist.first]; 329 | auto new_dist = dist.second + (*distance)[recv_msg.from]; 330 | printf("[%04d] Distance: old=%4d, %s -> %s | new=%4d, %s -> %s -> %s\n", time, 331 | old_dist, get_name_by_id(id), get_name_by_id(dist.first), 332 | new_dist, get_name_by_id(id), get_name_by_id(recv_msg.from), get_name_by_id(dist.first)); 333 | if (new_dist < old_dist) 334 | { 335 | (*router)[dist.first] = recv_msg.from; 336 | old_dist = new_dist; 337 | } 338 | } 339 | } 340 | } 341 | 342 | void Router::handle_running(int id) 343 | { 344 | auto& current_task = tasks[id].top(); 345 | auto span = time - times[id].front(); 346 | if (span > 220) 347 | current_task.type = task_exit; 348 | //printf("[%04d] Running: %s\n", time, get_name_by_id(id)); 349 | if (span < 2) 350 | { 351 | for (size_t i = 0; i < names.size(); ++i) 352 | { 353 | if (i == id) 354 | continue; 355 | send_msg(msg_ping, id, i, ttl, time); 356 | } 357 | } 358 | if (!recv[id].empty()) 359 | { 360 | auto recv_msg = recv[id].front(); 361 | recv[id].pop(); 362 | switch (recv_msg.type) 363 | { 364 | case msg_ping: 365 | printf("[%04d] Received ping: time=%d %s -> %s\n", time, time - (int)recv_msg.data, get_name_by_id(recv_msg.from), get_name_by_id(recv_msg.to)); 366 | break; 367 | default: 368 | break; 369 | } 370 | } 371 | } 372 | 373 | void Router::handle_exit(int id) 374 | { 375 | delete (task::map_int_long *)data[id][data_init_dist]; 376 | flags[id] = false; 377 | running_tasks--; 378 | printf("[%04d] Exit: %s\n", time, get_name_by_id(id)); 379 | } 380 | -------------------------------------------------------------------------------- /projects/router/Router.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROUTER_H 2 | #define _ROUTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class Router 13 | { 14 | private: 15 | enum msg_t 16 | { 17 | msg_init_req = 1, 18 | msg_init_resp, 19 | msg_init_router_req, 20 | msg_ping, 21 | }; 22 | 23 | struct msg 24 | { 25 | msg_t type; 26 | int from, to, router; 27 | int ttl; 28 | int delay; 29 | int time; 30 | unsigned long data; 31 | }; 32 | 33 | enum task_t 34 | { 35 | task_exit = -1, 36 | task_start = 0, 37 | task_sleep, 38 | task_init, 39 | task_init_resp, 40 | task_init_run, 41 | task_init_run_resp, 42 | task_running, 43 | }; 44 | 45 | struct task 46 | { 47 | task_t type; 48 | void* value; 49 | 50 | typedef std::unordered_map map_int_long; 51 | typedef std::unordered_set set_int; 52 | }; 53 | 54 | enum data_t 55 | { 56 | data_init_dist, 57 | data_router, 58 | }; 59 | 60 | std::vector> adj; 61 | std::unordered_map names; 62 | std::vector namesList; 63 | std::vector msgQueue; 64 | std::vector> delivery; 65 | std::vector> recv; 66 | std::vector> tasks; 67 | std::vector> data; 68 | std::vector flags; 69 | std::vector> times; 70 | long time{ 0 }; 71 | int ttl{ 10 }; 72 | int timed_out{ 120 }; 73 | int running_tasks{ 0 }; 74 | 75 | public: 76 | Router(); 77 | ~Router(); 78 | 79 | int add_name(const std::string& name); 80 | void connect(int from, int to, int cost); 81 | void connect(const std::string& from, const std::string& to, int cost); 82 | bool is_direct(int from, int to) const; 83 | int get_id_by_name(const std::string& name) const; 84 | const char* get_name_by_id(int id) const; 85 | void run(); 86 | 87 | private: 88 | void new_task(task_t type, int id, void* value); 89 | void pop_task(int id); 90 | void send_msg(msg_t type, int from, int to, int ttl, unsigned long data); 91 | void deliver_msg(int id); 92 | int get_router(int from, int to); 93 | void handle(int id); 94 | void handle_start(int id); 95 | void handle_sleep(int id); 96 | void handle_init(int id); 97 | void handle_init_resp(int id); 98 | void handle_init_run(int id); 99 | void handle_init_run_resp(int id); 100 | void handle_running(int id); 101 | void handle_exit(int id); 102 | }; 103 | 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /projects/router/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Router.h" 3 | 4 | int main() 5 | { 6 | Router router; 7 | 8 | router.add_name("A"); 9 | router.add_name("B"); 10 | router.add_name("C"); 11 | router.add_name("D"); 12 | router.add_name("E"); 13 | 14 | router.connect("A", "B", 10); 15 | router.connect("B", "D", 50); 16 | router.connect("A", "C", 48); 17 | router.connect("C", "D", 8); 18 | router.connect("B", "C", 5); 19 | router.connect("B", "E", 10); 20 | router.connect("D", "E", 45); 21 | router.connect("A", "E", 5); 22 | 23 | router.run(); 24 | 25 | return 0; 26 | } -------------------------------------------------------------------------------- /script/dns/hack_dns.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import socket 4 | import threading 5 | import time 6 | import dns.resolver 7 | 8 | # pip install dnspython 9 | 10 | class DNSQuery(object): 11 | """ 12 | Used for making fake DNS resolution responses based on received 13 | raw request 14 | Reference(s): 15 | 16 | http://code.activestate.com/recipes/491264-mini-fake-dns-server/ 17 | 18 | 19 | https://code.google.com/p/marlon-tools/source/browse/tools/dnsproxy/dnsproxy.py 20 | 21 | """ 22 | def __init__(self, raw): 23 | self._raw = raw 24 | self._query = "" 25 | type_ = (ord(raw[2]) >> 3) & 15 # Opcode bits 26 | if type_ == 0: # Standard query 27 | i = 12 28 | j = ord(raw[i]) 29 | while j != 0: 30 | self._query += raw[i + 1:i + j + 1] + '.' 31 | i = i + j + 1 32 | j = ord(raw[i]) 33 | def response(self, resolution): 34 | """ 35 | Crafts raw DNS resolution response packet 36 | """ 37 | retVal = "" 38 | if self._query: 39 | retVal += self._raw[:2] # Transaction ID 40 | retVal += "\x85\x80" # Flags (Standard query response, No error) 41 | retVal += self._raw[4:6] + self._raw[4:6] + "\x00\x00\x00\x00" # Questions and Answers Counts 42 | retVal += self._raw[12:(12 + self._raw[12:].find("\x00") + 5)] # Original Domain Name Query 43 | retVal += "\xc0\x0c" # Pointer to domain name 44 | retVal += "\x00\x01" # Type A 45 | retVal += "\x00\x01" # Class IN 46 | retVal += "\x00\x00\x00\x20" # TTL (32 seconds) 47 | retVal += "\x00\x04" # Data length 48 | retVal += "".join(chr(int(_)) for _ in resolution.split('.')) # 4 bytes of IP 49 | return retVal 50 | class DNSServer(object): 51 | def __init__(self): 52 | self.my_resolver = dns.resolver.Resolver() 53 | self.my_resolver.nameservers = ['61.177.7.1'] 54 | self._check_localhost() 55 | self._requests = [] 56 | self._lock = threading.Lock() 57 | try: 58 | self._socket = socket._orig_socket(socket.AF_INET, socket.SOCK_DGRAM) 59 | except AttributeError: 60 | self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 61 | self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 62 | self._socket.bind(("", 53)) 63 | print "dns ok" 64 | self._running = False 65 | self._initialized = False 66 | def _check_localhost(self): 67 | response = "" 68 | try: 69 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 70 | s.connect(("", 53)) 71 | s.send("6509012000010000000000010377777706676f6f676c6503636f6d00000100010000291000000000000000".decode("hex")) # A www.google.com 72 | response = s.recv(512) 73 | except: 74 | pass 75 | finally: 76 | if response and "google" in response: 77 | raise socket.error("another DNS service already running on *:53") 78 | def pop(self, prefix=None, suffix=None): 79 | """ 80 | Returns received DNS resolution request (if any) that has given 81 | prefix/suffix combination (e.g. prefix..suffix.domain) 82 | """ 83 | retVal = None 84 | with self._lock: 85 | for _ in self._requests: 86 | if prefix is None and suffix is None or re.search("%s\..+\.%s" % (prefix, suffix), _, re.I): 87 | retVal = _ 88 | self._requests.remove(_) 89 | break 90 | return retVal 91 | def get_domain_A(self,domain): 92 | try: 93 | results=self.my_resolver.query(domain,'A') 94 | for i in results.response.answer: 95 | for j in i.items: 96 | try: 97 | ip_address = j.address 98 | if re.match('\d+\.+\d+\.+\d+\.+\d', ip_address): 99 | return ip_address 100 | except AttributeError as e: 101 | continue 102 | except Exception as e: 103 | return '127.0.0.1' 104 | 105 | def run(self): 106 | """ 107 | Runs a DNSServer instance as a daemon thread (killed by program exit) 108 | """ 109 | def _(): 110 | reip = re.compile(r"^(?:\w+\.)?((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\.link$") 111 | try: 112 | self._running = True 113 | self._initialized = True 114 | while True: 115 | data, addr = self._socket.recvfrom(1024) 116 | _ = DNSQuery(data) 117 | domain=_._query[:-1] ###### exploit 118 | ip=self.get_domain_A(domain) 119 | aip = reip.findall(domain) 120 | if aip: # a.1.1.1.1.link -> 1.1.1.1 121 | ip=aip[0] 122 | print domain,' -> ',ip 123 | self._socket.sendto(_.response(ip), addr) 124 | with self._lock: 125 | self._requests.append(_._query) 126 | except KeyboardInterrupt: 127 | raise 128 | finally: 129 | self._running = False 130 | thread = threading.Thread(target=_) 131 | thread.daemon = True 132 | thread.start() 133 | if __name__ == "__main__": 134 | server = None 135 | try: 136 | server = DNSServer() 137 | server.run() 138 | while not server._initialized: 139 | time.sleep(0.1) 140 | while server._running: 141 | while True: 142 | _ = server.pop() 143 | if _ is None: 144 | break 145 | else: 146 | domian=_[:-1] #print "[i] %s with A %s" % (domian,server.get_domain_A(domian)) 147 | time.sleep(1) 148 | except socket.error, ex: 149 | if 'Permission' in str(ex): 150 | print "[x] Please run with sudo/Administrator privileges" 151 | else: 152 | raise 153 | except KeyboardInterrupt: 154 | os._exit(0) 155 | finally: 156 | if server: 157 | server._running = False --------------------------------------------------------------------------------