diff --git a/snappy-test.h b/snappy-test.h index ec9d4db..e31a78d 100644 --- a/snappy-test.h +++ b/snappy-test.h @@ -189,56 +189,6 @@ string ReadTestDataFile(const string& base); // Not safe for general use due to truncation issues. string StringPrintf(const char* format, ...); -// A simple, non-cryptographically-secure random generator. -class ACMRandom { - public: - explicit ACMRandom(uint32 seed) : seed_(seed) {} - - int32 Next(); - - int32 Uniform(int32 n) { - return Next() % n; - } - uint8 Rand8() { - return static_cast((Next() >> 1) & 0x000000ff); - } - bool OneIn(int X) { return Uniform(X) == 0; } - - // Skewed: pick "base" uniformly from range [0,max_log] and then - // return "base" random bits. The effect is to pick a number in the - // range [0,2^max_log-1] with bias towards smaller numbers. - int32 Skewed(int max_log); - - private: - static const uint32 M = 2147483647L; // 2^31-1 - uint32 seed_; -}; - -inline int32 ACMRandom::Next() { - static const uint64 A = 16807; // bits 14, 8, 7, 5, 2, 1, 0 - // We are computing - // seed_ = (seed_ * A) % M, where M = 2^31-1 - // - // seed_ must not be zero or M, or else all subsequent computed values - // will be zero or M respectively. For all other values, seed_ will end - // up cycling through every number in [1,M-1] - uint64 product = seed_ * A; - - // Compute (product % M) using the fact that ((x << 31) % M) == x. - seed_ = (product >> 31) + (product & M); - // The first reduction may overflow by 1 bit, so we may need to repeat. - // mod == M is not possible; using > allows the faster sign-bit-based test. - if (seed_ > M) { - seed_ -= M; - } - return seed_; -} - -inline int32 ACMRandom::Skewed(int max_log) { - const int32 base = (Next() - 1) % (max_log+1); - return (Next() - 1) & ((1u << base)-1); -} - // A wall-time clock. This stub is not super-accurate, nor resistant to the // system time changing. class CycleTimer { diff --git a/snappy_unittest.cc b/snappy_unittest.cc index b2c79ac..8d69319 100644 --- a/snappy_unittest.cc +++ b/snappy_unittest.cc @@ -31,6 +31,7 @@ #include +#include #include #include #include @@ -405,24 +406,28 @@ static void VerifyIOVec(const string& input) { // Try uncompressing into an iovec containing a random number of entries // ranging from 1 to 10. char* buf = new char[input.size()]; - ACMRandom rnd(input.size()); - size_t num = absl::Uniform(rnd) % 10 + 1; + std::minstd_rand0 rng(input.size()); + std::uniform_int_distribution uniform_1_to_10(1, 10); + size_t num = uniform_1_to_10(rng); if (input.size() < num) { num = input.size(); } struct iovec* iov = new iovec[num]; int used_so_far = 0; + std::bernoulli_distribution one_in_five(1.0 / 5); for (size_t i = 0; i < num; ++i) { + assert(used_so_far < input.size()); iov[i].iov_base = buf + used_so_far; if (i == num - 1) { iov[i].iov_len = input.size() - used_so_far; } else { // Randomly choose to insert a 0 byte entry. - if (rnd.OneIn(5)) { + if (one_in_five(rng)) { iov[i].iov_len = 0; } else { - iov[i].iov_len = - absl::Uniform(rnd, 0, input.size() - used_so_far); + std::uniform_int_distribution uniform_not_used_so_far( + 0, input.size() - used_so_far - 1); + iov[i].iov_len = uniform_not_used_so_far(rng); } } used_so_far += iov[i].iov_len; @@ -665,42 +670,58 @@ TEST(Snappy, SimpleTests) { // Verify max blowup (lots of four-byte copies) TEST(Snappy, MaxBlowup) { + std::mt19937 rng; + std::uniform_int_distribution random_byte; string input; - for (int i = 0; i < 20000; i++) { - ACMRandom rnd(i); - uint32 bytes = static_cast(absl::Uniform(rnd)); - input.append(reinterpret_cast(&bytes), sizeof(bytes)); - } - for (int i = 19999; i >= 0; i--) { - ACMRandom rnd(i); - uint32 bytes = static_cast(absl::Uniform(rnd)); - input.append(reinterpret_cast(&bytes), sizeof(bytes)); + for (int i = 0; i < 80000; ++i) + input.push_back(static_cast(random_byte(rng))); + + for (int i = 0; i < 80000; i += 4) { + string four_bytes(input.end() - i - 4, input.end() - i); + input.append(four_bytes); } Verify(input); } TEST(Snappy, RandomData) { - ACMRandom rnd(FLAGS_test_random_seed); + std::minstd_rand0 rng(FLAGS_test_random_seed); + std::uniform_int_distribution uniform_0_to_3(0, 3); + std::uniform_int_distribution uniform_0_to_8(0, 8); + std::uniform_int_distribution uniform_byte; + std::uniform_int_distribution uniform_4k(0, 4095); + std::uniform_int_distribution uniform_64k(0, 65535); + std::bernoulli_distribution one_in_ten(1.0 / 10); - const int num_ops = 20000; + constexpr int num_ops = 20000; for (int i = 0; i < num_ops; i++) { if ((i % 1000) == 0) { VLOG(0) << "Random op " << i << " of " << num_ops; } string x; - size_t len = absl::Uniform(rnd, 0, 4096); + size_t len = uniform_4k(rng); if (i < 100) { - len = 65536 + absl::Uniform(rnd, 0, 65536); + len = 65536 + uniform_64k(rng); } while (x.size() < len) { int run_len = 1; - if (rnd.OneIn(10)) { - run_len = rnd.Skewed(8); + if (one_in_ten(rng)) { + int skewed_bits = uniform_0_to_8(rng); + // int is guaranteed to hold at least 16 bits, this uses at most 8 bits. + std::uniform_int_distribution skewed_low(0, + (1 << skewed_bits) - 1); + run_len = skewed_low(rng); + } + char c = static_cast(uniform_byte(rng)); + if (i >= 100) { + int skewed_bits = uniform_0_to_3(rng); + // int is guaranteed to hold at least 16 bits, this uses at most 3 bits. + std::uniform_int_distribution skewed_low(0, + (1 << skewed_bits) - 1); + c = static_cast(skewed_low(rng)); } - char c = (i < 100) ? absl::Uniform(rnd, 0, 256) : rnd.Skewed(3); while (run_len-- > 0 && x.size() < len) { - x += c; + x.push_back(c); } } @@ -1038,17 +1059,20 @@ TEST(Snappy, FindMatchLength) { } TEST(Snappy, FindMatchLengthRandom) { - const int kNumTrials = 10000; - const int kTypicalLength = 10; - ACMRandom rnd(FLAGS_test_random_seed); + constexpr int kNumTrials = 10000; + constexpr int kTypicalLength = 10; + std::minstd_rand0 rng(FLAGS_test_random_seed); + std::uniform_int_distribution uniform_byte; + std::bernoulli_distribution one_in_two(1.0 / 2); + std::bernoulli_distribution one_in_typical_length(1.0 / kTypicalLength); for (int i = 0; i < kNumTrials; i++) { string s, t; - char a = absl::Uniform(rnd); - char b = absl::Uniform(rnd); - while (!rnd.OneIn(kTypicalLength)) { - s.push_back(rnd.OneIn(2) ? a : b); - t.push_back(rnd.OneIn(2) ? a : b); + char a = uniform_byte(rng); + char b = uniform_byte(rng); + while (!one_in_typical_length(rng)) { + s.push_back(one_in_two(rng) ? a : b); + t.push_back(one_in_two(rng) ? a : b); } DataEndingAtUnreadablePage u(s); DataEndingAtUnreadablePage v(t);