]> granicus.if.org Git - llvm/commitdiff
[Support/Endian] Add support for endian-specific enums
authorPavel Labath <pavel@labath.sk>
Mon, 11 Mar 2019 09:06:18 +0000 (09:06 +0000)
committerPavel Labath <pavel@labath.sk>
Mon, 11 Mar 2019 09:06:18 +0000 (09:06 +0000)
Summary:
Binary formats often include various enumerations or bitsets, but using
endian-specific types for accessing them is tricky because they
currently only support integral types. This is particularly true for
scoped enums (enum class), as these are not implicitly convertible to
integral types, and so one has to perform two casts just to read the
enum value.

This fixes that support by adding first-class support for enumeration
types to endian-specific types. The support for them was already almost
working -- all I needed to do was overload getSwappedBytes for
enumeration types (which casts the enum to its underlying type and performs the
conversion there). I also add some convenience template aliases to simplify
declaring endian-specific enums.

Reviewers: Bigcheese, zturner

Subscribers: kristina, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59141

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355812 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/Endian.h
include/llvm/Support/SwapByteOrder.h
unittests/Support/EndianTest.cpp

index 5c1e89ae793643bf06396a88f5a927a0813d690d..d8be94427d7e5533f3cce7aaca2d2ba823f96675 100644 (file)
@@ -338,6 +338,17 @@ using unaligned_int32_t =
 using unaligned_int64_t =
     detail::packed_endian_specific_integral<int64_t, native, unaligned>;
 
+template <typename T>
+using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
+template <typename T>
+using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
+
+template <typename T>
+using aligned_little_t =
+    detail::packed_endian_specific_integral<T, little, aligned>;
+template <typename T>
+using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
+
 namespace endian {
 
 template <typename T> inline T read(const void *P, endianness E) {
index f58b4d911d4db959351dca3ba972cbb75cfd7086..380ca0a781f28c4001284248bc0ea752a6e25dfe 100644 (file)
@@ -115,6 +115,13 @@ inline double getSwappedBytes(double C) {
   return out.d;
 }
 
+template <typename T>
+inline typename std::enable_if<std::is_enum<T>::value, T>::type
+getSwappedBytes(T C) {
+  return static_cast<T>(
+      getSwappedBytes(static_cast<typename std::underlying_type<T>::type>(C)));
+}
+
 template<typename T>
 inline void swapByteOrder(T &Value) {
   Value = getSwappedBytes(Value);
index c2b292885377c1a27d143375b603a12e96a18d2d..b5e4a9c8d14a359fad11107a7f966ea1c162a2ff 100644 (file)
@@ -200,4 +200,13 @@ TEST(Endian, PackedEndianSpecificIntegral) {
   EXPECT_EQ(*big_val, *little_val);
 }
 
+TEST(Endian, PacketEndianSpecificIntegralAsEnum) {
+  enum class Test : uint16_t { ONETWO = 0x0102, TWOONE = 0x0201 };
+  unsigned char bytes[] = {0x01, 0x02};
+  using LittleTest = little_t<Test>;
+  using BigTest = big_t<Test>;
+  EXPECT_EQ(Test::TWOONE, *reinterpret_cast<LittleTest *>(bytes));
+  EXPECT_EQ(Test::ONETWO, *reinterpret_cast<BigTest *>(bytes));
+}
+
 } // end anon namespace