numeric/str: Add constexpr int decode

This makes it possible to convert strings to numbers in a constexpr
context.

Change-Id: I051ce8600b643533cc25a8de06e15c917db9fbd7
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/numeric/str.cpp b/test/numeric/str.cpp
index 008cbe5..cedc87c 100644
--- a/test/numeric/str.cpp
+++ b/test/numeric/str.cpp
@@ -4,6 +4,8 @@
 
 #include <gtest/gtest.h>
 
+using std::literals::string_view_literals::operator""sv;
+
 namespace stdplus
 {
 
@@ -100,4 +102,95 @@
     EXPECT_TRUE(false);
 }
 
+TEST(StrToInt, Uint8_10)
+{
+    StrToInt<10, uint8_t> dec;
+    EXPECT_EQ(42, dec("42"sv));
+    EXPECT_EQ(255, dec("255"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("-1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("a0"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("257"sv), std::overflow_error);
+    EXPECT_THROW(dec("300"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Uint8_11)
+{
+    StrToInt<11, uint8_t> dec;
+    EXPECT_EQ(112, dec("a2"sv));
+    EXPECT_EQ(255, dec("212"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("-1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("b0"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("213"sv), std::overflow_error);
+    EXPECT_THROW(dec("300"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Uint16_16)
+{
+    StrToInt<16, uint16_t> dec;
+    EXPECT_EQ(0x42, dec("42"sv));
+    EXPECT_EQ(0xfacf, dec("facf"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("-1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("g0"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("10000"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Uint16_8)
+{
+    StrToInt<8, uint16_t> dec;
+    EXPECT_EQ(042, dec("42"sv));
+    EXPECT_EQ(0177777, dec("177777"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("-1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("g0"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("277777"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Int8_16)
+{
+    StrToInt<16, int8_t> dec;
+    EXPECT_EQ(-1, dec("-1"sv));
+    EXPECT_EQ(0x42, dec("42"sv));
+    EXPECT_EQ(-0x7f, dec("-7f"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("--1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("g0"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("ff"sv), std::overflow_error);
+    EXPECT_THROW(dec("10000"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Int8_0)
+{
+    StrToInt<0, int8_t> dec;
+    EXPECT_EQ(-1, dec("-1"sv));
+    EXPECT_EQ(42, dec("42"sv));
+    EXPECT_EQ(0x42, dec("0x42"sv));
+    EXPECT_EQ(-42, dec("-42"sv));
+    EXPECT_EQ(-0x42, dec("-0x42"sv));
+    EXPECT_THROW(dec(""sv), std::invalid_argument);
+    EXPECT_THROW(dec("--1"sv), std::invalid_argument);
+    EXPECT_THROW(dec("ac"sv), std::invalid_argument);
+    EXPECT_THROW(dec(".0"sv), std::invalid_argument);
+    EXPECT_THROW(dec("0xff"sv), std::overflow_error);
+    EXPECT_THROW(dec("10000"sv), std::overflow_error);
+}
+
+TEST(StrToInt, Perf)
+{
+    GTEST_SKIP();
+    StrToInt<16, size_t> dec;
+    for (size_t i = 0; i < 100000000; ++i)
+    {
+        dec("53036893"sv);
+    }
+    EXPECT_TRUE(false);
+}
+
 } // namespace stdplus