Skip to content

Commit e17ee4a

Browse files
authored
Add constexpr endianness utilities to fml (flutter#31118)
1 parent 312551e commit e17ee4a

File tree

5 files changed

+121
-0
lines changed

5 files changed

+121
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ FILE: ../../../flutter/fml/dart/dart_converter.h
177177
FILE: ../../../flutter/fml/delayed_task.cc
178178
FILE: ../../../flutter/fml/delayed_task.h
179179
FILE: ../../../flutter/fml/eintr_wrapper.h
180+
FILE: ../../../flutter/fml/endianness.cc
181+
FILE: ../../../flutter/fml/endianness.h
182+
FILE: ../../../flutter/fml/endianness_unittests.cc
180183
FILE: ../../../flutter/fml/file.cc
181184
FILE: ../../../flutter/fml/file.h
182185
FILE: ../../../flutter/fml/file_unittest.cc

fml/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ source_set("fml") {
2121
"delayed_task.cc",
2222
"delayed_task.h",
2323
"eintr_wrapper.h",
24+
"endianness.cc",
25+
"endianness.h",
2426
"file.cc",
2527
"file.h",
2628
"hash_combine.h",
@@ -268,6 +270,7 @@ if (enable_unittests) {
268270
"backtrace_unittests.cc",
269271
"base32_unittest.cc",
270272
"command_line_unittest.cc",
273+
"endianness_unittests.cc",
271274
"file_unittest.cc",
272275
"hash_combine_unittests.cc",
273276
"hex_codec_unittest.cc",

fml/endianness.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/fml/endianness.h"

fml/endianness.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FML_ENDIANNESS_H_
6+
#define FLUTTER_FML_ENDIANNESS_H_
7+
8+
#include <cstdint>
9+
#include <type_traits>
10+
#if defined(_MSC_VER)
11+
#include "intrin.h"
12+
#endif
13+
14+
#include "flutter/fml/build_config.h"
15+
16+
// Compiler intrinsics for flipping endianness.
17+
#define FML_BYTESWAP_16(n) __builtin_bswap16(n)
18+
#define FML_BYTESWAP_32(n) __builtin_bswap32(n)
19+
#define FML_BYTESWAP_64(n) __builtin_bswap64(n)
20+
21+
#if defined(_MSC_VER)
22+
#define FML_BYTESWAP_16(n) _byteswap_ushort(n)
23+
#define FML_BYTESWAP_32(n) _byteswap_ulong(n)
24+
#define FML_BYTESWAP_64(n) _byteswap_uint64(n)
25+
#endif
26+
27+
namespace fml {
28+
29+
/// @brief Flips the endianness of the given value.
30+
/// The given value must be an integral type of size 1, 2, 4, or 8.
31+
template <typename T, class = std::enable_if_t<std::is_integral_v<T>>>
32+
constexpr T ByteSwap(T n) {
33+
if constexpr (sizeof(T) == 1) {
34+
return n;
35+
} else if constexpr (sizeof(T) == 2) {
36+
return (T)FML_BYTESWAP_16((uint16_t)n);
37+
} else if constexpr (sizeof(T) == 4) {
38+
return (T)FML_BYTESWAP_32((uint32_t)n);
39+
} else if constexpr (sizeof(T) == 8) {
40+
return (T)FML_BYTESWAP_64((uint64_t)n);
41+
} else {
42+
static_assert(!sizeof(T), "Unsupported size");
43+
}
44+
}
45+
46+
/// @brief Convert a known big endian value to match the endianness of the
47+
/// current architecture. This is effectively a cross platform
48+
/// ntohl/ntohs (as network byte order is always Big Endian).
49+
/// The given value must be an integral type of size 1, 2, 4, or 8.
50+
template <typename T, class = std::enable_if_t<std::is_integral_v<T>>>
51+
constexpr T BigEndianToArch(T n) {
52+
#if ARCH_CPU_LITTLE_ENDIAN
53+
return ByteSwap<T>(n);
54+
#else
55+
return n;
56+
#endif
57+
}
58+
59+
/// @brief Convert a known little endian value to match the endianness of the
60+
/// current architecture.
61+
/// The given value must be an integral type of size 1, 2, 4, or 8.
62+
template <typename T, class = std::enable_if_t<std::is_integral_v<T>>>
63+
constexpr T LittleEndianToArch(T n) {
64+
#if !ARCH_CPU_LITTLE_ENDIAN
65+
return ByteSwap<T>(n);
66+
#else
67+
return n;
68+
#endif
69+
}
70+
71+
} // namespace fml
72+
73+
#endif // FLUTTER_FML_ENDIANNESS_H_

fml/endianness_unittests.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/fml/endianness.h"
6+
7+
#include "flutter/testing/testing.h"
8+
9+
namespace fml {
10+
namespace testing {
11+
12+
TEST(EndiannessTest, ByteSwap) {
13+
ASSERT_EQ(ByteSwap<int16_t>(0x1122), 0x2211);
14+
ASSERT_EQ(ByteSwap<int32_t>(0x11223344), 0x44332211);
15+
ASSERT_EQ(ByteSwap<uint64_t>(0x1122334455667788), 0x8877665544332211);
16+
}
17+
18+
TEST(EndiannessTest, BigEndianToArch) {
19+
#if ARCH_CPU_LITTLE_ENDIAN
20+
uint32_t expected = 0x44332211;
21+
#else
22+
uint32_t expected = 0x11223344;
23+
#endif
24+
ASSERT_EQ(BigEndianToArch(0x11223344u), expected);
25+
}
26+
27+
TEST(EndiannessTest, LittleEndianToArch) {
28+
#if ARCH_CPU_LITTLE_ENDIAN
29+
uint32_t expected = 0x11223344;
30+
#else
31+
uint32_t expected = 0x44332211;
32+
#endif
33+
ASSERT_EQ(LittleEndianToArch(0x11223344u), expected);
34+
}
35+
36+
} // namespace testing
37+
} // namespace fml

0 commit comments

Comments
 (0)