types: Add constexpr numeric decode

This will make it possible to implement constexpr address parsing.

Change-Id: I6fe5c8a8d517eb86f3596be1ecd50b98c5347e51
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/types.hpp b/src/types.hpp
index f1f2179..2bd895a 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -184,6 +184,73 @@
 
 namespace detail
 {
+inline constexpr auto charLookup = []() {
+    std::array<int8_t, 256> ret;
+    std::fill(ret.begin(), ret.end(), -1);
+    for (int8_t i = 0; i < 10; ++i)
+    {
+        ret[i + '0'] = i;
+    }
+    for (int8_t i = 0; i < 26; ++i)
+    {
+        ret[i + 'A'] = i + 10;
+        ret[i + 'a'] = i + 10;
+    }
+    return ret;
+}();
+}
+
+template <typename T, uint8_t base>
+struct DecodeInt
+{
+    static_assert(base > 1 && base <= 36);
+    static_assert(std::is_unsigned_v<T>);
+
+    constexpr T operator()(std::string_view str) const
+    {
+        if (str.empty())
+        {
+            throw std::invalid_argument("Empty Str");
+        }
+        constexpr auto max = std::numeric_limits<T>::max();
+        auto ret =
+            std::accumulate(str.begin(), str.end(), T{}, [&](T r, char c) {
+                auto v = detail::charLookup[c];
+                if (v < 0 || v >= base)
+                {
+                    throw std::invalid_argument("Invalid numeral");
+                }
+                if constexpr (std::popcount(base) == 1)
+                {
+                    constexpr auto shift = std::countr_zero(base);
+                    constexpr auto maxshift = max >> shift;
+                    if (r > maxshift)
+                    {
+                        throw std::overflow_error("Integer Decode");
+                    }
+                    return (r << shift) | v;
+                }
+                else
+                {
+                    constexpr auto maxbase = max / base;
+                    if (r > maxbase)
+                    {
+                        throw std::overflow_error("Integer Decode");
+                    }
+                    r *= base;
+                    if (max - v < r)
+                    {
+                        throw std::overflow_error("Integer Decode");
+                    }
+                    return r + v;
+                }
+            });
+        return ret;
+    }
+};
+
+namespace detail
+{
 
 template <typename T>
 constexpr bool vcontains() noexcept