-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Make use of bx::bit_cast #3212
Make use of bx::bit_cast #3212
Conversation
My suggestion is to reduce do smaller PR, where you use only For example, you can replace this inline uint32_t castfu(float _value)
{
union { float fl; uint32_t ui; } un;
un.fl = _value;
return un.ui;
} |
Sure yes, no worries. Let me know if the latest pushes are what you had in mind. |
examples/common/entry/entry_sdl.cpp
Outdated
@@ -830,7 +825,7 @@ namespace entry | |||
{ | |||
case SDL_USER_WINDOW_CREATE: | |||
{ | |||
WindowHandle handle = getWindowHandle(uev); | |||
WindowHandle handle = reinterpret_cast<WindowHandle>(_uev.data1); |
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 prefer you leave getWindowHandle instead this reinterpret_cast
. Basically ideally no reinterpret_cast
anywhere.
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.
Sure thing!
examples/common/entry/entry_sdl.cpp
Outdated
union { void* p; WindowHandle h; } cast; | ||
cast.h = _handle; | ||
uev.data1 = cast.p; | ||
uev.data1 = reinterpret_cast<void*>(_handle); |
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.
One benefit of union here is that type-safety will actually error if handle doesn't match. Where reinterpret_cast will just do whatever.
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.
You bring up an excellent point about the importance of type checking. It's crucial to ensure stability, especially in scenarios where _handle
might change its type unexpectedly. For instance, if the API were to transition WindowHandle
to an integer type like uint64_t
, it could lead to complications if the cast to void*
isn't adjusted accordingly.
I think we can enhance our type checking to be more robust and explicit by incorporating bx::isSame<Ty, Uy>()
. This approach emphasizes clarity and intentionality, making it easier to understand the expected behavior. I'll demonstrate this further with an example in an upcoming commit.
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.
In almost every use of reinterpret_cast
in your PR you're making code worse than before IMO. Not sure what's your goal here?!
examples/09-hdr/hdr.cpp
Outdated
union { uint32_t color; uint8_t bgra[4]; } cast = { m_lumBgra8 }; | ||
float exponent = cast.bgra[3]/255.0f * 255.0f - 128.0f; | ||
float lumAvg = cast.bgra[2]/255.0f * bx::exp2(exponent); | ||
struct packed { uint8_t bgra[4]; } arr = bx::bit_cast<packed>(m_lumBgra8); |
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 style is uppercase for struct/class, so Packed
.
|
||
cast.ptr = _thread->pop(); | ||
if (UINTPTR_MAX == cast.id) | ||
uintptr_t id = reinterpret_cast<uintptr_t>(_thread->pop()); |
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.
Still don't like reinterpret cast... This is not better than union thing.
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 should have probably marked the current this variable const
in the commit. The difference we'd have is that we can mark uintptr_t id
const, but not the same with union {} cast
.
examples/common/entry/entry_sdl.cpp
Outdated
union { void* p; WindowHandle h; } cast; | ||
cast.h = _handle; | ||
uev.data1 = cast.p; | ||
BX_STATIC_ASSERT((bx::isSame<WindowHandle, decltype(_handle)>()), "_handle must be of the type WindowHandle"); |
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.
This is getting more complicated than union cast 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.
This approach emphasizes clarity and intentionality, making it easier to understand the expected behavior.
The added type checking is a nice insurance policy in the event someone might inadvertently change the type of the input parameter. I wonder if we can get away with not having any such insurance policy, as it seems very likely that any type change to _handle
would force a rethink of what is being stored and retrieved from SDL_UserEvent.data1
..
examples/common/entry/entry_x11.cpp
Outdated
cast c; | ||
c.w = window; | ||
m_eventQueue.postWindowEvent(_handle, c.p); | ||
m_eventQueue.postWindowEvent(_handle, reinterpret_cast<void*>(window)); |
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.
Don't like reinterpret cast here.
src/renderer_d3d12.cpp
Outdated
@@ -2952,7 +2952,7 @@ namespace bgfx { namespace d3d12 | |||
|
|||
static void patchCb0(DxbcInstruction& _instruction, void* _userData) | |||
{ | |||
union { void* ptr; uint32_t offset; } cast = { _userData }; | |||
const uint32_t offset = uint32_t(reinterpret_cast<uintptr_t>(_userData)); |
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.
You need to realize that I consciously didn't want reinterpret_cast
when I wrote this code. I was aware that reinterpret_cast
exist before...
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 isn't something that appears super clear. As a reader, and user, I'm interpreting the usage as a reflex action (for example when we see the usage on line 3159), kind of like a C in C++ approach. Thank you for sharing your thought and decision process.
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.
Not sure what's your goal here?!
I had thought that the PR title and description were clear in stating the goal. Apologies if they haven't been clear enough.
I'll update this PR to reflect only the bx::bit_cast changes, as there seems to be a strong desire to maintain the stylistic choice of using unions for pointer to integer conversions.
examples/common/entry/entry_sdl.cpp
Outdated
union { void* p; WindowHandle h; } cast; | ||
cast.h = _handle; | ||
uev.data1 = cast.p; | ||
BX_STATIC_ASSERT((bx::isSame<WindowHandle, decltype(_handle)>()), "_handle must be of the type WindowHandle"); |
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.
This approach emphasizes clarity and intentionality, making it easier to understand the expected behavior.
The added type checking is a nice insurance policy in the event someone might inadvertently change the type of the input parameter. I wonder if we can get away with not having any such insurance policy, as it seems very likely that any type change to _handle
would force a rethink of what is being stored and retrieved from SDL_UserEvent.data1
..
src/renderer_d3d12.cpp
Outdated
@@ -2952,7 +2952,7 @@ namespace bgfx { namespace d3d12 | |||
|
|||
static void patchCb0(DxbcInstruction& _instruction, void* _userData) | |||
{ | |||
union { void* ptr; uint32_t offset; } cast = { _userData }; | |||
const uint32_t offset = uint32_t(reinterpret_cast<uintptr_t>(_userData)); |
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 isn't something that appears super clear. As a reader, and user, I'm interpreting the usage as a reflex action (for example when we see the usage on line 3159), kind of like a C in C++ approach. Thank you for sharing your thought and decision process.
|
||
cast.ptr = _thread->pop(); | ||
if (UINTPTR_MAX == cast.id) | ||
uintptr_t id = reinterpret_cast<uintptr_t>(_thread->pop()); |
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 should have probably marked the current this variable const
in the commit. The difference we'd have is that we can mark uintptr_t id
const, but not the same with union {} cast
.
…struct for arrays when necessary
…struct for arrays when necessary (bkaradzic#3212)
Use
bx::bit_cast()
where appropriate for type punning, and applying packed struct for arrays when necessary.bx::bit_cast()
is introduced in bkaradzic/bx#313 to address the similar issue of type punning inbx
(bkaradzic/bx#312).This PR also usesreinterpret_cast
for directvoid*
translations for integer handles.Withinrenderer_vk.cpp
, we remove the union when casting from void* to xcb_window_t, it isn't necessary.