StringTableBuilder.cpp revision 296417
1//===-- StringTableBuilder.cpp - String table building utility ------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/MC/StringTableBuilder.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Support/COFF.h"
13#include "llvm/Support/Endian.h"
14
15#include <vector>
16
17using namespace llvm;
18
19StringTableBuilder::StringTableBuilder(Kind K) : K(K) {}
20
21typedef std::pair<StringRef, size_t> StringPair;
22
23// Returns the character at Pos from end of a string.
24static int charTailAt(StringPair *P, size_t Pos) {
25  StringRef S = P->first;
26  if (Pos >= S.size())
27    return -1;
28  return (unsigned char)S[S.size() - Pos - 1];
29}
30
31// Three-way radix quicksort. This is much faster than std::sort with strcmp
32// because it does not compare characters that we already know the same.
33static void multikey_qsort(StringPair **Begin, StringPair **End, int Pos) {
34tailcall:
35  if (End - Begin <= 1)
36    return;
37
38  // Partition items. Items in [Begin, P) are greater than the pivot,
39  // [P, Q) are the same as the pivot, and [Q, End) are less than the pivot.
40  int Pivot = charTailAt(*Begin, Pos);
41  StringPair **P = Begin;
42  StringPair **Q = End;
43  for (StringPair **R = Begin + 1; R < Q;) {
44    int C = charTailAt(*R, Pos);
45    if (C > Pivot)
46      std::swap(*P++, *R++);
47    else if (C < Pivot)
48      std::swap(*--Q, *R);
49    else
50      R++;
51  }
52
53  multikey_qsort(Begin, P, Pos);
54  multikey_qsort(Q, End, Pos);
55  if (Pivot != -1) {
56    // qsort(P, Q, Pos + 1), but with tail call optimization.
57    Begin = P;
58    End = Q;
59    ++Pos;
60    goto tailcall;
61  }
62}
63
64void StringTableBuilder::finalize() {
65  std::vector<std::pair<StringRef, size_t> *> Strings;
66  Strings.reserve(StringIndexMap.size());
67  for (std::pair<StringRef, size_t> &P : StringIndexMap)
68    Strings.push_back(&P);
69
70  if (!Strings.empty())
71    multikey_qsort(&Strings[0], &Strings[0] + Strings.size(), 0);
72
73  switch (K) {
74  case RAW:
75    break;
76  case ELF:
77  case MachO:
78    // Start the table with a NUL byte.
79    StringTable += '\x00';
80    break;
81  case WinCOFF:
82    // Make room to write the table size later.
83    StringTable.append(4, '\x00');
84    break;
85  }
86
87  StringRef Previous;
88  for (std::pair<StringRef, size_t> *P : Strings) {
89    StringRef S = P->first;
90    if (K == WinCOFF)
91      assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
92
93    if (Previous.endswith(S)) {
94      P->second = StringTable.size() - S.size() - (K != RAW);
95      continue;
96    }
97
98    P->second = StringTable.size();
99    StringTable += S;
100    if (K != RAW)
101      StringTable += '\x00';
102    Previous = S;
103  }
104
105  switch (K) {
106  case RAW:
107  case ELF:
108    break;
109  case MachO:
110    // Pad to multiple of 4.
111    while (StringTable.size() % 4)
112      StringTable += '\x00';
113    break;
114  case WinCOFF:
115    // Write the table size in the first word.
116    assert(StringTable.size() <= std::numeric_limits<uint32_t>::max());
117    uint32_t Size = static_cast<uint32_t>(StringTable.size());
118    support::endian::write<uint32_t, support::little, support::unaligned>(
119        StringTable.data(), Size);
120    break;
121  }
122
123  Size = StringTable.size();
124}
125
126void StringTableBuilder::clear() {
127  StringTable.clear();
128  StringIndexMap.clear();
129}
130
131size_t StringTableBuilder::getOffset(StringRef S) const {
132  assert(isFinalized());
133  auto I = StringIndexMap.find(S);
134  assert(I != StringIndexMap.end() && "String is not in table!");
135  return I->second;
136}
137
138size_t StringTableBuilder::add(StringRef S) {
139  assert(!isFinalized());
140  auto P = StringIndexMap.insert(std::make_pair(S, Size));
141  if (P.second)
142    Size += S.size() + (K != RAW);
143  return P.first->second;
144}
145