-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Add templated GetRandDuration<> #18781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Conceptual suggestion by @amitiuttarwar #18038 (comment) |
Appears to be working for me:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK bbbb748.
Did the same locally yesterday.
Force pushed to
|
ACK, could add unit tests to |
Done |
std::chrono::microseconds GetRandMicros(std::chrono::microseconds duration_max) noexcept; | ||
/** Generate a random duration in the range [0..max). Precondition: max.count() > 0 */ | ||
template <typename D> | ||
D GetRandomDuration(typename std::common_type<D>::type max) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a comment here to explain why the std::common_type
construction is used here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea came from here, btw: https://stackoverflow.com/a/37737627/8342274
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
ACK faf2e85. |
src/random.h
Outdated
@@ -67,9 +67,21 @@ | |||
* Thread-safe. | |||
*/ | |||
void GetRandBytes(unsigned char* buf, int num) noexcept; | |||
/** Generate a random integer in the range [0..range). Precondition: range > 0 */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you're changing these comments anyway, you might want to add that the random number comes from a uniform distribution (especially for durations this is not obvious).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, fixed
Code review ACK 0000ea3 |
Code review ACK 0000ea3. |
ACK 0000ea3 thanks for the improved documentation. Code review, built, ran diff --git a/src/random.h b/src/random.h
index bb9b8c2a2a..0c6dc24983 100644
--- a/src/random.h
+++ b/src/random.h
@@ -67,9 +67,9 @@
* Thread-safe.
*/
void GetRandBytes(unsigned char* buf, int num) noexcept;
-/** Generate a random integer in the range [0..range). Precondition: range > 0 */
+/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
uint64_t GetRand(uint64_t nMax) noexcept;
-/** Generate a random duration in the range [0..max). Precondition: max.count() > 0 */
+/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */ |
Open-Close to re-run ci. See #15847 (comment) |
Merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK.
/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */ | ||
uint64_t GetRand(uint64_t nMax) noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */ | |
uint64_t GetRand(uint64_t nMax) noexcept; | |
/** Generate a uniform random integer in the range [0..nMax). Precondition: nMax > 0 */ | |
uint64_t GetRand(uint64_t nMax) noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. To not invalidate all the ACKs, I am going to leave this for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0000ea3 test: Add test for GetRandMillis and GetRandMicros (MarcoFalke) fa0e5b8 Add templated GetRandomDuration<> (MarcoFalke) Pull request description: A naive implementation of this template is dangerous, because the call site might accidentally omit the template parameter: ```cpp template <typename D> D GetRandDur(const D& duration_max) { return D{GetRand(duration_max.count())}; } BOOST_AUTO_TEST_CASE(util_time_GetRandTime) { std::chrono::seconds rand_hour = GetRandDur(std::chrono::hours{1}); // Want seconds to be in range [0..1hour), but always get zero :(((( BOOST_CHECK_EQUAL(rand_hour.count(), 0); } ``` Luckily `std::common_type` is already specialised in the standard lib for `std::chrono::duration` (https://en.cppreference.com/w/cpp/chrono/duration/common_type). And its effect seem to be that the call site must always specify the template argument explicitly. So instead of implementing the function for each duration type by hand, replace it with a templated version that is safe to use. ACKs for top commit: laanwj: Code review ACK 0000ea3 promag: Code review ACK 0000ea3. jonatack: ACK 0000ea3 thanks for the improved documentation. Code review, built, ran `src/test/test_bitcoin -t random_tests -l test_suite` for the new unit tests, `git diff fa05a4c 0000ea3` since previous review: hebasto: ACK 0000ea3 with non-blocking [nit](bitcoin#18781 (comment)). Tree-SHA512: e89d46e31452be6ea14269ecbbb2cdd9ae83b4412cd14dff7d1084283092722a2f847cb501e8054394e4a3eff852f9c87f6d694fd008b3f7e8458cb5a3068af7
Summary: > instead of implementing the function for each duration type by hand, replace it with a templated version that is safe to use. > A naive implementation of this template is dangerous, because the call site might accidentally omit the template parameter: > > ``` > template <typename D> > D GetRandDur(const D& duration_max) > { > return D{GetRand(duration_max.count())}; > } > > BOOST_AUTO_TEST_CASE(util_time_GetRandTime) > { > std::chrono::seconds rand_hour = GetRandDur(std::chrono::hours{1}); > // Want seconds to be in range [0..1hour), but always get zero :(((( > BOOST_CHECK_EQUAL(rand_hour.count(), 0); > } > ``` This is a backport of Core [[bitcoin/bitcoin#18781 | PR18781]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D9118
A naive implementation of this template is dangerous, because the call site might accidentally omit the template parameter:
Luckily
std::common_type
is already specialised in the standard lib forstd::chrono::duration
(https://en.cppreference.com/w/cpp/chrono/duration/common_type). And its effect seem to be that the call site must always specify the template argument explicitly.So instead of implementing the function for each duration type by hand, replace it with a templated version that is safe to use.