diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 536c859585413..a43d07e1c31fc 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -176,6 +176,9 @@ FILE: ../../../flutter/fml/dart/dart_converter.h FILE: ../../../flutter/fml/delayed_task.cc FILE: ../../../flutter/fml/delayed_task.h FILE: ../../../flutter/fml/eintr_wrapper.h +FILE: ../../../flutter/fml/endianness.cc +FILE: ../../../flutter/fml/endianness.h +FILE: ../../../flutter/fml/endianness_unittests.cc FILE: ../../../flutter/fml/file.cc FILE: ../../../flutter/fml/file.h FILE: ../../../flutter/fml/file_unittest.cc diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 1f764cea4b6f7..39610f6aa5613 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -21,6 +21,8 @@ source_set("fml") { "delayed_task.cc", "delayed_task.h", "eintr_wrapper.h", + "endianness.cc", + "endianness.h", "file.cc", "file.h", "hash_combine.h", @@ -268,6 +270,7 @@ if (enable_unittests) { "backtrace_unittests.cc", "base32_unittest.cc", "command_line_unittest.cc", + "endianness_unittests.cc", "file_unittest.cc", "hash_combine_unittests.cc", "hex_codec_unittest.cc", diff --git a/fml/endianness.cc b/fml/endianness.cc new file mode 100644 index 0000000000000..c7de7861f7ef6 --- /dev/null +++ b/fml/endianness.cc @@ -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" diff --git a/fml/endianness.h b/fml/endianness.h new file mode 100644 index 0000000000000..4951f7c2edeaf --- /dev/null +++ b/fml/endianness.h @@ -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 +#include +#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 >> +constexpr T ByteSwap(T n) { + 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 >> +constexpr T BigEndianToArch(T n) { +#if ARCH_CPU_LITTLE_ENDIAN + return ByteSwap(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 >> +constexpr T LittleEndianToArch(T n) { +#if !ARCH_CPU_LITTLE_ENDIAN + return ByteSwap(n); +#else + return n; +#endif +} + +} // namespace fml + +#endif // FLUTTER_FML_ENDIANNESS_H_ diff --git a/fml/endianness_unittests.cc b/fml/endianness_unittests.cc new file mode 100644 index 0000000000000..24b35464e82bd --- /dev/null +++ b/fml/endianness_unittests.cc @@ -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(0x1122), 0x2211); + ASSERT_EQ(ByteSwap(0x11223344), 0x44332211); + ASSERT_EQ(ByteSwap(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