numeric/endian: Add packed integer endian types
This makes it trivial to write packed structs for wire level
serialization.
Change-Id: I117eb6a80494c3ddca2a6924fd76be7df7365228
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/stdplus/numeric/endian.hpp b/include/stdplus/numeric/endian.hpp
index 39487ac..0dcdfc6 100644
--- a/include/stdplus/numeric/endian.hpp
+++ b/include/stdplus/numeric/endian.hpp
@@ -167,4 +167,67 @@
return etoh<std::endian::big>(t);
}
+template <typename T, std::endian E>
+struct EndianPacked
+{
+ using value_type = T;
+
+ constexpr EndianPacked() noexcept = default;
+ constexpr EndianPacked(T t) noexcept
+ {
+ *this = t;
+ }
+ constexpr EndianPacked& operator=(T t) noexcept
+ {
+ data.n = htoe<E>(t);
+ return *this;
+ }
+
+ constexpr T value() const noexcept
+ {
+ return etoh<E>(data.n);
+ }
+
+ constexpr operator T() const noexcept
+ {
+ return value();
+ }
+
+ struct
+ {
+ T n;
+ } __attribute__((packed)) data;
+};
+
+using int8_ubt = EndianPacked<std::int8_t, std::endian::big>;
+using int16_ubt = EndianPacked<std::int16_t, std::endian::big>;
+using int32_ubt = EndianPacked<std::int32_t, std::endian::big>;
+using int64_ubt = EndianPacked<std::int64_t, std::endian::big>;
+
+using int8_ult = EndianPacked<std::int8_t, std::endian::little>;
+using int16_ult = EndianPacked<std::int16_t, std::endian::little>;
+using int32_ult = EndianPacked<std::int32_t, std::endian::little>;
+using int64_ult = EndianPacked<std::int64_t, std::endian::little>;
+
+using int8_unt = EndianPacked<std::int8_t, std::endian::big>;
+using int16_unt = EndianPacked<std::int16_t, std::endian::big>;
+using int32_unt = EndianPacked<std::int32_t, std::endian::big>;
+using int64_unt = EndianPacked<std::int64_t, std::endian::big>;
+
+using uint8_ubt = EndianPacked<std::uint8_t, std::endian::big>;
+using uint16_ubt = EndianPacked<std::uint16_t, std::endian::big>;
+using uint32_ubt = EndianPacked<std::uint32_t, std::endian::big>;
+using uint64_ubt = EndianPacked<std::uint64_t, std::endian::big>;
+
+using uint8_ult = EndianPacked<std::uint8_t, std::endian::little>;
+using uint16_ult = EndianPacked<std::uint16_t, std::endian::little>;
+using uint32_ult = EndianPacked<std::uint32_t, std::endian::little>;
+using uint64_ult = EndianPacked<std::uint64_t, std::endian::little>;
+
+using uint8_unt = EndianPacked<std::uint8_t, std::endian::big>;
+using uint16_unt = EndianPacked<std::uint16_t, std::endian::big>;
+using uint32_unt = EndianPacked<std::uint32_t, std::endian::big>;
+static_assert(alignof(uint32_unt) == 1);
+using uint64_unt = EndianPacked<std::uint64_t, std::endian::big>;
+
} // namespace stdplus
diff --git a/test/numeric/endian.cpp b/test/numeric/endian.cpp
index d8f2ae8..8160753 100644
--- a/test/numeric/endian.cpp
+++ b/test/numeric/endian.cpp
@@ -1,6 +1,7 @@
#include <stdplus/numeric/endian.hpp>
#include <array>
+#include <cstring>
#include <gtest/gtest.h>
@@ -21,4 +22,36 @@
EXPECT_EQ(40, ntoh(hton(40)));
}
+TEST(EndianPacked, Uint8)
+{
+ uint8_unt n = 0;
+ EXPECT_EQ(n.value(), 0);
+ EXPECT_EQ(n, 0);
+
+ n = 15;
+ EXPECT_EQ(n.value(), 15);
+ EXPECT_EQ(n, 15);
+}
+
+TEST(EndianPacked, Uint32)
+{
+ uint32_unt n = 0;
+ EXPECT_EQ(n.value(), 0);
+ EXPECT_EQ(n, 0);
+
+ n = 15;
+ EXPECT_EQ(n.value(), 15);
+ EXPECT_EQ(n, 15);
+}
+
+TEST(EndianPacked, ValidateUnderlying)
+{
+ uint32_ubt b(15);
+ uint32_ult l = {};
+ EXPECT_EQ(b, 15);
+ EXPECT_EQ(l, 0);
+ std::memcpy(&l, &b, sizeof(l));
+ EXPECT_EQ(0x0f000000, l);
+}
+
} // namespace stdplus