| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- #include <gtest/gtest.h>
- #include <climits>
- #include <queue>
- #include <random>
- #include <utility>
- #include "util/heap.h"
- #ifndef GFLAGS
- const int64_t FLAGS_iters = 100000;
- #else
- #include "util/gflags_compat.h"
- DEFINE_int64(iters, 100000, "number of pseudo-random operations in each test");
- #endif // GFLAGS
- /*
- * Compares the custom heap implementation in util/heap.h against
- * std::priority_queue on a pseudo-random sequence of operations.
- */
- namespace ROCKSDB_NAMESPACE {
- using HeapTestValue = uint64_t;
- using Params = std::tuple<size_t, HeapTestValue, int64_t>;
- class HeapTest : public ::testing::TestWithParam<Params> {
- };
- TEST_P(HeapTest, Test) {
- // This test performs the same pseudorandom sequence of operations on a
- // BinaryHeap and an std::priority_queue, comparing output. The three
- // possible operations are insert, replace top and pop.
- //
- // Insert is chosen slightly more often than the others so that the size of
- // the heap slowly grows. Once the size heats the MAX_HEAP_SIZE limit, we
- // disallow inserting until the heap becomes empty, testing the "draining"
- // scenario.
- const auto MAX_HEAP_SIZE = std::get<0>(GetParam());
- const auto MAX_VALUE = std::get<1>(GetParam());
- const auto RNG_SEED = std::get<2>(GetParam());
- BinaryHeap<HeapTestValue> heap;
- std::priority_queue<HeapTestValue> ref;
- std::mt19937 rng(static_cast<unsigned int>(RNG_SEED));
- std::uniform_int_distribution<HeapTestValue> value_dist(0, MAX_VALUE);
- int ndrains = 0;
- bool draining = false; // hit max size, draining until we empty the heap
- size_t size = 0;
- for (int64_t i = 0; i < FLAGS_iters; ++i) {
- if (size == 0) {
- draining = false;
- }
- if (!draining &&
- (size == 0 || std::bernoulli_distribution(0.4)(rng))) {
- // insert
- HeapTestValue val = value_dist(rng);
- heap.push(val);
- ref.push(val);
- ++size;
- if (size == MAX_HEAP_SIZE) {
- draining = true;
- ++ndrains;
- }
- } else if (std::bernoulli_distribution(0.5)(rng)) {
- // replace top
- HeapTestValue val = value_dist(rng);
- heap.replace_top(val);
- ref.pop();
- ref.push(val);
- } else {
- // pop
- assert(size > 0);
- heap.pop();
- ref.pop();
- --size;
- }
- // After every operation, check that the public methods give the same
- // results
- assert((size == 0) == ref.empty());
- ASSERT_EQ(size == 0, heap.empty());
- if (size > 0) {
- ASSERT_EQ(ref.top(), heap.top());
- }
- }
- // Probabilities should be set up to occasionally hit the max heap size and
- // drain it
- assert(ndrains > 0);
- heap.clear();
- ASSERT_TRUE(heap.empty());
- }
- // Basic test, MAX_VALUE = 3*MAX_HEAP_SIZE (occasional duplicates)
- INSTANTIATE_TEST_CASE_P(
- Basic, HeapTest,
- ::testing::Values(Params(1000, 3000, 0x1b575cf05b708945))
- );
- // Mid-size heap with small values (many duplicates)
- INSTANTIATE_TEST_CASE_P(
- SmallValues, HeapTest,
- ::testing::Values(Params(100, 10, 0x5ae213f7bd5dccd0))
- );
- // Small heap, large value range (no duplicates)
- INSTANTIATE_TEST_CASE_P(
- SmallHeap, HeapTest,
- ::testing::Values(Params(10, ULLONG_MAX, 0x3e1fa8f4d01707cf))
- );
- // Two-element heap
- INSTANTIATE_TEST_CASE_P(
- TwoElementHeap, HeapTest,
- ::testing::Values(Params(2, 5, 0x4b5e13ea988c6abc))
- );
- // One-element heap
- INSTANTIATE_TEST_CASE_P(
- OneElementHeap, HeapTest,
- ::testing::Values(Params(1, 3, 0x176a1019ab0b612e))
- );
- } // namespace ROCKSDB_NAMESPACE
- int main(int argc, char** argv) {
- ::testing::InitGoogleTest(&argc, argv);
- #ifdef GFLAGS
- GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
- #endif // GFLAGS
- return RUN_ALL_TESTS();
- }
|