piece table 的C语言简单实现

本文介绍了piece table在文本编辑器中的重要性,并提供了一个简单的C语言实现。piece table由源文本、输入缓存和pieces组成,允许高效地进行撤回、重做操作。文章详细阐述了创建、销毁、添加和删除字符串的函数实现,并提供了实验和源码链接。
摘要由CSDN通过智能技术生成

piece table 的C语言简单实现

piece table的介绍

piece table是文本编辑器领域的一个很重要的数据结构

能实现文本编辑器的数据结构有很多,例如vi编辑器远古版本使用的一整块数组、块状链表、行链表、数组的改进GAP BUFFER等,还有本文要介绍的piece table。

关于文本编辑器的各种实现方式,这篇论文给出了很详细的介绍
https://pan.baidu.com/s/1tNuJ6trAStnr52z1QZDR4A

关于piece table,这篇文章给出了很详细的说明
https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation

这里简要说明什么是piece table
主要参考了这篇文章:
https://zhuanlan.zhihu.com/p/259387658

piece table 由三部分构成:
源文本、输入缓存、pieces

源文本记录源文件的内容,它是一个只读字符串

输入缓存记录每一次输入的内容。它是一个只增字符串(append only)

pieces是piece table的精华
它的作用是指示哪些是应当出现在渲染界面的内容

举个例子,源文件内容为:

hello
01234

最开始的时候pieces记录的内容如下:

type	|start	|len
SOURCE	|0		|5

此时渲染的内容为hello
我们往输入缓存中添加, world

, world
0123456

要使渲染层输出内容为hello, world,需要将pieces记录的内容改为:

type	|start	|len
SOURCE	|0		|5
ADDBUF	|0		|7

此时要删除llo,,需要将pieces记录的内容更改为

type	|start	|len
SOURCE	|0		|2
ADDBUF	|1		|7

此时的输出为he world

pieces就像是手电筒一样,照亮我们需要的字符,如要删除某些字符,只要简单地将它的范围缩小即可。

piece table比起其他数据结构,优越的地方在于它可以迅速实现撤回和重做功能,无需复制粘贴大量数据
使用一个栈来存储每次的操作,只需要对table链表执行对应的操作即可迅速实现撤回与重做功能。

另外,可以使用另一个结构来存储每一行开始的位置等等。不在本文的考虑范围内。

C语言的简单实现

本次主要实现的功能为:在piecetable数据结构中添加一段字符、删除一段字符

涉及到的数据结构操作有:

  1. 可扩容数组
  2. 单链表的搜索、增添、删除、合并操作

设计如下数据结构:

typedef struct buf_t
{
   
	char *data;
	size_t curSize;
	size_t maxSize;
}buf_t;  // 变长缓存
typedef enum
{
   
	SOURCE = 0,
	ADDBUF,
	UNKNOW
}buf_e;
typedef struct table_t
{
   
	buf_e type;
	size_t start;
	size_t len;
	struct table_t *next;
}table_t;  // 单链表结构
typedef struct piecetable_t
{
   
	buf_t addbuf;  // append only
	char *source;  // read only
	table_t *table;  // linked list
}piecetable_t;

将输入缓存设置为可扩容类型的

注意其中的table_t类型,我将其设置为无表头的单向链表
实际上有表头的链表更好写一点

在实际使用中,可以使用红黑数来重写table_t类型的所有操作,将时间复杂度从O(n)提升到O(ln n)

创建与销毁

设计如下函数

// 创建新的piecetable结构
piecetable_t *piecetable_new(char *srcTxt);
// 销毁该piecetable
bool piecetable_free(piecetable_t *pt);

/**
 * 创建新的piecetable类型
 * @param  srcTxt 源文件指针
 */
piecetable_t *piecetable_new(char *srcTxt)
{
   
	piecetable_t *pt = (piecetable_t *)
		malloc(sizeof(piecetable_t));
	if (pt == NULL)
		return NULL;
	pt->source = srcTxt;  // 只读
	pt->table = table_init(srcTxt);  // 无表头的单链表结构
	buf_init(&(pt->addbuf));  // 可扩容的缓存数组
	return pt;
}

/**
 * 销毁piecetable
 * @param  pt 要销毁的对象
 * @return    是否销毁成功
 */
bool piecetable_free(piecetable_t *pt)
{
   
	free(pt->source);
	buf_free(&(pt->addbuf));
	table_free(pt->table);
	free(pt);
	return true;
}

具体函数实现细节请看等一下贴出来的源码

添加一段字符串

设置如下函数来添加字符串

// 往pt的pos处后面插入大小为size的字符串
bool piecetable_ins(
	piecetable_t *pt, size_t pos, char *s, size_t size);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值