类 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 使用周期内确保生存。若是不当心使用,则会致使不可预知的结果。