diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/Jamfile | 2 | ||||
-rw-r--r-- | util/random.cc | 39 | ||||
-rw-r--r-- | util/random.hh | 32 | ||||
-rw-r--r-- | util/random_test.cc | 39 |
4 files changed, 111 insertions, 1 deletions
diff --git a/util/Jamfile b/util/Jamfile index a82a5e23d..2d3cede01 100644 --- a/util/Jamfile +++ b/util/Jamfile @@ -21,7 +21,7 @@ obj file_piece_test.o : file_piece_test.cc /top//boost_unit_test_framework : $(c fakelib parallel_read : parallel_read.cc : <threading>multi:<source>/top//boost_thread <threading>multi:<define>WITH_THREADS : : <include>.. ; -fakelib kenutil : bit_packing.cc ersatz_progress.cc exception.cc file.cc file_piece.cc mmap.cc murmur_hash.cc parallel_read pool.cc read_compressed scoped.cc string_piece.cc usage.cc double-conversion//double-conversion : <include>.. <os>LINUX,<threading>single:<source>rt : : <include>.. ; +fakelib kenutil : bit_packing.cc ersatz_progress.cc exception.cc file.cc file_piece.cc mmap.cc murmur_hash.cc parallel_read pool.cc random.cc read_compressed scoped.cc string_piece.cc usage.cc double-conversion//double-conversion : <include>.. <os>LINUX,<threading>single:<source>rt : : <include>.. ; exe cat_compressed : cat_compressed_main.cc kenutil ; diff --git a/util/random.cc b/util/random.cc new file mode 100644 index 000000000..368718c9f --- /dev/null +++ b/util/random.cc @@ -0,0 +1,39 @@ +#include "util/random.hh" + +#include <cstdlib> + +#include <boost/thread/locks.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/mutex.hpp> + +namespace util +{ +namespace +{ +/** Lock to protect randomizer. + * + * This module is implemented in terms of rand()/srand() from <cstdlib>. + * These functions are standard C, but they're not thread-safe. Scalability + * is not worth much complexity here, so just slap a mutex around it. + */ +boost::mutex rand_lock; +} // namespace + +void rand_int_init(unsigned int seed) +{ + boost::lock_guard<boost::mutex> lock(rand_lock); + srand(seed); +} + + +void rand_int_init() +{ + rand_int_init(time(NULL)); +} + +int rand_int() +{ + boost::lock_guard<boost::mutex> lock(rand_lock); + return rand(); +} +} // namespace util diff --git a/util/random.hh b/util/random.hh new file mode 100644 index 000000000..c372de463 --- /dev/null +++ b/util/random.hh @@ -0,0 +1,32 @@ +#ifndef UTIL_RANDOM_H +#define UTIL_RANDOM_H + +namespace util +{ + +/** Initialize randomizer with a fixed seed. + * + * After this, unless the randomizer gets seeded again, consecutive calls to + * rand_int() will return a sequence of pseudo-random numbers determined by + * the seed. Every time the randomizer is seeded with this same seed, it will + * again start returning the same sequence of numbers. + */ +void rand_int_init(unsigned int); + +/** Initialize randomizer based on current time. + * + * Call this to make the randomizer return hard-to-predict numbers. It won't + * produce high-grade randomness, but enough to make the program act + * differently on different runs. + */ +void rand_int_init(); + +/** Return a pseudorandom number between 0 and RAND_MAX inclusive. + * + * Initialize (seed) the randomizer before starting to call this. + */ +int rand_int(); + +} // namespace util + +#endif diff --git a/util/random_test.cc b/util/random_test.cc new file mode 100644 index 000000000..d1c555a0c --- /dev/null +++ b/util/random_test.cc @@ -0,0 +1,39 @@ +#include "util/random.hh" + +#define BOOST_TEST_MODULE RandomTest +#include <boost/test/unit_test.hpp> + +namespace util +{ +namespace +{ + +BOOST_AUTO_TEST_CASE(returns_different_consecutive_numbers) +{ + rand_int_init(99); + const int first = rand_int(), second = rand_int(), third = rand_int(); + // Sometimes you'll get the same number twice in a row, but generally the + // randomizer returns different numbers. + BOOST_CHECK(second != first || third != first); +} + +BOOST_AUTO_TEST_CASE(returns_different_numbers_for_different_seeds) +{ + rand_int_init(1); + const int one1 = rand_int(), one2 = rand_int(); + rand_int_init(2); + const int two1 = rand_int(), two2 = rand_int(); + BOOST_CHECK(two1 != one1 || two2 != two1); +} + +BOOST_AUTO_TEST_CASE(returns_same_sequence_for_same_seed) +{ + rand_int_init(1); + const int first = rand_int(); + rand_int_init(1); + const int second = rand_int(); + BOOST_CHECK_EQUAL(first, second); +} + +} // namespace +} // namespace util |