types: Add constexpr int encoder

Change-Id: I4a3117f442c5a829faffbb5897eb2a0ea013f63a
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/types.hpp b/src/types.hpp
index 73d2778..4bbff0d 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -198,7 +198,19 @@
     }
     return ret;
 }();
-}
+inline constexpr auto intLookup = []() {
+    std::array<char, 36> ret;
+    for (int8_t i = 0; i < 10; ++i)
+    {
+        ret[i] = i + '0';
+    }
+    for (int8_t i = 0; i < 26; ++i)
+    {
+        ret[i + 10] = i + 'a';
+    }
+    return ret;
+}();
+} // namespace detail
 
 template <typename T, uint8_t base>
 struct DecodeInt
@@ -249,6 +261,59 @@
     }
 };
 
+template <typename T, uint8_t base>
+struct EncodeInt
+{
+    static_assert(base > 1 && base <= 36);
+    static_assert(std::is_unsigned_v<T>);
+
+    static constexpr uint8_t buf_size = []() {
+        T v = std::numeric_limits<T>::max();
+        uint8_t i = 0;
+        for (; v != 0; ++i)
+        {
+            v /= base;
+        }
+        return i;
+    }();
+    using buf_type = std::array<char, buf_size>;
+
+    constexpr uint8_t reverseFill(char* buf, T v) const noexcept
+    {
+        uint8_t i = 0;
+        do
+        {
+            if constexpr (std::popcount(base) == 1)
+            {
+                buf[i++] = detail::intLookup[v & 0xf];
+                v >>= 4;
+            }
+            else
+            {
+                buf[i++] = detail::intLookup[v % base];
+                v /= base;
+            }
+        } while (v > 0);
+        return i;
+    }
+
+    constexpr char* operator()(char* buf, T v) const noexcept
+    {
+        uint8_t i = reverseFill(buf, v);
+        std::reverse(buf, buf + i);
+        return buf + i;
+    }
+
+    constexpr char* operator()(char* buf, T v, uint8_t min_width) const noexcept
+    {
+        uint8_t i = reverseFill(buf, v);
+        auto end = buf + std::max(i, min_width);
+        std::fill(buf + i, end, '0');
+        std::reverse(buf, end);
+        return end;
+    }
+};
+
 template <typename T>
 struct ToAddr
 {