@@ -12,12 +12,53 @@ static int compare_unsigned(unsigned lhs, unsigned rhs) {
12
12
}
13
13
14
14
namespace {
15
+ enum EntryOrder {
16
+ creationOrder,
17
+ reverseCreationOrder
18
+ };
19
+
15
20
struct Entry {
16
21
unsigned id;
17
22
unsigned value;
18
23
Entry *next;
19
24
};
20
25
26
+ class EntryFactory {
27
+ std::vector<std::unique_ptr<Entry>> entries;
28
+ unsigned nextID = 0 ;
29
+ public:
30
+ Entry *create (unsigned value) {
31
+ auto entry = new Entry{nextID++, value, nullptr };
32
+ entries.emplace_back (entry);
33
+ return entry;
34
+ }
35
+
36
+ // / Sort the entries in this list.
37
+ // /
38
+ // / \param reverseCreationOrder - if true, then order equal-value
39
+ // / nodes in the reverse of creation order; otherwise
40
+ // / creator order of creation order
41
+ void sort (EntryOrder order) {
42
+ std::sort (entries.begin (), entries.end (),
43
+ [=](const std::unique_ptr<Entry> &lhs,
44
+ const std::unique_ptr<Entry> &rhs) {
45
+ if (lhs->value != rhs->value ) return lhs->value < rhs->value ;
46
+ return order == creationOrder
47
+ ? lhs->id < rhs->id
48
+ : lhs->id > rhs->id ;
49
+ });
50
+ }
51
+
52
+ void checkSameAs (Entry *list) {
53
+ for (auto &entry: entries) {
54
+ std::cout << " " << list->value << " (" << list->id << " )\n " ;
55
+ assert (list == entry.get ());
56
+ list = list->next ;
57
+ };
58
+ assert (list == nullptr );
59
+ }
60
+ };
61
+
21
62
struct EntryListTraits {
22
63
static Entry *getNext (Entry *e) { return e->next ; }
23
64
static void setNext (Entry *e, Entry *next) { e->next = next; }
@@ -26,6 +67,8 @@ struct EntryListTraits {
26
67
}
27
68
};
28
69
70
+ using EntryListMerger = ListMerger<Entry*, EntryListTraits>;
71
+
29
72
enum Op {
30
73
insert,
31
74
beginMerge,
@@ -54,12 +97,12 @@ struct Instruction {
54
97
55
98
template <class T >
56
99
static std::ostream &operator <<(std::ostream &str, llvm::ArrayRef<T> list) {
57
- str << " [ " ;
100
+ str << " { " ;
58
101
for (auto b = list.begin (), i = b, e = list.end (); i != e; ++i) {
59
102
if (i != b) str << " , " ;
60
103
str << *i;
61
104
}
62
- str << " ] " ;
105
+ str << " } " ;
63
106
return str;
64
107
}
65
108
@@ -68,12 +111,9 @@ static std::ostream &operator<<(std::ostream &str, const std::vector<T> &list) {
68
111
return (str << llvm::makeArrayRef (list));
69
112
}
70
113
71
- static void runTest (llvm::ArrayRef<Instruction> values) {
72
- std::vector<std::unique_ptr<Entry>> entries;
73
-
74
- ListMerger<Entry*, EntryListTraits> merger;
75
-
76
- unsigned nextID = 0 ;
114
+ static void runInsertAndMergeTest (llvm::ArrayRef<Instruction> values) {
115
+ EntryFactory entries;
116
+ EntryListMerger merger;
77
117
78
118
// Between beginMerge and endMerge instructions, values don't get
79
119
// inserted immediately: they build up into a separate list of items
@@ -86,8 +126,7 @@ static void runTest(llvm::ArrayRef<Instruction> values) {
86
126
switch (inst.op ) {
87
127
case insert: {
88
128
// Create the new entry.
89
- Entry *entry = new Entry{nextID++, inst.value , nullptr };
90
- entries.emplace_back (entry);
129
+ Entry *entry = entries.create (inst.value );
91
130
92
131
// If we're building a merge list, append to the end of it.
93
132
if (lastMergeEntry) {
@@ -121,38 +160,48 @@ static void runTest(llvm::ArrayRef<Instruction> values) {
121
160
}
122
161
assert (!lastMergeEntry && " ended while still building a merge list" );
123
162
124
- // Do a stable sort of the entries.
125
- std::stable_sort (entries.begin (), entries.end (),
126
- [](const std::unique_ptr<Entry> &lhs,
127
- const std::unique_ptr<Entry> &rhs) {
128
- return (lhs->value < rhs->value );
129
- });
130
-
131
- // Make sure that we end up with the same list.
132
- auto list = merger.release ();
133
- for (auto &entry : entries) {
134
- std::cout << " " << list->value << " (" << list->id << " )\n " ;
135
- assert (list == entry.get ());
136
- list = list->next ;
163
+ entries.sort (creationOrder);
164
+ entries.checkSameAs (merger.release ());
165
+ }
166
+
167
+ static void runInsertAtFrontTest (llvm::ArrayRef<unsigned > values) {
168
+ EntryFactory entries;
169
+ EntryListMerger merger;
170
+ for (auto value: values) {
171
+ merger.insertAtFront (entries.create (value));
137
172
}
138
- assert (list == nullptr );
173
+ entries.sort (reverseCreationOrder);
174
+ entries.checkSameAs (merger.release ());
139
175
}
140
176
141
- int main () {
142
- runTest ({ 5 , 0 , 3 , 0 , 1 , 0 , 7 });
177
+ static void runConcreteTests () {
178
+ runInsertAndMergeTest ({ 5 , 0 , 3 , 0 , 1 , 0 , 7 });
179
+ }
143
180
181
+ namespace {
182
+ struct TestConfig {
183
+ unsigned numTests;
184
+ unsigned numEntries;
185
+ unsigned maxValue;
186
+ };
187
+
188
+ }
189
+
190
+ static void runInsertAndMergeTests (const TestConfig &config) {
144
191
std::random_device randomDevice;
145
192
std::default_random_engine e (randomDevice ());
146
- std::uniform_int_distribution<unsigned > dist (0 , 20 );
193
+ std::uniform_int_distribution<unsigned > valueDist (0 , config.maxValue );
194
+ // Chance of entering or exiting a merge.
195
+ std::uniform_int_distribution<unsigned > mergeDist (0 , 20 );
147
196
148
197
std::vector<Instruction> ins;
149
- for (unsigned testN = 0 ; testN < 1000 ; ++testN) {
198
+ for (unsigned testN = 0 ; testN < config. numTests ; ++testN) {
150
199
ins.clear ();
151
200
152
201
const size_t noMerge = -1 ;
153
202
size_t mergeStart = noMerge;
154
- for (unsigned i = 0 ; i < 2000 || mergeStart != noMerge; ++i) {
155
- if (dist (e) == 0 ) {
203
+ for (unsigned i = 0 ; i < config. numEntries || mergeStart != noMerge; ++i) {
204
+ if (mergeDist (e) == 0 ) {
156
205
if (mergeStart != noMerge) {
157
206
std::sort (ins.begin () + mergeStart, ins.end (),
158
207
[](const Instruction &lhs, const Instruction &rhs) {
@@ -165,11 +214,39 @@ int main() {
165
214
mergeStart = ins.size ();
166
215
}
167
216
} else {
168
- ins.push_back (dist (e));
217
+ ins.push_back (valueDist (e));
169
218
}
170
219
}
171
220
172
- std::cout << ins << std::endl;
173
- runTest (ins);
221
+ std::cout << " runInsertAndMergeTest(" << ins << " );" << std::endl;
222
+ runInsertAndMergeTest (ins);
223
+ }
224
+ }
225
+
226
+ static void runInsertAtFrontTests (const TestConfig &config) {
227
+ std::random_device randomDevice;
228
+ std::default_random_engine e (randomDevice ());
229
+ std::uniform_int_distribution<unsigned > valueDist (0 , config.maxValue );
230
+
231
+ std::vector<unsigned > ins;
232
+ for (unsigned testN = 0 ; testN < config.numTests ; ++testN) {
233
+ ins.clear ();
234
+ for (unsigned i = 0 ; i < config.numEntries ; ++i) {
235
+ ins.push_back (valueDist (e));
236
+ }
237
+
238
+ std::cout << " runInsertAtFrontTest(" << ins << " );" << std::endl;
239
+ runInsertAtFrontTest (ins);
174
240
}
175
241
}
242
+
243
+ int main () {
244
+ TestConfig config = {
245
+ .numTests = 1000 ,
246
+ .numEntries = 2000 ,
247
+ .maxValue = 3
248
+ };
249
+ runConcreteTests ();
250
+ runInsertAndMergeTests (config);
251
+ runInsertAtFrontTests (config);
252
+ }
0 commit comments