学习 LLVM(5) Twine 类

类 Twine 定义为文件 llvm/include/ADT/Twine.h 中。html

参见:http://llvm.org/docs/ProgrammersManual.html#Twineexpress

== 说明 ==
Twine 是一个轻量的数据结构,用于高效率地表达字符串的链接。数据结构

Twine 是一种 rope(串接),它使用二叉树表示一个链接的字符串,结果字符串是二叉树节点由前序遍历拼接而成。只有当须要字符串拼接结果的时候,才进行这种拼接到一个最终的 buffer 中,所以能够避免在多个字符串拼接中产生临时的 string 对象,及避免没必要要的高消耗的内存分配操做。函数

Twine 对象通常在堆栈中分配,这样在语句结束的时候会自动释放。由于这个缘由,通常不保存 Twine 对象,作为参数传递使用较多。指针

== 实现 ==调试

class Twine {
  union Child LHS, RHS;  // 二叉树的左、右节点。
  char/*enum NodeKind*/ LHSKind, RHSKind;  // 左右节点的类型。
  Twine(...)  // 很是多种形态的构造 *注1
  concat()    // 拼接(Twine = Twine + Twine)
  str() // 进行实际拼接,并返回为 std::string
  toVector() // 拼接并转换为 vector<char>
  toStringRef(),toNullTerminatedStringRef() // 灵巧转换为 StringRef
  print(),dump() // 输出、调试 Twine。
}
// 一些能够构造为 Twine 的操做符 '+' 的重载,如 operator+(StringRef&, char*) 等。

 

* 注1:构造 Twine(const long long &Val) 由于实际要保存 Val 的指针,所以 Val 这里使用了引用。调用者须要本身保证 Val 的内存合法。code

* enum NodeKine 声明了 Twine 左右节点可能的全部类型,主要有:
** NullKind -- 空字符串,任何串与之拼接结果都是 Null(应该是至关于 null)
** EmptyKind -- 空字符串(至关于 "")
** TwineKind -- 节点是另外一个 Twine 的指针。
** CStringKind -- 节点是 const char *
** StdStringKind -- 节点是 std::string *
** StringRefKind -- 节点是 StringRef *
** CharKind -- 节点是一个字符。
** DecUIKind 等多种数字类型,有符号的、无符号的,32,64位的。
** UHexKind -- 输出 16进制格式的数字。htm

* union Child 对应 enum NodeKind 为每一种节点类型定义了保存何种数据。sizeof(Child) == 4,当数据能容纳在 4 字节内的直接保存,不然保存的是指针(如 std::string*)。对象

== 例子 ==递归

StringRef sr1 = StringRef("world", 5);
std::string s1 = "LLVM!";
Twine t("Hello "); // 构造新的一个 Twine 从 const char *
Twine t2 = t.concat(sr1);   // t2 = "Hello world"
Twine t3 = t2 + " from ";   // t3 = "Hello world from "
Twine t4 = t3.concat(s1);   // t4 = "Hello world from LLVM!"
std::string s2 = t4.str();  // 获得 "Hello world from LLVM!"
Twine t5 = t4 + " And 你还能拼接一个数字: " + Twine(123);

 

== 实现机理和问题 ==
* Twine 要解决的问题是字符串拼接。在程序中,有不少须要临时拼接一个字符串,提供给别的函数作参数使用。
**  首先,拼接出来的字符串参数可能并不使用,则延迟拼接会减小空间分配的消耗。
**  次之,若是是屡次拼接,如例子中所示,Twine 使用二叉树保存拼接表达式,也即模板表达式(expression),在最后真正须要结果(.str())的时候才进行实际的字符串拼接,这样能够大量节省分配、释放内存所需的昂贵操做。

* 我看如今 Twine.str() 方法中使用 SmallString<256> 做为拼接字符串使用的临时空间,并使用递归调用分别遍历左右节点产生拼接结果。也许还能够之后用更好的方法来进行实际合并? * 节点可能保存的是 std::string, StringRef, long long 的指针,所以指针指向的数据要在 Twine 使用周期内确保生存。若是不当心使用,则会致使不可预知的结果。

相关文章
相关标签/搜索