pw_varint: Expose zig-zag decoding
This change moves the ZigZagDecode function from varint.cc to varint.h
so that it is part of pw_varint's public interface.
Change-Id: I53a659f1e5c701465c277eab2082d57624c0e65c
diff --git a/pw_varint/public/pw_varint/varint.h b/pw_varint/public/pw_varint/varint.h
index 8d1995f..eab1b59 100644
--- a/pw_varint/public/pw_varint/varint.h
+++ b/pw_varint/public/pw_varint/varint.h
@@ -42,6 +42,14 @@
return (static_cast<U>(n) << 1) ^ static_cast<U>(n >> (sizeof(T) * 8 - 1));
}
+// ZigZag decodes a signed integer.
+template <typename T>
+constexpr std::make_signed_t<T> ZigZagDecode(T n) {
+ static_assert(std::is_unsigned<T>(),
+ "Zig-zag decoding is for unsigned integers");
+ return static_cast<std::make_signed_t<T>>((n >> 1) ^ (~(n & 1) + 1));
+}
+
// Encodes a uint64_t with Little-Endian Base 128 (LEB128) encoding.
size_t EncodeLittleEndianBase128(uint64_t integer,
const span<std::byte>& output);
diff --git a/pw_varint/varint.cc b/pw_varint/varint.cc
index 849d053..e9c5199 100644
--- a/pw_varint/varint.cc
+++ b/pw_varint/varint.cc
@@ -17,13 +17,6 @@
#include <algorithm>
namespace pw::varint {
-namespace {
-
-constexpr int64_t ZigZagDecode64(uint64_t n) {
- return static_cast<int64_t>((n >> 1) ^ (~(n & 1) + 1));
-}
-
-} // namespace
size_t EncodeLittleEndianBase128(uint64_t integer,
const span<std::byte>& output) {
@@ -44,7 +37,7 @@
size_t Decode(const span<const std::byte>& input, int64_t* value) {
const size_t bytes = Decode(input, reinterpret_cast<uint64_t*>(value));
- *value = ZigZagDecode64(*value);
+ *value = ZigZagDecode(static_cast<uint64_t>(*value));
return bytes;
}
diff --git a/pw_varint/varint_test.cc b/pw_varint/varint_test.cc
index 54a0966..c50df32 100644
--- a/pw_varint/varint_test.cc
+++ b/pw_varint/varint_test.cc
@@ -305,5 +305,144 @@
EXPECT_EQ(value, std::numeric_limits<int64_t>::max());
}
+TEST(Varint, ZigZagEncode_Int8) {
+ EXPECT_EQ(ZigZagEncode(int8_t(0)), uint8_t(0));
+ EXPECT_EQ(ZigZagEncode(int8_t(-1)), uint8_t(1));
+ EXPECT_EQ(ZigZagEncode(int8_t(1)), uint8_t(2));
+ EXPECT_EQ(ZigZagEncode(int8_t(-2)), uint8_t(3));
+ EXPECT_EQ(ZigZagEncode(int8_t(2)), uint8_t(4));
+ EXPECT_EQ(ZigZagEncode(int8_t(-33)), uint8_t(65));
+ EXPECT_EQ(ZigZagEncode(int8_t(33)), uint8_t(66));
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int8_t>::min()),
+ std::numeric_limits<uint8_t>::max());
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int8_t>::max()),
+ std::numeric_limits<uint8_t>::max() - 1u);
+}
+
+TEST(Varint, ZigZagEncode_Int16) {
+ EXPECT_EQ(ZigZagEncode(int16_t(0)), uint16_t(0));
+ EXPECT_EQ(ZigZagEncode(int16_t(-1)), uint16_t(1));
+ EXPECT_EQ(ZigZagEncode(int16_t(1)), uint16_t(2));
+ EXPECT_EQ(ZigZagEncode(int16_t(-2)), uint16_t(3));
+ EXPECT_EQ(ZigZagEncode(int16_t(2)), uint16_t(4));
+ EXPECT_EQ(ZigZagEncode(int16_t(-3333)), uint16_t(6665));
+ EXPECT_EQ(ZigZagEncode(int16_t(3333)), uint16_t(6666));
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int16_t>::min()),
+ std::numeric_limits<uint16_t>::max());
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int16_t>::max()),
+ std::numeric_limits<uint16_t>::max() - 1u);
+}
+
+TEST(Varint, ZigZagEncode_Int32) {
+ EXPECT_EQ(ZigZagEncode(int32_t(0)), uint32_t(0));
+ EXPECT_EQ(ZigZagEncode(int32_t(-1)), uint32_t(1));
+ EXPECT_EQ(ZigZagEncode(int32_t(1)), uint32_t(2));
+ EXPECT_EQ(ZigZagEncode(int32_t(-2)), uint32_t(3));
+ EXPECT_EQ(ZigZagEncode(int32_t(2)), uint32_t(4));
+ EXPECT_EQ(ZigZagEncode(int32_t(-128)), uint32_t(255));
+ EXPECT_EQ(ZigZagEncode(int32_t(128)), uint32_t(256));
+ EXPECT_EQ(ZigZagEncode(int32_t(-333333)), uint32_t(666665));
+ EXPECT_EQ(ZigZagEncode(int32_t(333333)), uint32_t(666666));
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int32_t>::min()),
+ std::numeric_limits<uint32_t>::max());
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int32_t>::max()),
+ std::numeric_limits<uint32_t>::max() - 1u);
+}
+
+TEST(Varint, ZigZagEncode_Int64) {
+ EXPECT_EQ(ZigZagEncode(int64_t(0)), uint64_t(0));
+ EXPECT_EQ(ZigZagEncode(int64_t(-1)), uint64_t(1));
+ EXPECT_EQ(ZigZagEncode(int64_t(1)), uint64_t(2));
+ EXPECT_EQ(ZigZagEncode(int64_t(-2)), uint64_t(3));
+ EXPECT_EQ(ZigZagEncode(int64_t(2)), uint64_t(4));
+ EXPECT_EQ(ZigZagEncode(int64_t(-3333333333)), uint64_t(6666666665));
+ EXPECT_EQ(ZigZagEncode(int64_t(3333333333)), uint64_t(6666666666));
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int64_t>::min()),
+ std::numeric_limits<uint64_t>::max());
+ EXPECT_EQ(ZigZagEncode(std::numeric_limits<int64_t>::max()),
+ std::numeric_limits<uint64_t>::max() - 1u);
+}
+
+TEST(Varint, ZigZagDecode_Int8) {
+ EXPECT_EQ(ZigZagDecode(uint8_t(0)), int8_t(0));
+ EXPECT_EQ(ZigZagDecode(uint8_t(1)), int8_t(-1));
+ EXPECT_EQ(ZigZagDecode(uint8_t(2)), int8_t(1));
+ EXPECT_EQ(ZigZagDecode(uint8_t(3)), int8_t(-2));
+ EXPECT_EQ(ZigZagDecode(uint8_t(4)), int8_t(2));
+ EXPECT_EQ(ZigZagDecode(uint8_t(65)), int8_t(-33));
+ EXPECT_EQ(ZigZagDecode(uint8_t(66)), int8_t(33));
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint8_t>::max()),
+ std::numeric_limits<int8_t>::min());
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint8_t>::max() - 1u),
+ std::numeric_limits<int8_t>::max());
+}
+
+TEST(Varint, ZigZagDecode_Int16) {
+ EXPECT_EQ(ZigZagDecode(uint16_t(0)), int16_t(0));
+ EXPECT_EQ(ZigZagDecode(uint16_t(1)), int16_t(-1));
+ EXPECT_EQ(ZigZagDecode(uint16_t(2)), int16_t(1));
+ EXPECT_EQ(ZigZagDecode(uint16_t(3)), int16_t(-2));
+ EXPECT_EQ(ZigZagDecode(uint16_t(4)), int16_t(2));
+ EXPECT_EQ(ZigZagDecode(uint16_t(6665)), int16_t(-3333));
+ EXPECT_EQ(ZigZagDecode(uint16_t(6666)), int16_t(3333));
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint16_t>::max()),
+ std::numeric_limits<int16_t>::min());
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint16_t>::max() - 1u),
+ std::numeric_limits<int16_t>::max());
+}
+
+TEST(Varint, ZigZagDecode_Int32) {
+ EXPECT_EQ(ZigZagDecode(uint32_t(0)), int32_t(0));
+ EXPECT_EQ(ZigZagDecode(uint32_t(1)), int32_t(-1));
+ EXPECT_EQ(ZigZagDecode(uint32_t(2)), int32_t(1));
+ EXPECT_EQ(ZigZagDecode(uint32_t(3)), int32_t(-2));
+ EXPECT_EQ(ZigZagDecode(uint32_t(4)), int32_t(2));
+ EXPECT_EQ(ZigZagDecode(uint32_t(255)), int32_t(-128));
+ EXPECT_EQ(ZigZagDecode(uint32_t(256)), int32_t(128));
+ EXPECT_EQ(ZigZagDecode(uint32_t(666665)), int32_t(-333333));
+ EXPECT_EQ(ZigZagDecode(uint32_t(666666)), int32_t(333333));
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint32_t>::max()),
+ std::numeric_limits<int32_t>::min());
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint32_t>::max() - 1u),
+ std::numeric_limits<int32_t>::max());
+}
+
+TEST(Varint, ZigZagDecode_Int64) {
+ EXPECT_EQ(ZigZagDecode(uint64_t(0)), int64_t(0));
+ EXPECT_EQ(ZigZagDecode(uint64_t(1)), int64_t(-1));
+ EXPECT_EQ(ZigZagDecode(uint64_t(2)), int64_t(1));
+ EXPECT_EQ(ZigZagDecode(uint64_t(3)), int64_t(-2));
+ EXPECT_EQ(ZigZagDecode(uint64_t(4)), int64_t(2));
+ EXPECT_EQ(ZigZagDecode(uint64_t(6666666665)), int64_t(-3333333333));
+ EXPECT_EQ(ZigZagDecode(uint64_t(6666666666)), int64_t(3333333333));
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint64_t>::max()),
+ std::numeric_limits<int64_t>::min());
+ EXPECT_EQ(ZigZagDecode(std::numeric_limits<uint64_t>::max() - 1llu),
+ std::numeric_limits<int64_t>::max());
+}
+
+TEST(Varint, ZigZagEncodeDecode) {
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(0)), 0);
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(1)), 1);
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(-1)), -1);
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(8675309)), 8675309);
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int8_t>::min())),
+ std::numeric_limits<int8_t>::min());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int8_t>::max())),
+ std::numeric_limits<int8_t>::max());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int16_t>::min())),
+ std::numeric_limits<int16_t>::min());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int16_t>::max())),
+ std::numeric_limits<int16_t>::max());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int32_t>::min())),
+ std::numeric_limits<int32_t>::min());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int32_t>::max())),
+ std::numeric_limits<int32_t>::max());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int64_t>::min())),
+ std::numeric_limits<int64_t>::min());
+ EXPECT_EQ(ZigZagDecode(ZigZagEncode(std::numeric_limits<int64_t>::max())),
+ std::numeric_limits<int64_t>::max());
+}
+
} // namespace
} // namespace pw::varint