1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "BasicHashtable_test" 18 19 #include <utils/BasicHashtable.h> 20 #include <cutils/log.h> 21 #include <gtest/gtest.h> 22 #include <unistd.h> 23 24 namespace android { 25 26 typedef int SimpleKey; 27 typedef int SimpleValue; 28 typedef key_value_pair_t<SimpleKey, SimpleValue> SimpleEntry; 29 typedef BasicHashtable<SimpleKey, SimpleEntry> SimpleHashtable; 30 31 struct ComplexKey { 32 int k; 33 34 explicit ComplexKey(int k) : k(k) { 35 instanceCount += 1; 36 } 37 38 ComplexKey(const ComplexKey& other) : k(other.k) { 39 instanceCount += 1; 40 } 41 42 ~ComplexKey() { 43 instanceCount -= 1; 44 } 45 46 bool operator ==(const ComplexKey& other) const { 47 return k == other.k; 48 } 49 50 bool operator !=(const ComplexKey& other) const { 51 return k != other.k; 52 } 53 54 static ssize_t instanceCount; 55 }; 56 57 ssize_t ComplexKey::instanceCount = 0; 58 59 template<> inline hash_t hash_type(const ComplexKey& value) { 60 return hash_type(value.k); 61 } 62 63 struct ComplexValue { 64 int v; 65 66 explicit ComplexValue(int v) : v(v) { 67 instanceCount += 1; 68 } 69 70 ComplexValue(const ComplexValue& other) : v(other.v) { 71 instanceCount += 1; 72 } 73 74 ~ComplexValue() { 75 instanceCount -= 1; 76 } 77 78 static ssize_t instanceCount; 79 }; 80 81 ssize_t ComplexValue::instanceCount = 0; 82 83 typedef key_value_pair_t<ComplexKey, ComplexValue> ComplexEntry; 84 typedef BasicHashtable<ComplexKey, ComplexEntry> ComplexHashtable; 85 86 class BasicHashtableTest : public testing::Test { 87 protected: 88 virtual void SetUp() { 89 ComplexKey::instanceCount = 0; 90 ComplexValue::instanceCount = 0; 91 } 92 93 virtual void TearDown() { 94 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 95 } 96 97 void assertInstanceCount(ssize_t keys, ssize_t values) { 98 if (keys != ComplexKey::instanceCount || values != ComplexValue::instanceCount) { 99 FAIL() << "Expected " << keys << " keys and " << values << " values " 100 "but there were actually " << ComplexKey::instanceCount << " keys and " 101 << ComplexValue::instanceCount << " values"; 102 } 103 } 104 105 public: 106 template <typename TKey, typename TEntry> 107 static void cookieAt(const BasicHashtable<TKey, TEntry>& h, size_t index, 108 bool* collision, bool* present, hash_t* hash) { 109 uint32_t cookie = h.cookieAt(index); 110 *collision = cookie & BasicHashtable<TKey, TEntry>::Bucket::COLLISION; 111 *present = cookie & BasicHashtable<TKey, TEntry>::Bucket::PRESENT; 112 *hash = cookie & BasicHashtable<TKey, TEntry>::Bucket::HASH_MASK; 113 } 114 115 template <typename TKey, typename TEntry> 116 static const void* getBuckets(const BasicHashtable<TKey, TEntry>& h) { 117 return h.mBuckets; 118 } 119 }; 120 121 template <typename TKey, typename TValue> 122 static size_t add(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, 123 const TKey& key, const TValue& value) { 124 return h.add(hash_type(key), key_value_pair_t<TKey, TValue>(key, value)); 125 } 126 127 template <typename TKey, typename TValue> 128 static ssize_t find(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, 129 ssize_t index, const TKey& key) { 130 return h.find(index, hash_type(key), key); 131 } 132 133 template <typename TKey, typename TValue> 134 static bool remove(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h, 135 const TKey& key) { 136 ssize_t index = find(h, -1, key); 137 if (index >= 0) { 138 h.removeAt(index); 139 return true; 140 } 141 return false; 142 } 143 144 template <typename TEntry> 145 static void getKeyValue(const TEntry& entry, int* key, int* value); 146 147 template <> void getKeyValue(const SimpleEntry& entry, int* key, int* value) { 148 *key = entry.key; 149 *value = entry.value; 150 } 151 152 template <> void getKeyValue(const ComplexEntry& entry, int* key, int* value) { 153 *key = entry.key.k; 154 *value = entry.value.v; 155 } 156 157 template <typename TKey, typename TValue> 158 static void dump(BasicHashtable<TKey, key_value_pair_t<TKey, TValue> >& h) { 159 ALOGD("hashtable %p, size=%u, capacity=%u, bucketCount=%u", 160 &h, h.size(), h.capacity(), h.bucketCount()); 161 for (size_t i = 0; i < h.bucketCount(); i++) { 162 bool collision, present; 163 hash_t hash; 164 BasicHashtableTest::cookieAt(h, i, &collision, &present, &hash); 165 if (present) { 166 int key, value; 167 getKeyValue(h.entryAt(i), &key, &value); 168 ALOGD(" [%3u] = collision=%d, present=%d, hash=0x%08x, key=%3d, value=%3d, " 169 "hash_type(key)=0x%08x", 170 i, collision, present, hash, key, value, hash_type(key)); 171 } else { 172 ALOGD(" [%3u] = collision=%d, present=%d", 173 i, collision, present); 174 } 175 } 176 } 177 178 TEST_F(BasicHashtableTest, DefaultConstructor_WithDefaultProperties) { 179 SimpleHashtable h; 180 181 EXPECT_EQ(0U, h.size()); 182 EXPECT_EQ(3U, h.capacity()); 183 EXPECT_EQ(5U, h.bucketCount()); 184 EXPECT_EQ(0.75f, h.loadFactor()); 185 } 186 187 TEST_F(BasicHashtableTest, Constructor_WithNonUnityLoadFactor) { 188 SimpleHashtable h(52, 0.8f); 189 190 EXPECT_EQ(0U, h.size()); 191 EXPECT_EQ(77U, h.capacity()); 192 EXPECT_EQ(97U, h.bucketCount()); 193 EXPECT_EQ(0.8f, h.loadFactor()); 194 } 195 196 TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndExactCapacity) { 197 SimpleHashtable h(46, 1.0f); 198 199 EXPECT_EQ(0U, h.size()); 200 EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f 201 EXPECT_EQ(47U, h.bucketCount()); 202 EXPECT_EQ(1.0f, h.loadFactor()); 203 } 204 205 TEST_F(BasicHashtableTest, Constructor_WithUnityLoadFactorAndInexactCapacity) { 206 SimpleHashtable h(42, 1.0f); 207 208 EXPECT_EQ(0U, h.size()); 209 EXPECT_EQ(46U, h.capacity()); // must be one less than bucketCount because loadFactor == 1.0f 210 EXPECT_EQ(47U, h.bucketCount()); 211 EXPECT_EQ(1.0f, h.loadFactor()); 212 } 213 214 TEST_F(BasicHashtableTest, FindAddFindRemoveFind_OneEntry) { 215 SimpleHashtable h; 216 ssize_t index = find(h, -1, 8); 217 ASSERT_EQ(-1, index); 218 219 index = add(h, 8, 1); 220 ASSERT_EQ(1U, h.size()); 221 222 ASSERT_EQ(index, find(h, -1, 8)); 223 ASSERT_EQ(8, h.entryAt(index).key); 224 ASSERT_EQ(1, h.entryAt(index).value); 225 226 index = find(h, index, 8); 227 ASSERT_EQ(-1, index); 228 229 ASSERT_TRUE(remove(h, 8)); 230 ASSERT_EQ(0U, h.size()); 231 232 index = find(h, -1, 8); 233 ASSERT_EQ(-1, index); 234 } 235 236 TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithUniqueKey) { 237 const size_t N = 11; 238 239 SimpleHashtable h; 240 for (size_t i = 0; i < N; i++) { 241 ssize_t index = find(h, -1, int(i)); 242 ASSERT_EQ(-1, index); 243 244 index = add(h, int(i), int(i * 10)); 245 ASSERT_EQ(i + 1, h.size()); 246 247 ASSERT_EQ(index, find(h, -1, int(i))); 248 ASSERT_EQ(int(i), h.entryAt(index).key); 249 ASSERT_EQ(int(i * 10), h.entryAt(index).value); 250 251 index = find(h, index, int(i)); 252 ASSERT_EQ(-1, index); 253 } 254 255 for (size_t i = N; --i > 0; ) { 256 ASSERT_TRUE(remove(h, int(i))) << "i = " << i; 257 ASSERT_EQ(i, h.size()); 258 259 ssize_t index = find(h, -1, int(i)); 260 ASSERT_EQ(-1, index); 261 } 262 } 263 264 TEST_F(BasicHashtableTest, FindAddFindRemoveFind_MultipleEntryWithDuplicateKey) { 265 const size_t N = 11; 266 const int K = 1; 267 268 SimpleHashtable h; 269 for (size_t i = 0; i < N; i++) { 270 ssize_t index = find(h, -1, K); 271 if (i == 0) { 272 ASSERT_EQ(-1, index); 273 } else { 274 ASSERT_NE(-1, index); 275 } 276 277 add(h, K, int(i)); 278 ASSERT_EQ(i + 1, h.size()); 279 280 index = -1; 281 int values = 0; 282 for (size_t j = 0; j <= i; j++) { 283 index = find(h, index, K); 284 ASSERT_GE(index, 0); 285 ASSERT_EQ(K, h.entryAt(index).key); 286 values |= 1 << h.entryAt(index).value; 287 } 288 ASSERT_EQ(values, (1 << (i + 1)) - 1); 289 290 index = find(h, index, K); 291 ASSERT_EQ(-1, index); 292 } 293 294 for (size_t i = N; --i > 0; ) { 295 ASSERT_TRUE(remove(h, K)) << "i = " << i; 296 ASSERT_EQ(i, h.size()); 297 298 ssize_t index = -1; 299 for (size_t j = 0; j < i; j++) { 300 index = find(h, index, K); 301 ASSERT_GE(index, 0); 302 ASSERT_EQ(K, h.entryAt(index).key); 303 } 304 305 index = find(h, index, K); 306 ASSERT_EQ(-1, index); 307 } 308 } 309 310 TEST_F(BasicHashtableTest, Clear_WhenAlreadyEmpty_DoesNothing) { 311 SimpleHashtable h; 312 h.clear(); 313 314 EXPECT_EQ(0U, h.size()); 315 EXPECT_EQ(3U, h.capacity()); 316 EXPECT_EQ(5U, h.bucketCount()); 317 EXPECT_EQ(0.75f, h.loadFactor()); 318 } 319 320 TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_RemovesThem) { 321 SimpleHashtable h; 322 add(h, 0, 0); 323 add(h, 1, 0); 324 h.clear(); 325 326 EXPECT_EQ(0U, h.size()); 327 EXPECT_EQ(3U, h.capacity()); 328 EXPECT_EQ(5U, h.bucketCount()); 329 EXPECT_EQ(0.75f, h.loadFactor()); 330 } 331 332 TEST_F(BasicHashtableTest, Clear_AfterElementsAdded_DestroysThem) { 333 ComplexHashtable h; 334 add(h, ComplexKey(0), ComplexValue(0)); 335 add(h, ComplexKey(1), ComplexValue(0)); 336 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 337 338 h.clear(); 339 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 340 341 EXPECT_EQ(0U, h.size()); 342 EXPECT_EQ(3U, h.capacity()); 343 EXPECT_EQ(5U, h.bucketCount()); 344 EXPECT_EQ(0.75f, h.loadFactor()); 345 } 346 347 TEST_F(BasicHashtableTest, Remove_AfterElementsAdded_DestroysThem) { 348 ComplexHashtable h; 349 add(h, ComplexKey(0), ComplexValue(0)); 350 add(h, ComplexKey(1), ComplexValue(0)); 351 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 352 353 ASSERT_TRUE(remove(h, ComplexKey(0))); 354 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); 355 356 ASSERT_TRUE(remove(h, ComplexKey(1))); 357 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 358 359 EXPECT_EQ(0U, h.size()); 360 EXPECT_EQ(3U, h.capacity()); 361 EXPECT_EQ(5U, h.bucketCount()); 362 EXPECT_EQ(0.75f, h.loadFactor()); 363 } 364 365 TEST_F(BasicHashtableTest, Destructor_AfterElementsAdded_DestroysThem) { 366 { 367 ComplexHashtable h; 368 add(h, ComplexKey(0), ComplexValue(0)); 369 add(h, ComplexKey(1), ComplexValue(0)); 370 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 371 } // h is destroyed here 372 373 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 374 } 375 376 TEST_F(BasicHashtableTest, Next_WhenEmpty_ReturnsMinusOne) { 377 SimpleHashtable h; 378 379 ASSERT_EQ(-1, h.next(-1)); 380 } 381 382 TEST_F(BasicHashtableTest, Next_WhenNonEmpty_IteratesOverAllEntries) { 383 const int N = 88; 384 385 SimpleHashtable h; 386 for (int i = 0; i < N; i++) { 387 add(h, i, i * 10); 388 } 389 390 bool set[N]; 391 memset(set, 0, sizeof(bool) * N); 392 int count = 0; 393 for (ssize_t index = -1; (index = h.next(index)) != -1; ) { 394 ASSERT_GE(index, 0); 395 ASSERT_LT(size_t(index), h.bucketCount()); 396 397 const SimpleEntry& entry = h.entryAt(index); 398 ASSERT_GE(entry.key, 0); 399 ASSERT_LT(entry.key, N); 400 ASSERT_EQ(false, set[entry.key]); 401 ASSERT_EQ(entry.key * 10, entry.value); 402 403 set[entry.key] = true; 404 count += 1; 405 } 406 ASSERT_EQ(N, count); 407 } 408 409 TEST_F(BasicHashtableTest, Add_RehashesOnDemand) { 410 SimpleHashtable h; 411 size_t initialCapacity = h.capacity(); 412 size_t initialBucketCount = h.bucketCount(); 413 414 for (size_t i = 0; i < initialCapacity; i++) { 415 add(h, int(i), 0); 416 } 417 418 EXPECT_EQ(initialCapacity, h.size()); 419 EXPECT_EQ(initialCapacity, h.capacity()); 420 EXPECT_EQ(initialBucketCount, h.bucketCount()); 421 422 add(h, -1, -1); 423 424 EXPECT_EQ(initialCapacity + 1, h.size()); 425 EXPECT_GT(h.capacity(), initialCapacity); 426 EXPECT_GT(h.bucketCount(), initialBucketCount); 427 EXPECT_GT(h.bucketCount(), h.capacity()); 428 } 429 430 TEST_F(BasicHashtableTest, Rehash_WhenCapacityAndBucketCountUnchanged_DoesNothing) { 431 ComplexHashtable h; 432 add(h, ComplexKey(0), ComplexValue(0)); 433 const void* oldBuckets = getBuckets(h); 434 ASSERT_NE((void*)NULL, oldBuckets); 435 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); 436 437 h.rehash(h.capacity(), h.loadFactor()); 438 439 ASSERT_EQ(oldBuckets, getBuckets(h)); 440 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(1, 1)); 441 } 442 443 TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasNoBuckets_ButDoesNotAllocateBuckets) { 444 ComplexHashtable h; 445 ASSERT_EQ((void*)NULL, getBuckets(h)); 446 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 447 448 h.rehash(9, 1.0f); 449 450 EXPECT_EQ(0U, h.size()); 451 EXPECT_EQ(10U, h.capacity()); 452 EXPECT_EQ(11U, h.bucketCount()); 453 EXPECT_EQ(1.0f, h.loadFactor()); 454 EXPECT_EQ((void*)NULL, getBuckets(h)); 455 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 456 } 457 458 TEST_F(BasicHashtableTest, Rehash_WhenEmptyAndHasBuckets_ReleasesBucketsAndSetsCapacity) { 459 ComplexHashtable h(10); 460 add(h, ComplexKey(0), ComplexValue(0)); 461 ASSERT_TRUE(remove(h, ComplexKey(0))); 462 ASSERT_NE((void*)NULL, getBuckets(h)); 463 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 464 465 h.rehash(0, 0.75f); 466 467 EXPECT_EQ(0U, h.size()); 468 EXPECT_EQ(3U, h.capacity()); 469 EXPECT_EQ(5U, h.bucketCount()); 470 EXPECT_EQ(0.75f, h.loadFactor()); 471 EXPECT_EQ((void*)NULL, getBuckets(h)); 472 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(0, 0)); 473 } 474 475 TEST_F(BasicHashtableTest, Rehash_WhenLessThanCurrentCapacity_ShrinksBuckets) { 476 ComplexHashtable h(10); 477 add(h, ComplexKey(0), ComplexValue(0)); 478 add(h, ComplexKey(1), ComplexValue(1)); 479 const void* oldBuckets = getBuckets(h); 480 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 481 482 h.rehash(0, 0.75f); 483 484 EXPECT_EQ(2U, h.size()); 485 EXPECT_EQ(3U, h.capacity()); 486 EXPECT_EQ(5U, h.bucketCount()); 487 EXPECT_EQ(0.75f, h.loadFactor()); 488 EXPECT_NE(oldBuckets, getBuckets(h)); 489 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 490 } 491 492 TEST_F(BasicHashtableTest, CopyOnWrite) { 493 ComplexHashtable h1; 494 add(h1, ComplexKey(0), ComplexValue(0)); 495 add(h1, ComplexKey(1), ComplexValue(1)); 496 const void* originalBuckets = getBuckets(h1); 497 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 498 ssize_t index0 = find(h1, -1, ComplexKey(0)); 499 EXPECT_GE(index0, 0); 500 501 // copy constructor acquires shared reference 502 ComplexHashtable h2(h1); 503 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 504 ASSERT_EQ(originalBuckets, getBuckets(h2)); 505 EXPECT_EQ(h1.size(), h2.size()); 506 EXPECT_EQ(h1.capacity(), h2.capacity()); 507 EXPECT_EQ(h1.bucketCount(), h2.bucketCount()); 508 EXPECT_EQ(h1.loadFactor(), h2.loadFactor()); 509 EXPECT_EQ(index0, find(h2, -1, ComplexKey(0))); 510 511 // operator= acquires shared reference 512 ComplexHashtable h3; 513 h3 = h2; 514 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 515 ASSERT_EQ(originalBuckets, getBuckets(h3)); 516 EXPECT_EQ(h1.size(), h3.size()); 517 EXPECT_EQ(h1.capacity(), h3.capacity()); 518 EXPECT_EQ(h1.bucketCount(), h3.bucketCount()); 519 EXPECT_EQ(h1.loadFactor(), h3.loadFactor()); 520 EXPECT_EQ(index0, find(h3, -1, ComplexKey(0))); 521 522 // editEntryAt copies shared contents 523 h1.editEntryAt(index0).value.v = 42; 524 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); 525 ASSERT_NE(originalBuckets, getBuckets(h1)); 526 EXPECT_EQ(42, h1.entryAt(index0).value.v); 527 EXPECT_EQ(0, h2.entryAt(index0).value.v); 528 EXPECT_EQ(0, h3.entryAt(index0).value.v); 529 530 // clear releases reference to shared contents 531 h2.clear(); 532 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); 533 EXPECT_EQ(0U, h2.size()); 534 ASSERT_NE(originalBuckets, getBuckets(h2)); 535 536 // operator= acquires shared reference, destroys unshared contents 537 h1 = h3; 538 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 539 ASSERT_EQ(originalBuckets, getBuckets(h1)); 540 EXPECT_EQ(h3.size(), h1.size()); 541 EXPECT_EQ(h3.capacity(), h1.capacity()); 542 EXPECT_EQ(h3.bucketCount(), h1.bucketCount()); 543 EXPECT_EQ(h3.loadFactor(), h1.loadFactor()); 544 EXPECT_EQ(index0, find(h1, -1, ComplexKey(0))); 545 546 // add copies shared contents 547 add(h1, ComplexKey(2), ComplexValue(2)); 548 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(5, 5)); 549 ASSERT_NE(originalBuckets, getBuckets(h1)); 550 EXPECT_EQ(3U, h1.size()); 551 EXPECT_EQ(0U, h2.size()); 552 EXPECT_EQ(2U, h3.size()); 553 554 // remove copies shared contents 555 h1 = h3; 556 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 557 ASSERT_EQ(originalBuckets, getBuckets(h1)); 558 h1.removeAt(index0); 559 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(3, 3)); 560 ASSERT_NE(originalBuckets, getBuckets(h1)); 561 EXPECT_EQ(1U, h1.size()); 562 EXPECT_EQ(0U, h2.size()); 563 EXPECT_EQ(2U, h3.size()); 564 565 // rehash copies shared contents 566 h1 = h3; 567 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(2, 2)); 568 ASSERT_EQ(originalBuckets, getBuckets(h1)); 569 h1.rehash(10, 1.0f); 570 ASSERT_NO_FATAL_FAILURE(assertInstanceCount(4, 4)); 571 ASSERT_NE(originalBuckets, getBuckets(h1)); 572 EXPECT_EQ(2U, h1.size()); 573 EXPECT_EQ(0U, h2.size()); 574 EXPECT_EQ(2U, h3.size()); 575 } 576 577 } // namespace android 578