行结构(6/8字节) 线段结构(32字节) +--------+ +--------+ |NNNNNNNN| |nnnnnnnn| |NNNNNNNN| |nnnnnnnn| |PPPPPPPP| |pppppppp| |PPPPPPPP| |pppppppp| |bbbbbbbb| |LLLLLLLL| |bbbbbbbb| |LLLLLLLL| |........| |xxxxxxxx| |........| :25 more : +--------+ : x lines: +--------+其中:
x
)指向线段池。N
是下一行的块号(空表示这是文件中的最后一行)。P
是前一行的块号(空表示这是文件中的第一行)。b
是该行第一个线段的块号(空表示该行为空)。.
是保留填充(将结构推出到8个字节)。n
是下一行线段的块号(空表示这是该行中的最后一个线段)。p
是前一个线段的块号(空表示这是该行中的第一个线段)。L
是该线段所在行块的块号。x
是该行线段中的26个字符。线结构被填充的原因是为了加快块号转换为实际内存位置的速度(在那种特定的架构中,左移3位比乘以6要快得多,并且额外使用的内存仅为128K,与总存储相比很小),尽管我们为那些更关心内存的人提供了更慢的版本。
我们还有一个包含100个16位值的数组,大约包含该百分比的线段(以便我们可以快速转到特定行),并且在每个池中维护自由指针的两个指针(这是一个非常简单的单向列表,其中结构中的N
或n
表示下一个空闲块,并且空闲块从这些列表的前面分配和放回)。
没有必要保留每个线段中的字符计数,因为文件中不允许出现0字节。每个线段允许在末尾拥有被完全忽略的0字节。每当修改时,就会压缩行(即合并线段)。这使得块使用率低(无需频繁和冗长的垃圾回收),并且极大地加快了搜索和替换操作。
使用这些结构允许非常快速的编辑、插入、删除、搜索和导航文本,这是您在简单文本编辑器中可能遇到的大多数性能问题所在。
选择的使用(我们没有实现这一点,因为它是一个使用vi-like命令的文本模式编辑器,例如3d
删除3行或6x
删除6个字符)可以通过具有{line#/block,char-pos}
元组来标记文本中的位置,并使用其中两个元组来表示选择范围。
有一篇关于Piece Chains的优秀文章,作者是HexEdit的James Brown。
简而言之:Piece chains允许您记录对文本所做的更改。加载后,您将拥有一个跨越整个文本的piece chain。现在你在中间插入。
与其分配新缓冲区,复制文本等,不如创建两个新的pieces并修改现有的一个:现有的一个现在包含插入点之前的文本(即您只需更改piece的长度),然后有一个包含新文本的piece,再加上一个包含插入点之后所有文本的新piece。原始文本保持不变。
对于撤消/重做,您只需记住添加/删除/更改的pieces。
使用piece chains时最复杂的领域是可见文本中的偏移量与内存结构之间不再具有1:1映射。您可以搜索chain,也可以维护某种二叉树结构。