-
Notifications
You must be signed in to change notification settings - Fork 6k
Add constexpr endianness utilities to fml #31118
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #include "flutter/fml/endianness.h" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #ifndef FLUTTER_FML_ENDIANNESS_H_ | ||
| #define FLUTTER_FML_ENDIANNESS_H_ | ||
|
|
||
| #include <cstdint> | ||
| #include <type_traits> | ||
| #if defined(_MSC_VER) | ||
| #include "intrin.h" | ||
| #endif | ||
|
|
||
| #include "flutter/fml/build_config.h" | ||
|
|
||
| // Compiler intrinsics for flipping endianness. | ||
| #define FML_BYTESWAP_16(n) __builtin_bswap16(n) | ||
| #define FML_BYTESWAP_32(n) __builtin_bswap32(n) | ||
| #define FML_BYTESWAP_64(n) __builtin_bswap64(n) | ||
|
|
||
| #if defined(_MSC_VER) | ||
| #define FML_BYTESWAP_16(n) _byteswap_ushort(n) | ||
| #define FML_BYTESWAP_32(n) _byteswap_ulong(n) | ||
| #define FML_BYTESWAP_64(n) _byteswap_uint64(n) | ||
| #endif | ||
|
|
||
| namespace fml { | ||
|
|
||
| /// @brief Flips the endianness of the given value. | ||
| /// The given value must be an integral type of size 1, 2, 4, or 8. | ||
| template <typename T, class = std::enable_if_t<std::is_integral_v<T>>> | ||
| constexpr T ByteSwap(T n) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using templating in C++, please be mindful of the error messages being generated. For instance, if I say One way to avoid this in the scheme you have devised would be to have restrictions on specialization. So, something like This makes the error move to the right spot. The compiler note will indicate why the specialization failed. Here, the error is in the right spot and the note indicates what the user must to do make the specialization work. BTW, the restriction may even avoid you needing the check for other zero sized typed and the whole static assert can be In case you want a link to the sandbox where you can experiment with templating and error messages. Another suggestion would be to just add explicit overloads for each integral type. I suppose that would work for ByteSwap but get tedious for Templating is really interesting and powerful but its easy to call it a day without paying sufficient attention to UX concerns around its use which gives the technique a worse rep than it perhaps deserves. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting! I haven't touched adding type restrictions like this, so this was illuminating. I added what you suggested here, but if you have a preference for adding overloads in this case, let me know and I'll do it (I don't have a strong opinion either way). |
||
| if constexpr (sizeof(T) == 1) { | ||
| return n; | ||
| } else if constexpr (sizeof(T) == 2) { | ||
| return (T)FML_BYTESWAP_16((uint16_t)n); | ||
| } else if constexpr (sizeof(T) == 4) { | ||
| return (T)FML_BYTESWAP_32((uint32_t)n); | ||
| } else if constexpr (sizeof(T) == 8) { | ||
| return (T)FML_BYTESWAP_64((uint64_t)n); | ||
| } else { | ||
| static_assert(!sizeof(T), "Unsupported size"); | ||
| } | ||
| } | ||
|
|
||
| /// @brief Convert a known big endian value to match the endianness of the | ||
| /// current architecture. This is effectively a cross platform | ||
| /// ntohl/ntohs (as network byte order is always Big Endian). | ||
| /// The given value must be an integral type of size 1, 2, 4, or 8. | ||
| template <typename T, class = std::enable_if_t<std::is_integral_v<T>>> | ||
| constexpr T BigEndianToArch(T n) { | ||
| #if ARCH_CPU_LITTLE_ENDIAN | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh. I didn't realize we had un-"namespaced" macros in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up patch incoming :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| return ByteSwap<T>(n); | ||
| #else | ||
| return n; | ||
| #endif | ||
| } | ||
|
|
||
| /// @brief Convert a known little endian value to match the endianness of the | ||
| /// current architecture. | ||
| /// The given value must be an integral type of size 1, 2, 4, or 8. | ||
| template <typename T, class = std::enable_if_t<std::is_integral_v<T>>> | ||
| constexpr T LittleEndianToArch(T n) { | ||
| #if !ARCH_CPU_LITTLE_ENDIAN | ||
| return ByteSwap<T>(n); | ||
| #else | ||
| return n; | ||
| #endif | ||
| } | ||
|
|
||
| } // namespace fml | ||
|
|
||
| #endif // FLUTTER_FML_ENDIANNESS_H_ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #include "flutter/fml/endianness.h" | ||
|
|
||
| #include "flutter/testing/testing.h" | ||
|
|
||
| namespace fml { | ||
| namespace testing { | ||
|
|
||
| TEST(EndiannessTest, ByteSwap) { | ||
| ASSERT_EQ(ByteSwap<int16_t>(0x1122), 0x2211); | ||
| ASSERT_EQ(ByteSwap<int32_t>(0x11223344), 0x44332211); | ||
| ASSERT_EQ(ByteSwap<uint64_t>(0x1122334455667788), 0x8877665544332211); | ||
| } | ||
|
|
||
| TEST(EndiannessTest, BigEndianToArch) { | ||
| #if ARCH_CPU_LITTLE_ENDIAN | ||
| uint32_t expected = 0x44332211; | ||
| #else | ||
| uint32_t expected = 0x11223344; | ||
| #endif | ||
| ASSERT_EQ(BigEndianToArch(0x11223344u), expected); | ||
| } | ||
|
|
||
| TEST(EndiannessTest, LittleEndianToArch) { | ||
| #if ARCH_CPU_LITTLE_ENDIAN | ||
| uint32_t expected = 0x11223344; | ||
| #else | ||
| uint32_t expected = 0x44332211; | ||
| #endif | ||
| ASSERT_EQ(LittleEndianToArch(0x11223344u), expected); | ||
| } | ||
|
|
||
| } // namespace testing | ||
| } // namespace fml |


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.
Please add an empty
endianness.ccthat only includeendianness.h. That is a good way to check that the header can always be included cleanly.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.