-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Use memset and memcmp in a bit more cases #1160
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
| bool output[] = {false, true, false}; | ||
| fill(output, output + 3, 5); | ||
| for (bool elem : output) { | ||
| assert(elem == true); |
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.
These tests will likely pass even if int is not properly converted to bool. I suggest
for (const bool& elem : output) {
assert(memcmp(&elem, &true_value, sizeof(bool)) == 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.
On my PC the assertion fails when I run:
#include <cstring>
#include <cassert>
using namespace std;
int main() {
bool b;
memset(&b, 5, 1);
assert(b == true);
}
And I can't use memcmp because it's not constexpr
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.
I think it depends on debug (/Od) vs release (/O2).
Maybe in debug == true is literally comparison against true, and in release it is just test and branch on flags.
If that's right, then since tests run in debug, this looks enough.
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.
Tested this code in release width /O2 (only replaced assert(b == true); with if (b != true) abort(); because assert does nothing in release) and it still fails.
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.
It mustn't be UB because this code compiles (unless it's a compiler bug):
#include <bit>
#include <cassert>
using namespace std;
constexpr bool f() {
char i = 5;
return bit_cast<bool>(i);
}
int main() {
constexpr bool b = f();
static_assert(b != true);
static_assert(b != false);
}
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.
Also I found that this code compiles:
#include <bit>
#include <algorithm>
using namespace std;
constexpr bool f() {
char i = 2;
bool arr[] = {false, true, true};
bool arr2[] = {false, true, bit_cast<bool>(i)};
return !equal(begin(arr), end(arr), begin(arr2));
}
int main() {
static_assert(f());
}
Line 4895 in e000d3f
| // * They can't be bool. (Not even `bool == bool`; we're concerned about representations other than 0 and 1.) |
Which means that
equal should be able to use memcmp with bool.
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.
Interesting.
I think it is still UB (expected behavior is a possible UB manifestation)
Usually wrong bools act sometimes as true, but apparently constexpr evaluation does not trigger that.
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.
Maybe assert(bit_cast<char>(elem) == bit_cast<char>(bool(true))) ?
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.
Maybe
assert(bit_cast<char>(elem) == bit_cast<char>(bool(true)))?
These tests are not C++20 only so bit_cast is not always available.
I think it is still UB (expected behavior is a possible UB manifestation)
And even if it's UB it means that there's no reason for equal not to use memcmp for bool - not using memcmp in this case would only make sense if bit_cast<bool>((char)2) == true was always true and we know now that at least sometimes it's not.
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.
Also has_unique_object_representations_v<bool> is true which (I think) means that if two bools have different representations they must compare unequal.
|
Changed |
|
After doing some further investigation I discovered that comparing |
|
I think it's ready for review. |
Co-authored-by: Alex Guteniev <gutenev@gmail.com>
StephanTLavavej
left a comment
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! I think this product change is good (I thought really hard about the metaprogramming and couldn't find any ways for it to fail), although I have one concern about warnings (or the lack thereof) and minor test nitpicks.
I think this will be ready for final review after a quick revision.
|
It seems your formatting is behaving strangely |
For some reason visual studio didn't run clang-format automatically. |
|
Thanks for making our bitwise-equality optimizations a bit more effective! |
A small PR to optimize
(ranges::)(uninitialized_)fill(_n)when filling ranges ofboolor(signed|unsigned)char(8_t)with other scalar types. Part of #431.EDIT: Fixes #1183.