e68cffd909a7ee2f8fd1a2f1b13e3fe0a633647e
[oota-llvm.git] / unittests / ADT / HashingTest.cpp
1 //===- llvm/unittest/ADT/HashingTest.cpp ----------------------------------===//
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 // Hashing.h unit tests.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "gtest/gtest.h"
15 #include "llvm/ADT/Hashing.h"
16 #include "llvm/Support/DataTypes.h"
17 #include <deque>
18 #include <list>
19 #include <map>
20 #include <vector>
21
22 namespace llvm {
23
24 // Helper for test code to print hash codes.
25 void PrintTo(const hash_code &code, std::ostream *os) {
26   *os << static_cast<size_t>(code);
27 }
28
29 // Fake an object that is recognized as hashable data to test super large
30 // objects.
31 struct LargeTestInteger { uint64_t arr[8]; };
32
33 namespace hashing {
34 namespace detail {
35 template <> struct is_hashable_data<LargeTestInteger> : true_type {};
36 } // namespace detail
37 } // namespace hashing
38
39 } // namespace llvm
40
41 using namespace llvm;
42
43 namespace {
44
45 #if _MSC_VER != 1600
46 struct NonPOD {
47   uint64_t x, y;
48   NonPOD(uint64_t x, uint64_t y) : x(x), y(y) {}
49   ~NonPOD() {}
50   friend hash_code hash_value(const NonPOD &obj) {
51     return hash_combine(obj.x, obj.y);
52   }
53 };
54 #endif
55
56
57 TEST(HashingTest, HashValueBasicTest) {
58   int x = 42, y = 43, c = 'x';
59   void *p = 0;
60   uint64_t i = 71;
61   const unsigned ci = 71;
62   volatile int vi = 71;
63   const volatile int cvi = 71;
64   uintptr_t addr = reinterpret_cast<uintptr_t>(&y);
65   EXPECT_EQ(hash_value(42), hash_value(x));
66   EXPECT_NE(hash_value(42), hash_value(y));
67   EXPECT_NE(hash_value(42), hash_value(p));
68   EXPECT_EQ(hash_value(71), hash_value(i));
69   EXPECT_EQ(hash_value(71), hash_value(ci));
70   EXPECT_EQ(hash_value(71), hash_value(vi));
71   EXPECT_EQ(hash_value(71), hash_value(cvi));
72   EXPECT_EQ(hash_value(c), hash_value('x'));
73   EXPECT_EQ(hash_value('4'), hash_value('0' + 4));
74   EXPECT_EQ(hash_value(addr), hash_value(&y));
75
76   EXPECT_EQ(hash_combine(42, 43), hash_value(std::make_pair(42, 43)));
77   EXPECT_NE(hash_combine(43, 42), hash_value(std::make_pair(42, 43)));
78   EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43ull)));
79   EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42, 43ull)));
80   EXPECT_NE(hash_combine(42, 43), hash_value(std::make_pair(42ull, 43)));
81
82   // Note that pairs are implicitly flattened to a direct sequence of data and
83   // hashed efficiently as a consequence.
84   EXPECT_EQ(hash_combine(42, 43, 44),
85             hash_value(std::make_pair(42, std::make_pair(43, 44))));
86   EXPECT_EQ(hash_value(std::make_pair(42, std::make_pair(43, 44))),
87             hash_value(std::make_pair(std::make_pair(42, 43), 44)));
88
89 #if _MSC_VER != 1600
90   // Ensure that pairs which have padding bytes *inside* them don't get treated
91   // this way.
92   EXPECT_EQ(hash_combine('0', hash_combine(1ull, '2')),
93             hash_value(std::make_pair('0', std::make_pair(1ull, '2'))));
94
95   // Ensure that non-POD pairs don't explode the traits used.
96   NonPOD obj1(1, 2), obj2(3, 4), obj3(5, 6);
97   EXPECT_EQ(hash_combine(obj1, hash_combine(obj2, obj3)),
98             hash_value(std::make_pair(obj1, std::make_pair(obj2, obj3))));
99 #endif
100 }
101
102 template <typename T, size_t N> T *begin(T (&arr)[N]) { return arr; }
103 template <typename T, size_t N> T *end(T (&arr)[N]) { return arr + N; }
104
105 // Provide a dummy, hashable type designed for easy verification: its hash is
106 // the same as its value.
107 struct HashableDummy { size_t value; };
108 hash_code hash_value(HashableDummy dummy) { return dummy.value; }
109
110 TEST(HashingTest, HashCombineRangeBasicTest) {
111   // Leave this uninitialized in the hope that valgrind will catch bad reads.
112   int dummy;
113   hash_code dummy_hash = hash_combine_range(&dummy, &dummy);
114   EXPECT_NE(hash_code(0), dummy_hash);
115
116   const int arr1[] = { 1, 2, 3 };
117   hash_code arr1_hash = hash_combine_range(begin(arr1), end(arr1));
118   EXPECT_NE(dummy_hash, arr1_hash);
119   EXPECT_EQ(arr1_hash, hash_combine_range(begin(arr1), end(arr1)));
120
121   const std::vector<int> vec(begin(arr1), end(arr1));
122   EXPECT_EQ(arr1_hash, hash_combine_range(vec.begin(), vec.end()));
123
124   const std::list<int> list(begin(arr1), end(arr1));
125   EXPECT_EQ(arr1_hash, hash_combine_range(list.begin(), list.end()));
126
127   const std::deque<int> deque(begin(arr1), end(arr1));
128   EXPECT_EQ(arr1_hash, hash_combine_range(deque.begin(), deque.end()));
129
130   const int arr2[] = { 3, 2, 1 };
131   hash_code arr2_hash = hash_combine_range(begin(arr2), end(arr2));
132   EXPECT_NE(dummy_hash, arr2_hash);
133   EXPECT_NE(arr1_hash, arr2_hash);
134
135   const int arr3[] = { 1, 1, 2, 3 };
136   hash_code arr3_hash = hash_combine_range(begin(arr3), end(arr3));
137   EXPECT_NE(dummy_hash, arr3_hash);
138   EXPECT_NE(arr1_hash, arr3_hash);
139
140   const int arr4[] = { 1, 2, 3, 3 };
141   hash_code arr4_hash = hash_combine_range(begin(arr4), end(arr4));
142   EXPECT_NE(dummy_hash, arr4_hash);
143   EXPECT_NE(arr1_hash, arr4_hash);
144
145   const size_t arr5[] = { 1, 2, 3 };
146   const HashableDummy d_arr5[] = { {1}, {2}, {3} };
147   hash_code arr5_hash = hash_combine_range(begin(arr5), end(arr5));
148   hash_code d_arr5_hash = hash_combine_range(begin(d_arr5), end(d_arr5));
149   EXPECT_EQ(arr5_hash, d_arr5_hash);
150 }
151
152 TEST(HashingTest, HashCombineRangeLengthDiff) {
153   // Test that as only the length varies, we compute different hash codes for
154   // sequences.
155   std::map<size_t, size_t> code_to_size;
156   std::vector<char> all_one_c(256, '\xff');
157   for (unsigned Idx = 1, Size = all_one_c.size(); Idx < Size; ++Idx) {
158     hash_code code = hash_combine_range(&all_one_c[0], &all_one_c[0] + Idx);
159     std::map<size_t, size_t>::iterator
160       I = code_to_size.insert(std::make_pair(code, Idx)).first;
161     EXPECT_EQ(Idx, I->second);
162   }
163   code_to_size.clear();
164   std::vector<char> all_zero_c(256, '\0');
165   for (unsigned Idx = 1, Size = all_zero_c.size(); Idx < Size; ++Idx) {
166     hash_code code = hash_combine_range(&all_zero_c[0], &all_zero_c[0] + Idx);
167     std::map<size_t, size_t>::iterator
168       I = code_to_size.insert(std::make_pair(code, Idx)).first;
169     EXPECT_EQ(Idx, I->second);
170   }
171   code_to_size.clear();
172   std::vector<unsigned> all_one_int(512, -1);
173   for (unsigned Idx = 1, Size = all_one_int.size(); Idx < Size; ++Idx) {
174     hash_code code = hash_combine_range(&all_one_int[0], &all_one_int[0] + Idx);
175     std::map<size_t, size_t>::iterator
176       I = code_to_size.insert(std::make_pair(code, Idx)).first;
177     EXPECT_EQ(Idx, I->second);
178   }
179   code_to_size.clear();
180   std::vector<unsigned> all_zero_int(512, 0);
181   for (unsigned Idx = 1, Size = all_zero_int.size(); Idx < Size; ++Idx) {
182     hash_code code = hash_combine_range(&all_zero_int[0], &all_zero_int[0] + Idx);
183     std::map<size_t, size_t>::iterator
184       I = code_to_size.insert(std::make_pair(code, Idx)).first;
185     EXPECT_EQ(Idx, I->second);
186   }
187 }
188
189 TEST(HashingTest, HashCombineRangeGoldenTest) {
190   struct { const char *s; uint64_t hash; } golden_data[] = {
191 #if SIZE_MAX == UINT64_MAX
192     { "a",                                0xaeb6f9d5517c61f8ULL },
193     { "ab",                               0x7ab1edb96be496b4ULL },
194     { "abc",                              0xe38e60bf19c71a3fULL },
195     { "abcde",                            0xd24461a66de97f6eULL },
196     { "abcdefgh",                         0x4ef872ec411dec9dULL },
197     { "abcdefghijklm",                    0xe8a865539f4eadfeULL },
198     { "abcdefghijklmnopqrstu",            0x261cdf85faaf4e79ULL },
199     { "abcdefghijklmnopqrstuvwxyzabcdef", 0x43ba70e4198e3b2aULL },
200     { "abcdefghijklmnopqrstuvwxyzabcdef"
201       "abcdefghijklmnopqrstuvwxyzghijkl"
202       "abcdefghijklmnopqrstuvwxyzmnopqr"
203       "abcdefghijklmnopqrstuvwxyzstuvwx"
204       "abcdefghijklmnopqrstuvwxyzyzabcd", 0xdcd57fb2afdf72beULL },
205     { "a",                                0xaeb6f9d5517c61f8ULL },
206     { "aa",                               0xf2b3b69a9736a1ebULL },
207     { "aaa",                              0xf752eb6f07b1cafeULL },
208     { "aaaaa",                            0x812bd21e1236954cULL },
209     { "aaaaaaaa",                         0xff07a2cff08ac587ULL },
210     { "aaaaaaaaaaaaa",                    0x84ac949d54d704ecULL },
211     { "aaaaaaaaaaaaaaaaaaaaa",            0xcb2c8fb6be8f5648ULL },
212     { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xcc40ab7f164091b6ULL },
213     { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
214       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
215       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
216       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
217       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xc58e174c1e78ffe9ULL },
218     { "z",                                0x1ba160d7e8f8785cULL },
219     { "zz",                               0x2c5c03172f1285d7ULL },
220     { "zzz",                              0x9d2c4f4b507a2ac3ULL },
221     { "zzzzz",                            0x0f03b9031735693aULL },
222     { "zzzzzzzz",                         0xe674147c8582c08eULL },
223     { "zzzzzzzzzzzzz",                    0x3162d9fa6938db83ULL },
224     { "zzzzzzzzzzzzzzzzzzzzz",            0x37b9a549e013620cULL },
225     { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0x8921470aff885016ULL },
226     { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
227       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
228       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
229       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
230       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0xf60fdcd9beb08441ULL },
231     { "a",                                0xaeb6f9d5517c61f8ULL },
232     { "ab",                               0x7ab1edb96be496b4ULL },
233     { "aba",                              0x3edb049950884d0aULL },
234     { "ababa",                            0x8f2de9e73a97714bULL },
235     { "abababab",                         0xee14a29ddf0ce54cULL },
236     { "ababababababa",                    0x38b3ddaada2d52b4ULL },
237     { "ababababababababababa",            0xd3665364219f2b85ULL },
238     { "abababababababababababababababab", 0xa75cd6afbf1bc972ULL },
239     { "abababababababababababababababab"
240       "abababababababababababababababab"
241       "abababababababababababababababab"
242       "abababababababababababababababab"
243       "abababababababababababababababab", 0x840192d129f7a22bULL }
244 #elif SIZE_MAX == UINT32_MAX
245     { "a",                                0x000000004605f745ULL },
246     { "ab",                               0x00000000d5f06301ULL },
247     { "abc",                              0x00000000559fe1eeULL },
248     { "abcde",                            0x00000000424028d7ULL },
249     { "abcdefgh",                         0x000000007bb119f8ULL },
250     { "abcdefghijklm",                    0x00000000edbca513ULL },
251     { "abcdefghijklmnopqrstu",            0x000000007c15712eULL },
252     { "abcdefghijklmnopqrstuvwxyzabcdef", 0x000000000b3aad66ULL },
253     { "abcdefghijklmnopqrstuvwxyzabcdef"
254       "abcdefghijklmnopqrstuvwxyzghijkl"
255       "abcdefghijklmnopqrstuvwxyzmnopqr"
256       "abcdefghijklmnopqrstuvwxyzstuvwx"
257       "abcdefghijklmnopqrstuvwxyzyzabcd", 0x000000008c758c8bULL },
258     { "a",                                0x000000004605f745ULL },
259     { "aa",                               0x00000000dc0a52daULL },
260     { "aaa",                              0x00000000b309274fULL },
261     { "aaaaa",                            0x00000000203b5ef6ULL },
262     { "aaaaaaaa",                         0x00000000a429e18fULL },
263     { "aaaaaaaaaaaaa",                    0x000000008662070bULL },
264     { "aaaaaaaaaaaaaaaaaaaaa",            0x000000003f11151cULL },
265     { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0x000000008600fe20ULL },
266     { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
267       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
268       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
269       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
270       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0x000000004e0e0804ULL },
271     { "z",                                0x00000000c5e405e9ULL },
272     { "zz",                               0x00000000a8d8a2c6ULL },
273     { "zzz",                              0x00000000fc2af672ULL },
274     { "zzzzz",                            0x0000000047d9efe6ULL },
275     { "zzzzzzzz",                         0x0000000080d77794ULL },
276     { "zzzzzzzzzzzzz",                    0x00000000405f93adULL },
277     { "zzzzzzzzzzzzzzzzzzzzz",            0x00000000fc72838dULL },
278     { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0x000000007ce160f1ULL },
279     { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
280       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
281       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
282       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
283       "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0x00000000aed9ed1bULL },
284     { "a",                                0x000000004605f745ULL },
285     { "ab",                               0x00000000d5f06301ULL },
286     { "aba",                              0x00000000a85cd91bULL },
287     { "ababa",                            0x000000009e3bb52eULL },
288     { "abababab",                         0x000000002709b3b9ULL },
289     { "ababababababa",                    0x000000003a234174ULL },
290     { "ababababababababababa",            0x000000005c63e5ceULL },
291     { "abababababababababababababababab", 0x0000000013f74334ULL },
292     { "abababababababababababababababab"
293       "abababababababababababababababab"
294       "abababababababababababababababab"
295       "abababababababababababababababab"
296       "abababababababababababababababab", 0x00000000c1a6f135ULL },
297 #else
298 #error This test only supports 64-bit and 32-bit systems.
299 #endif
300   };
301   for (unsigned i = 0; i < sizeof(golden_data)/sizeof(*golden_data); ++i) {
302     StringRef str = golden_data[i].s;
303     hash_code hash = hash_combine_range(str.begin(), str.end());
304 #if 0 // Enable this to generate paste-able text for the above structure.
305     std::string member_str = "\"" + str.str() + "\",";
306     fprintf(stderr, " { %-35s 0x%016llxULL },\n",
307             member_str.c_str(), static_cast<uint64_t>(hash));
308 #endif
309     EXPECT_EQ(static_cast<size_t>(golden_data[i].hash),
310               static_cast<size_t>(hash));
311   }
312 }
313
314 TEST(HashingTest, HashCombineBasicTest) {
315   // Hashing a sequence of homogenous types matches range hashing.
316   const int i1 = 42, i2 = 43, i3 = 123, i4 = 999, i5 = 0, i6 = 79;
317   const int arr1[] = { i1, i2, i3, i4, i5, i6 };
318   EXPECT_EQ(hash_combine_range(arr1, arr1 + 1), hash_combine(i1));
319   EXPECT_EQ(hash_combine_range(arr1, arr1 + 2), hash_combine(i1, i2));
320   EXPECT_EQ(hash_combine_range(arr1, arr1 + 3), hash_combine(i1, i2, i3));
321   EXPECT_EQ(hash_combine_range(arr1, arr1 + 4), hash_combine(i1, i2, i3, i4));
322   EXPECT_EQ(hash_combine_range(arr1, arr1 + 5),
323             hash_combine(i1, i2, i3, i4, i5));
324   EXPECT_EQ(hash_combine_range(arr1, arr1 + 6),
325             hash_combine(i1, i2, i3, i4, i5, i6));
326
327   // Hashing a sequence of heterogenous types which *happen* to all produce the
328   // same data for hashing produces the same as a range-based hash of the
329   // fundamental values.
330   const size_t s1 = 1024, s2 = 8888, s3 = 9000000;
331   const HashableDummy d1 = { 1024 }, d2 = { 8888 }, d3 = { 9000000 };
332   const size_t arr2[] = { s1, s2, s3 };
333   EXPECT_EQ(hash_combine_range(begin(arr2), end(arr2)),
334             hash_combine(s1, s2, s3));
335   EXPECT_EQ(hash_combine(s1, s2, s3), hash_combine(s1, s2, d3));
336   EXPECT_EQ(hash_combine(s1, s2, s3), hash_combine(s1, d2, s3));
337   EXPECT_EQ(hash_combine(s1, s2, s3), hash_combine(d1, s2, s3));
338   EXPECT_EQ(hash_combine(s1, s2, s3), hash_combine(d1, d2, s3));
339   EXPECT_EQ(hash_combine(s1, s2, s3), hash_combine(d1, d2, d3));
340
341   // Permuting values causes hashes to change.
342   EXPECT_NE(hash_combine(i1, i1, i1), hash_combine(i1, i1, i2));
343   EXPECT_NE(hash_combine(i1, i1, i1), hash_combine(i1, i2, i1));
344   EXPECT_NE(hash_combine(i1, i1, i1), hash_combine(i2, i1, i1));
345   EXPECT_NE(hash_combine(i1, i1, i1), hash_combine(i2, i2, i1));
346   EXPECT_NE(hash_combine(i1, i1, i1), hash_combine(i2, i2, i2));
347   EXPECT_NE(hash_combine(i2, i1, i1), hash_combine(i1, i1, i2));
348   EXPECT_NE(hash_combine(i1, i1, i2), hash_combine(i1, i2, i1));
349   EXPECT_NE(hash_combine(i1, i2, i1), hash_combine(i2, i1, i1));
350
351   // Changing type w/o changing value causes hashes to change.
352   EXPECT_NE(hash_combine(i1, i2, i3), hash_combine((char)i1, i2, i3));
353   EXPECT_NE(hash_combine(i1, i2, i3), hash_combine(i1, (char)i2, i3));
354   EXPECT_NE(hash_combine(i1, i2, i3), hash_combine(i1, i2, (char)i3));
355
356   // This is array of uint64, but it should have the exact same byte pattern as
357   // an array of LargeTestIntegers.
358   const uint64_t bigarr[] = {
359     0xaaaaaaaaababababULL, 0xacacacacbcbcbcbcULL, 0xccddeeffeeddccbbULL,
360     0xdeadbeafdeadbeefULL, 0xfefefefededededeULL, 0xafafafafededededULL,
361     0xffffeeeeddddccccULL, 0xaaaacbcbffffababULL,
362     0xaaaaaaaaababababULL, 0xacacacacbcbcbcbcULL, 0xccddeeffeeddccbbULL,
363     0xdeadbeafdeadbeefULL, 0xfefefefededededeULL, 0xafafafafededededULL,
364     0xffffeeeeddddccccULL, 0xaaaacbcbffffababULL,
365     0xaaaaaaaaababababULL, 0xacacacacbcbcbcbcULL, 0xccddeeffeeddccbbULL,
366     0xdeadbeafdeadbeefULL, 0xfefefefededededeULL, 0xafafafafededededULL,
367     0xffffeeeeddddccccULL, 0xaaaacbcbffffababULL
368   };
369   // Hash a preposterously large integer, both aligned with the buffer and
370   // misaligned.
371   const LargeTestInteger li = { {
372     0xaaaaaaaaababababULL, 0xacacacacbcbcbcbcULL, 0xccddeeffeeddccbbULL,
373     0xdeadbeafdeadbeefULL, 0xfefefefededededeULL, 0xafafafafededededULL,
374     0xffffeeeeddddccccULL, 0xaaaacbcbffffababULL
375   } };
376   // Rotate the storage from 'li'.
377   const LargeTestInteger l2 = { {
378     0xacacacacbcbcbcbcULL, 0xccddeeffeeddccbbULL, 0xdeadbeafdeadbeefULL,
379     0xfefefefededededeULL, 0xafafafafededededULL, 0xffffeeeeddddccccULL,
380     0xaaaacbcbffffababULL, 0xaaaaaaaaababababULL
381   } };
382   const LargeTestInteger l3 = { {
383     0xccddeeffeeddccbbULL, 0xdeadbeafdeadbeefULL, 0xfefefefededededeULL,
384     0xafafafafededededULL, 0xffffeeeeddddccccULL, 0xaaaacbcbffffababULL,
385     0xaaaaaaaaababababULL, 0xacacacacbcbcbcbcULL
386   } };
387   EXPECT_EQ(hash_combine_range(begin(bigarr), end(bigarr)),
388             hash_combine(li, li, li));
389   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 9),
390             hash_combine(bigarr[0], l2));
391   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 10),
392             hash_combine(bigarr[0], bigarr[1], l3));
393   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 17),
394             hash_combine(li, bigarr[0], l2));
395   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 18),
396             hash_combine(li, bigarr[0], bigarr[1], l3));
397   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 18),
398             hash_combine(bigarr[0], l2, bigarr[9], l3));
399   EXPECT_EQ(hash_combine_range(bigarr, bigarr + 20),
400             hash_combine(bigarr[0], l2, bigarr[9], l3, bigarr[18], bigarr[19]));
401 }
402
403 }