str/cexpr: Add a function to make a constexpr generated string
This allows the user to generate an arbitrary length string at compile
time and convert it automatically to an std::array that is embedded in
the program for zero overhead runtime strings.
Change-Id: Ib6c2dd20cac53bb55e7a32e2fca194bdf0e06211
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/include/meson.build b/include/meson.build
index dc4de82..c3bfdfe 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -10,6 +10,7 @@
'stdplus/raw.hpp',
'stdplus/signal.hpp',
'stdplus/str/cat.hpp',
+ 'stdplus/str/cexpr.hpp',
'stdplus/util/cexec.hpp',
'stdplus/util/string.hpp',
'stdplus/zstring.hpp',
diff --git a/include/stdplus/str/cexpr.hpp b/include/stdplus/str/cexpr.hpp
new file mode 100644
index 0000000..a3d5f1c
--- /dev/null
+++ b/include/stdplus/str/cexpr.hpp
@@ -0,0 +1,38 @@
+#pragma once
+#include <algorithm>
+#include <array>
+#include <string_view>
+
+namespace stdplus
+{
+
+template <auto f, bool nul>
+consteval auto cexprToStrArr()
+{
+ std::array<typename decltype(f())::value_type, f().size() + (nul ? 1 : 0)>
+ ret;
+ {
+ auto res = f();
+ std::copy(res.begin(), res.end(), ret.begin());
+ if constexpr (nul)
+ {
+ ret[ret.size() - 1] = '\0';
+ }
+ }
+ return ret;
+}
+
+template <auto f, bool nul>
+inline constexpr auto cexprStrArr = cexprToStrArr<f, nul>();
+
+template <auto f>
+consteval auto cexprToSv()
+{
+ constexpr auto& d = cexprStrArr<f, /*nul=*/false>;
+ return std::basic_string_view(d.begin(), d.end());
+}
+
+template <auto f>
+inline constexpr auto cexprSv = cexprToSv<f>();
+
+} // namespace stdplus
diff --git a/include/stdplus/zstring_view.hpp b/include/stdplus/zstring_view.hpp
index 79003bd..0c18bfb 100644
--- a/include/stdplus/zstring_view.hpp
+++ b/include/stdplus/zstring_view.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <fmt/core.h>
+#include <stdplus/str/cexpr.hpp>
#include <stdplus/zstring.hpp>
#include <stdexcept>
@@ -318,6 +319,19 @@
}
} // namespace zstring_view_literals
+template <auto f>
+consteval auto cexprToZsv()
+{
+ constexpr auto& d = cexprStrArr<f, /*nul=*/true>;
+ static_assert(detail::zstring_find_term(d.data(), d.size() - 1, d.size()) >=
+ 0);
+ return detail::unsafe_zstring_view(
+ std::basic_string_view(d.begin(), d.end() - 1));
+}
+
+template <auto f>
+inline constexpr auto cexprZsv = cexprToZsv<f>();
+
} // namespace stdplus
#define zstring_view_all(char_t, pfx) \
diff --git a/src/meson.build b/src/meson.build
index 2a08ac5..7c4dabf 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -51,6 +51,7 @@
'raw.cpp',
'signal.cpp',
'str/cat.cpp',
+ 'str/cexpr.cpp',
'util/cexec.cpp',
'zstring.cpp',
'zstring_view.cpp',
diff --git a/src/str/cexpr.cpp b/src/str/cexpr.cpp
new file mode 100644
index 0000000..b672808
--- /dev/null
+++ b/src/str/cexpr.cpp
@@ -0,0 +1 @@
+#include <stdplus/str/cexpr.hpp>
diff --git a/test/meson.build b/test/meson.build
index 2f1d7f9..901527d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -7,6 +7,7 @@
'raw': [stdplus_dep, gmock_dep, gtest_main_dep],
'signal': [stdplus_dep, gtest_main_dep],
'str/cat': [stdplus_dep, gtest_main_dep],
+ 'str/cexpr': [stdplus_dep, gtest_main_dep],
'util/cexec': [stdplus_dep, gtest_main_dep],
'zstring': [stdplus_dep, gtest_main_dep],
'zstring_view': [stdplus_dep, gtest_main_dep],
diff --git a/test/str/cexpr.cpp b/test/str/cexpr.cpp
new file mode 100644
index 0000000..557591c
--- /dev/null
+++ b/test/str/cexpr.cpp
@@ -0,0 +1,44 @@
+#include <stdplus/str/cexpr.hpp>
+#include <stdplus/zstring_view.hpp>
+
+#include <string>
+#include <string_view>
+
+#include <gtest/gtest.h>
+
+using namespace std::string_view_literals;
+using namespace std::string_literals;
+
+namespace stdplus
+{
+
+TEST(Constexpr, SvFromSv)
+{
+ EXPECT_EQ((std::array{'a', 'b', 'c', '\0'}),
+ (cexprStrArr<[]() { return "abc"sv; }, true>));
+ EXPECT_EQ((std::array{'a', 'b', 'c'}),
+ (cexprStrArr<[]() { return "abc"sv; }, false>));
+ EXPECT_EQ("abc"sv, cexprZsv<[]() { return "abc"sv; }>);
+ EXPECT_EQ("abc"sv, cexprSv<[]() { return "abc"sv; }>);
+}
+
+TEST(Constexpr, SvFromSmallStr)
+{
+ EXPECT_EQ((std::array{'a', 'b', 'c', '\0'}),
+ (cexprStrArr<[]() { return "abc"s; }, true>));
+ EXPECT_EQ((std::array{'a', 'b', 'c'}),
+ (cexprStrArr<[]() { return "abc"s; }, false>));
+ EXPECT_EQ("abc"sv, cexprSv<[]() { return "abc"s; }>);
+ EXPECT_EQ("abc"sv, cexprZsv<[]() { return "abc"s; }>);
+}
+
+TEST(Constexpr, SvFromAllocStr)
+{
+ constexpr auto cb = []() {
+ return "abcdefg"s.append("hijklmnopqrstuvwxyz"sv);
+ };
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyz"sv, cexprSv<cb>);
+ EXPECT_EQ("abcdefghijklmnopqrstuvwxyz"sv, cexprZsv<cb>);
+}
+
+} // namespace stdplus