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

相關文章
相關標籤/搜索