pw_varint: Add EncodedSize function

This change adds functions to the varint module which return the size of
an integer when encoded as a varint.

Change-Id: I976e33835b1b6bece7ca586cd7f1c4d9ca17cdc8
diff --git a/pw_varint/docs.rst b/pw_varint/docs.rst
index 16c465b..49db88e 100644
--- a/pw_varint/docs.rst
+++ b/pw_varint/docs.rst
@@ -18,6 +18,18 @@
 * C
 * C++11 (with :doc:`../pw_polyfill/docs`)
 
+API
+===
+
+.. cpp:function:: size_t EncodedSize(uint64_t integer)
+
+Returns the size of an integer when encoded as a varint. Works on both signed
+and unsigned integers.
+
+.. cpp:function:: size_t ZigZagEncodedSize(int64_t integer)
+
+Returns the size of a signed integer when ZigZag encoded as a varint.
+
 Dependencies
 ============
 * ``pw_span``
diff --git a/pw_varint/public/pw_varint/varint.h b/pw_varint/public/pw_varint/varint.h
index 3bef687..b128bc0 100644
--- a/pw_varint/public/pw_varint/varint.h
+++ b/pw_varint/public/pw_varint/varint.h
@@ -32,6 +32,10 @@
                              size_t input_size,
                              int64_t* output);
 
+// Returns the size of an when encoded as a varint.
+size_t pw_VarintEncodedSize(uint64_t integer);
+size_t pw_VarintZigZagEncodedSize(int64_t integer);
+
 #ifdef __cplusplus
 
 }  // extern "C"
@@ -129,6 +133,16 @@
   return pw_VarintDecode(input.data(), input.size(), value);
 }
 
+// Returns a size of an integer when encoded as a varint.
+inline size_t EncodedSize(uint64_t integer) {
+  return pw_VarintEncodedSize(integer);
+}
+
+// Returns a size of an signed integer when ZigZag encoded as a varint.
+inline size_t ZigZagEncodedSize(int64_t integer) {
+  return pw_VarintZigZagEncodedSize(integer);
+}
+
 }  // namespace varint
 }  // namespace pw
 
diff --git a/pw_varint/varint.cc b/pw_varint/varint.cc
index ddfc0ed..9b782c0 100644
--- a/pw_varint/varint.cc
+++ b/pw_varint/varint.cc
@@ -83,5 +83,13 @@
   return bytes;
 }
 
+extern "C" size_t pw_VarintEncodedSize(uint64_t integer) {
+  return integer == 0 ? 1 : (64 - __builtin_clzll(integer) + 6) / 7;
+}
+
+extern "C" size_t pw_VarintZigZagEncodedSize(int64_t integer) {
+  return pw_VarintEncodedSize(ZigZagEncode(integer));
+}
+
 }  // namespace varint
 }  // namespace pw
diff --git a/pw_varint/varint_test.cc b/pw_varint/varint_test.cc
index 4e2efe2..eceaeb7 100644
--- a/pw_varint/varint_test.cc
+++ b/pw_varint/varint_test.cc
@@ -780,5 +780,50 @@
             std::numeric_limits<int64_t>::max());
 }
 
+TEST(Varint, EncodedSize) {
+  EXPECT_EQ(EncodedSize(uint64_t(0u)), 1u);
+  EXPECT_EQ(EncodedSize(uint64_t(1u)), 1u);
+  EXPECT_EQ(EncodedSize(uint64_t(127u)), 1u);
+  EXPECT_EQ(EncodedSize(uint64_t(128u)), 2u);
+  EXPECT_EQ(EncodedSize(uint64_t(16383u)), 2u);
+  EXPECT_EQ(EncodedSize(uint64_t(16384u)), 3u);
+  EXPECT_EQ(EncodedSize(uint64_t(2097151u)), 3u);
+  EXPECT_EQ(EncodedSize(uint64_t(2097152u)), 4u);
+  EXPECT_EQ(EncodedSize(uint64_t(268435455u)), 4u);
+  EXPECT_EQ(EncodedSize(uint64_t(268435456u)), 5u);
+  EXPECT_EQ(EncodedSize(uint64_t(34359738367u)), 5u);
+  EXPECT_EQ(EncodedSize(uint64_t(34359738368u)), 6u);
+  EXPECT_EQ(EncodedSize(uint64_t(4398046511103u)), 6u);
+  EXPECT_EQ(EncodedSize(uint64_t(4398046511104u)), 7u);
+  EXPECT_EQ(EncodedSize(uint64_t(562949953421311u)), 7u);
+  EXPECT_EQ(EncodedSize(uint64_t(562949953421312u)), 8u);
+  EXPECT_EQ(EncodedSize(uint64_t(72057594037927935u)), 8u);
+  EXPECT_EQ(EncodedSize(uint64_t(72057594037927936u)), 9u);
+  EXPECT_EQ(EncodedSize(uint64_t(9223372036854775807u)), 9u);
+  EXPECT_EQ(EncodedSize(uint64_t(9223372036854775808u)), 10u);
+  EXPECT_EQ(EncodedSize(std::numeric_limits<uint64_t>::max()), 10u);
+  EXPECT_EQ(EncodedSize(std::numeric_limits<int64_t>::max()), 9u);
+  EXPECT_EQ(EncodedSize(int64_t(-1)), 10u);
+  EXPECT_EQ(EncodedSize(std::numeric_limits<int64_t>::min()), 10u);
+}
+
+TEST(Varint, ZigZagEncodedSize) {
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(0)), 1u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(-1)), 1u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(1)), 1u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(-64)), 1u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(-65)), 2u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(63)), 1u);
+  EXPECT_EQ(ZigZagEncodedSize(int64_t(64)), 2u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int8_t>::min()), 2u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int8_t>::max()), 2u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int16_t>::min()), 3u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int16_t>::max()), 3u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int32_t>::min()), 5u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int32_t>::max()), 5u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int64_t>::min()), 10u);
+  EXPECT_EQ(ZigZagEncodedSize(std::numeric_limits<int64_t>::max()), 10u);
+}
+
 }  // namespace
 }  // namespace pw::varint