numeric/str: Add constexpr int encode

This makes it possible to quickly convert numbers to strings in
constexpr contexts.

Change-Id: I5a460feacf97c80761d02a3b07f5b22080401b45
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/test/meson.build b/test/meson.build
index 1239296..fd62657 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -10,6 +10,7 @@
   'net/addr/ip': [stdplus_dep, gtest_main_dep],
   'net/addr/subnet': [stdplus_dep, gtest_main_dep],
   'numeric/endian': [stdplus_dep, gtest_main_dep],
+  'numeric/str': [stdplus_dep, gtest_main_dep],
   'pinned': [stdplus_dep, gtest_main_dep],
   'raw': [stdplus_dep, gmock_dep, gtest_main_dep],
   'signal': [stdplus_dep, gtest_main_dep],
diff --git a/test/numeric/str.cpp b/test/numeric/str.cpp
new file mode 100644
index 0000000..5646045
--- /dev/null
+++ b/test/numeric/str.cpp
@@ -0,0 +1,103 @@
+#include <stdplus/numeric/str.hpp>
+
+#include <string_view>
+
+#include <gtest/gtest.h>
+
+namespace stdplus
+{
+
+TEST(IntToStr, Uint8_10)
+{
+    IntToStr<10, uint8_t> enc;
+    static_assert(enc.buf_size == 3);
+    char buf[enc.buf_size];
+    EXPECT_EQ("0", std::string_view(buf, enc(buf, 0)));
+    EXPECT_EQ("42", std::string_view(buf, enc(buf, 42)));
+    EXPECT_EQ("255", std::string_view(buf, enc(buf, 255)));
+    EXPECT_EQ("000", std::string_view(buf, enc(buf, 0, 3)));
+    EXPECT_EQ("255", std::string_view(buf, enc(buf, 255, 3)));
+}
+
+TEST(IntToStr, Int8_10)
+{
+    IntToStr<10, int8_t> enc;
+    static_assert(enc.buf_size == 4);
+    char buf[enc.buf_size];
+    EXPECT_EQ("42", std::string_view(buf, enc(buf, 42)));
+    EXPECT_EQ("-127", std::string_view(buf, enc(buf, -127)));
+}
+
+TEST(IntToStr, Uint16_10)
+{
+    IntToStr<10, uint16_t> enc;
+    static_assert(enc.buf_size == 5);
+    char buf[enc.buf_size];
+    EXPECT_EQ("55255", std::string_view(buf, enc(buf, 55255, 3)));
+}
+
+TEST(IntToStr, Uint32_10)
+{
+    IntToStr<10, uint32_t> enc;
+    static_assert(enc.buf_size == 10);
+    char buf[enc.buf_size];
+    EXPECT_EQ("55255", std::string_view(buf, enc(buf, 55255, 3)));
+    EXPECT_EQ("055255", std::string_view(buf, enc(buf, 55255, 6)));
+    EXPECT_EQ("255255", std::string_view(buf, enc(buf, 255255, 3)));
+}
+
+TEST(IntToStr, Uint8_16)
+{
+    IntToStr<16, uint8_t> enc;
+    static_assert(enc.buf_size == 2);
+    char buf[enc.buf_size];
+    EXPECT_EQ("0", std::string_view(buf, enc(buf, 0)));
+    EXPECT_EQ("2a", std::string_view(buf, enc(buf, 42)));
+    EXPECT_EQ("ff", std::string_view(buf, enc(buf, 255)));
+    EXPECT_EQ("00", std::string_view(buf, enc(buf, 0, 2)));
+    EXPECT_EQ("02", std::string_view(buf, enc(buf, 2, 2)));
+    EXPECT_EQ("ff", std::string_view(buf, enc(buf, 255, 2)));
+}
+
+TEST(IntToStr, Uint8_8)
+{
+    IntToStr<8, uint8_t> enc;
+    static_assert(enc.buf_size == 3);
+    char buf[enc.buf_size];
+    EXPECT_EQ("0", std::string_view(buf, enc(buf, 0)));
+    EXPECT_EQ("7", std::string_view(buf, enc(buf, 7)));
+    EXPECT_EQ("10", std::string_view(buf, enc(buf, 8)));
+    EXPECT_EQ("377", std::string_view(buf, enc(buf, 255)));
+}
+
+TEST(IntToStr, Uint8_11)
+{
+    IntToStr<11, uint8_t> enc;
+    static_assert(enc.buf_size == 3);
+    char buf[enc.buf_size];
+    EXPECT_EQ("0", std::string_view(buf, enc(buf, 0)));
+    EXPECT_EQ("39", std::string_view(buf, enc(buf, 42)));
+    EXPECT_EQ("212", std::string_view(buf, enc(buf, 255)));
+}
+
+TEST(ToString, Int)
+{
+    EXPECT_EQ("10", stdplus::toStr(size_t{10}));
+    EXPECT_EQ(L"10", stdplus::toBasicStr<wchar_t>(size_t{10}));
+    EXPECT_EQ("-10", stdplus::toStr(ssize_t{-10}));
+    EXPECT_EQ(L"-10", stdplus::toBasicStr<wchar_t>(ssize_t{-10}));
+}
+
+TEST(ToString, perf)
+{
+    GTEST_SKIP();
+    IntToStr<16, size_t> enc;
+    char buf[enc.buf_size];
+    for (size_t i = 0; i < 100000000; ++i)
+    {
+        enc(buf, i);
+    }
+    EXPECT_TRUE(false);
+}
+
+} // namespace stdplus