6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
//
9
- // SequenceToOffsetTable can be used to emit a number of null-terminated
10
- // sequences as one big array. Use the same memory when a sequence is a suffix
11
- // of another.
9
+ // SequenceToOffsetTable can be used to emit a number of sequences as one big
10
+ // array. Uses the same memory when a sequence is a suffix of another.
12
11
//
13
12
// ===----------------------------------------------------------------------===//
14
13
@@ -65,21 +64,28 @@ class SequenceToOffsetTable {
65
64
// Sequences added so far, with suffixes removed.
66
65
SeqMap Seqs;
67
66
67
+ // Terminator element to be appended to each added sequence.
68
+ std::optional<ElemT> Terminator;
69
+
70
+ // True if `layout` method was called.
71
+ bool IsLaidOut = false ;
72
+
68
73
// Entries in the final table, or 0 before layout was called.
69
- unsigned Entries;
74
+ unsigned Entries = 0 ;
70
75
71
76
// isSuffix - Returns true if A is a suffix of B.
72
77
static bool isSuffix (const SeqT &A, const SeqT &B) {
73
78
return A.size () <= B.size () && std::equal (A.rbegin (), A.rend (), B.rbegin ());
74
79
}
75
80
76
81
public:
77
- SequenceToOffsetTable () : Entries(0 ) {}
82
+ explicit SequenceToOffsetTable (std::optional<ElemT> Terminator = ElemT())
83
+ : Terminator(Terminator) {}
78
84
79
85
// / add - Add a sequence to the table.
80
86
// / This must be called before layout().
81
87
void add (const SeqT &Seq) {
82
- assert (Entries == 0 && " Cannot call add() after layout()" );
88
+ assert (!IsLaidOut && " Cannot call add() after layout()" );
83
89
typename SeqMap::iterator I = Seqs.lower_bound (Seq);
84
90
85
91
// If SeqMap contains a sequence that has Seq as a suffix, I will be
@@ -97,25 +103,27 @@ class SequenceToOffsetTable {
97
103
bool empty () const { return Seqs.empty (); }
98
104
99
105
unsigned size () const {
100
- assert (( empty () || Entries) && " Call layout() before size()" );
106
+ assert (IsLaidOut && " Call layout() before size()" );
101
107
return Entries;
102
108
}
103
109
104
110
// / layout - Computes the final table layout.
105
111
void layout () {
106
- assert (Entries == 0 && " Can only call layout() once" );
112
+ assert (!IsLaidOut && " Can only call layout() once" );
113
+ IsLaidOut = true ;
114
+
107
115
// Lay out the table in Seqs iteration order.
108
116
for (typename SeqMap::iterator I = Seqs.begin (), E = Seqs.end (); I != E;
109
117
++I) {
110
118
I->second = Entries;
111
119
// Include space for a terminator.
112
- Entries += I->first .size () + 1 ;
120
+ Entries += I->first .size () + Terminator. has_value () ;
113
121
}
114
122
}
115
123
116
124
// / get - Returns the offset of Seq in the final table.
117
125
unsigned get (const SeqT &Seq) const {
118
- assert (Entries && " Call layout() before get()" );
126
+ assert (IsLaidOut && " Call layout() before get()" );
119
127
typename SeqMap::const_iterator I = Seqs.lower_bound (Seq);
120
128
assert (I != Seqs.end () && isSuffix (Seq, I->first ) &&
121
129
" get() called with sequence that wasn't added first" );
@@ -127,10 +135,10 @@ class SequenceToOffsetTable {
127
135
// / `\0`. Falls back to emitting a comma-separated integer list if
128
136
// / `EmitLongStrLiterals` is false
129
137
void emitStringLiteralDef (raw_ostream &OS, const Twine &Decl) const {
130
- assert (Entries && " Call layout() before emitStringLiteralDef()" );
138
+ assert (IsLaidOut && " Call layout() before emitStringLiteralDef()" );
131
139
if (!EmitLongStrLiterals) {
132
140
OS << Decl << " = {\n " ;
133
- emit (OS, printChar, " 0 " );
141
+ emit (OS, printChar);
134
142
OS << " 0\n };\n\n " ;
135
143
return ;
136
144
}
@@ -143,7 +151,9 @@ class SequenceToOffsetTable {
143
151
for (const auto &[Seq, Offset] : Seqs) {
144
152
OS << " /* " << Offset << " */ \" " ;
145
153
OS.write_escaped (Seq);
146
- OS << " \\ 0\"\n " ;
154
+ if (Terminator)
155
+ OS.write_escaped (StringRef (&*Terminator, 1 ));
156
+ OS << " \"\n " ;
147
157
}
148
158
OS << " };\n "
149
159
<< " #ifdef __GNUC__\n "
@@ -153,16 +163,26 @@ class SequenceToOffsetTable {
153
163
154
164
// / emit - Print out the table as the body of an array initializer.
155
165
// / Use the Print function to print elements.
156
- void emit (raw_ostream &OS, void (*Print)(raw_ostream &, ElemT),
157
- const char *Term = "0") const {
158
- assert ((empty () || Entries) && " Call layout() before emit()" );
166
+ void emit (raw_ostream &OS, void (*Print)(raw_ostream &, ElemT)) const {
167
+ assert (IsLaidOut && " Call layout() before emit()" );
159
168
for (const auto &[Seq, Offset] : Seqs) {
160
169
OS << " /* " << Offset << " */ " ;
161
170
for (const ElemT &Element : Seq) {
162
171
Print (OS, Element);
163
172
OS << " , " ;
164
173
}
165
- OS << Term << " ,\n " ;
174
+ if (Terminator) {
175
+ Print (OS, *Terminator);
176
+ OS << ' ,' ;
177
+ }
178
+ OS << ' \n ' ;
179
+ }
180
+
181
+ // Print a dummy element if the array would be empty otherwise.
182
+ if (!Entries) {
183
+ OS << " /* dummy */ " ;
184
+ Print (OS, ElemT ());
185
+ OS << ' \n ' ;
166
186
}
167
187
}
168
188
};
0 commit comments