Browse Source

MACAddress: constexpr support

Problem:
- `MACAddress` class is not usable in a compile-time context.
- `__builtin_memcpy` is not constexpr in gcc.

Solution:
- Decorate functions with `constexpr` keyword.
- Use default constructors and destructors.
- Change `__builtin_memcpy` to a hand-written `for` loop and let the
  compiler's optimizer take care of it.
- Add tests to ensure compile-time capabilities.
Lenny Maiorani 4 years ago
parent
commit
964d2e0dd0
2 changed files with 41 additions and 16 deletions
  1. 13 8
      AK/MACAddress.h
  2. 28 8
      AK/Tests/TestMACAddress.cpp

+ 13 - 8
AK/MACAddress.h

@@ -33,12 +33,16 @@
 class [[gnu::packed]] MACAddress
 {
 public:
-    MACAddress() { }
-    MACAddress(const u8 data[6])
+    constexpr MACAddress() = default;
+
+    constexpr MACAddress(const u8 data[6])
     {
-        __builtin_memcpy(m_data, data, 6);
+        for (auto i = 0u; i < sizeof(m_data); ++i) {
+            m_data[i] = data[i];
+        }
     }
-    MACAddress(u8 a, u8 b, u8 c, u8 d, u8 e, u8 f)
+
+    constexpr MACAddress(u8 a, u8 b, u8 c, u8 d, u8 e, u8 f)
     {
         m_data[0] = a;
         m_data[1] = b;
@@ -47,15 +51,16 @@ public:
         m_data[4] = e;
         m_data[5] = f;
     }
-    ~MACAddress() { }
 
-    u8 operator[](int i) const
+    constexpr ~MACAddress() = default;
+
+    constexpr u8 operator[](int i) const
     {
         ASSERT(i >= 0 && i < 6);
         return m_data[i];
     }
 
-    bool operator==(const MACAddress& other) const
+    constexpr bool operator==(const MACAddress& other) const
     {
         return !__builtin_memcmp(m_data, other.m_data, sizeof(m_data));
     }
@@ -65,7 +70,7 @@ public:
         return String::formatted("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", m_data[0], m_data[1], m_data[2], m_data[3], m_data[4], m_data[5]);
     }
 
-    bool is_zero() const
+    constexpr bool is_zero() const
     {
         return m_data[0] == 0 && m_data[1] == 0 && m_data[2] == 0 && m_data[3] == 0 && m_data[4] == 0 && m_data[5] == 0;
     }

+ 28 - 8
AK/Tests/TestMACAddress.cpp

@@ -31,32 +31,48 @@
 
 TEST_CASE(should_default_construct)
 {
-    MACAddress sut {};
+    constexpr MACAddress sut {};
+    static_assert(sut.is_zero());
     EXPECT(sut.is_zero());
 }
 
 TEST_CASE(should_braces_construct)
 {
-    MACAddress sut { 1, 2, 3, 4, 5, 6 };
+    constexpr MACAddress sut { 1, 2, 3, 4, 5, 6 };
+    static_assert(!sut.is_zero());
     EXPECT(!sut.is_zero());
 }
 
 TEST_CASE(should_construct_from_c_array)
 {
-    u8 addr[6] = { 1, 2, 3, 4, 5, 6 };
-    MACAddress sut(addr);
+    constexpr u8 addr[6] = { 1, 2, 3, 4, 5, 6 };
+    constexpr MACAddress sut(addr);
+    static_assert(!sut.is_zero());
     EXPECT(!sut.is_zero());
 }
 
 TEST_CASE(should_construct_from_6_octets)
 {
-    MACAddress sut(1, 2, 3, 4, 5, 6);
+    constexpr MACAddress sut(1, 2, 3, 4, 5, 6);
+    static_assert(!sut.is_zero());
     EXPECT(!sut.is_zero());
 }
 
 TEST_CASE(should_provide_access_to_octet_by_index)
 {
-    MACAddress sut(1, 2, 3, 4, 5, 6);
+    constexpr auto is_all_expected = [](auto& sut) {
+        for (auto i = 0u; i < sizeof(MACAddress); ++i) {
+            if (sut[i] != i + 1) {
+                return false;
+            }
+        }
+        return true;
+    };
+
+    constexpr MACAddress sut(1, 2, 3, 4, 5, 6);
+
+    static_assert(is_all_expected(sut));
+
     for (auto i = 0u; i < sizeof(MACAddress); ++i) {
         EXPECT_EQ(i + 1, sut[i]);
     }
@@ -64,8 +80,12 @@ TEST_CASE(should_provide_access_to_octet_by_index)
 
 TEST_CASE(should_equality_compare)
 {
-    MACAddress a(1, 2, 3, 4, 5, 6);
-    MACAddress b(1, 2, 3, 42, 5, 6);
+    constexpr MACAddress a(1, 2, 3, 4, 5, 6);
+    constexpr MACAddress b(1, 2, 3, 42, 5, 6);
+
+    static_assert(a == a);
+    static_assert(a != b);
+
     EXPECT(a == a);
     EXPECT(a != b);
 }