類 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 使用週期內確保生存。若是不當心使用,則會致使不可預知的結果。