]> git.proxmox.com Git - rustc.git/blame - src/compiler-rt/test/esan/Unit/hashtable.cpp
New upstream version 1.19.0+dfsg3
[rustc.git] / src / compiler-rt / test / esan / Unit / hashtable.cpp
CommitLineData
7cac9316
XL
1// RUN: %clangxx_unit -esan-instrument-loads-and-stores=0 -O0 %s -o %t 2>&1
2// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s
3
4#include "esan/esan_hashtable.h"
5#include <assert.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10class MyData {
11 public:
12 MyData(const char *Str) : RefCount(0) { Buf = strdup(Str); }
13 ~MyData() {
14 fprintf(stderr, " Destructor: %s.\n", Buf);
15 free(Buf);
16 }
17 bool operator==(MyData &Cmp) { return strcmp(Buf, Cmp.Buf) == 0; }
18 operator size_t() const {
19 size_t Res = 0;
20 for (int i = 0; i < strlen(Buf); ++i)
21 Res ^= Buf[i];
22 return Res;
23 }
24 char *Buf;
25 int RefCount;
26};
27
28// We use a smart pointer wrapper to free the payload on hashtable removal.
29struct MyDataPayload {
30 MyDataPayload() : Data(nullptr) {}
31 explicit MyDataPayload(MyData *Data) : Data(Data) { ++Data->RefCount; }
32 ~MyDataPayload() {
33 if (Data && --Data->RefCount == 0) {
34 fprintf(stderr, "Deleting %s.\n", Data->Buf);
35 delete Data;
36 }
37 }
38 MyDataPayload(const MyDataPayload &Copy) {
39 Data = Copy.Data;
40 ++Data->RefCount;
41 }
42 MyDataPayload & operator=(const MyDataPayload &Copy) {
43 if (this != &Copy) {
44 this->~MyDataPayload();
45 Data = Copy.Data;
46 ++Data->RefCount;
47 }
48 return *this;
49 }
50 bool operator==(MyDataPayload &Cmp) { return *Data == *Cmp.Data; }
51 operator size_t() const { return (size_t)*Data; }
52 MyData *Data;
53};
54
55int main()
56{
57 __esan::HashTable<int, int> IntTable;
58 assert(IntTable.size() == 0);
59
60 // Test iteration on an empty table.
61 int Count = 0;
62 for (auto Iter = IntTable.begin(); Iter != IntTable.end();
63 ++Iter, ++Count) {
64 // Empty.
65 }
66 assert(Count == 0);
67
68 bool Added = IntTable.add(4, 42);
69 assert(Added);
70 assert(!IntTable.add(4, 42));
71 assert(IntTable.size() == 1);
72 int Value;
73 bool Found = IntTable.lookup(4, Value);
74 assert(Found && Value == 42);
75
76 // Test iterator.
77 IntTable.lock();
78 for (auto Iter = IntTable.begin(); Iter != IntTable.end();
79 ++Iter, ++Count) {
80 assert((*Iter).Key == 4);
81 assert((*Iter).Data == 42);
82 }
83 IntTable.unlock();
84 assert(Count == 1);
85 assert(Count == IntTable.size());
86 assert(!IntTable.remove(5));
87 assert(IntTable.remove(4));
88
89 // Test a more complex payload.
90 __esan::HashTable<int, MyDataPayload> DataTable(4);
91 MyDataPayload NewData(new MyData("mystring"));
92 Added = DataTable.add(4, NewData);
93 assert(Added);
94 MyDataPayload FoundData;
95 Found = DataTable.lookup(4, FoundData);
96 assert(Found && strcmp(FoundData.Data->Buf, "mystring") == 0);
97 assert(!DataTable.remove(5));
98 assert(DataTable.remove(4));
99 // Test resize.
100 for (int i = 0; i < 4; ++i) {
101 MyDataPayload MoreData(new MyData("delete-at-end"));
102 Added = DataTable.add(i+1, MoreData);
103 assert(Added);
104 assert(!DataTable.add(i+1, MoreData));
105 }
106 for (int i = 0; i < 4; ++i) {
107 Found = DataTable.lookup(i+1, FoundData);
108 assert(Found && strcmp(FoundData.Data->Buf, "delete-at-end") == 0);
109 }
110 DataTable.lock();
111 Count = 0;
112 for (auto Iter = DataTable.begin(); Iter != DataTable.end();
113 ++Iter, ++Count) {
114 int Key = (*Iter).Key;
115 FoundData = (*Iter).Data;
116 assert(Key >= 1 && Key <= 4);
117 assert(strcmp(FoundData.Data->Buf, "delete-at-end") == 0);
118 }
119 DataTable.unlock();
120 assert(Count == 4);
121 assert(Count == DataTable.size());
122
123 // Ensure the iterator supports a range-based for loop.
124 DataTable.lock();
125 Count = 0;
126 for (auto Pair : DataTable) {
127 assert(Pair.Key >= 1 && Pair.Key <= 4);
128 assert(strcmp(Pair.Data.Data->Buf, "delete-at-end") == 0);
129 ++Count;
130 }
131 DataTable.unlock();
132 assert(Count == 4);
133 assert(Count == DataTable.size());
134
135 // Test payload freeing via smart pointer wrapper.
136 __esan::HashTable<MyDataPayload, MyDataPayload, true> DataKeyTable;
137 MyDataPayload DataA(new MyData("string AB"));
138 DataKeyTable.lock();
139 Added = DataKeyTable.add(DataA, DataA);
140 assert(Added);
141 Found = DataKeyTable.lookup(DataA, FoundData);
142 assert(Found && strcmp(FoundData.Data->Buf, "string AB") == 0);
143 MyDataPayload DataB(new MyData("string AB"));
144 Added = DataKeyTable.add(DataB, DataB);
145 assert(!Added);
146 DataKeyTable.remove(DataB); // Should free the DataA payload.
147 DataKeyTable.unlock();
148
149 // Test custom functors.
150 struct CustomHash {
151 size_t operator()(int Key) const { return Key % 4; }
152 };
153 struct CustomEqual {
154 bool operator()(int Key1, int Key2) const { return Key1 %4 == Key2 % 4; }
155 };
156 __esan::HashTable<int, int, false, CustomHash, CustomEqual> ModTable;
157 Added = ModTable.add(2, 42);
158 assert(Added);
159 Added = ModTable.add(6, 42);
160 assert(!Added);
161
162 fprintf(stderr, "All checks passed.\n");
163 return 0;
164}
165// CHECK: Deleting mystring.
166// CHECK-NEXT: Destructor: mystring.
167// CHECK-NEXT: All checks passed.
168// CHECK-NEXT: Deleting string AB.
169// CHECK-NEXT: Destructor: string AB.
170// CHECK-NEXT: Deleting string AB.
171// CHECK-NEXT: Destructor: string AB.
172// CHECK-NEXT: Deleting delete-at-end.
173// CHECK-NEXT: Destructor: delete-at-end.
174// CHECK-NEXT: Deleting delete-at-end.
175// CHECK-NEXT: Destructor: delete-at-end.
176// CHECK-NEXT: Deleting delete-at-end.
177// CHECK-NEXT: Destructor: delete-at-end.
178// CHECK-NEXT: Deleting delete-at-end.
179// CHECK-NEXT: Destructor: delete-at-end.