Loading include/ftl/concat.h +3 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ namespace android::ftl { // Lightweight (not allocating nor sprintf-based) concatenation. // Lightweight (not allocating nor sprintf-based) concatenation. The variadic arguments can be // values of integral type (including bool and char), string literals, or strings whose length // is constrained: // // std::string_view name = "Volume"; // ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); Loading include/ftl/details/concat.h +32 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <functional> #include <string_view> #include <ftl/details/type_traits.h> #include <ftl/string.h> namespace android::ftl::details { Loading @@ -26,16 +27,42 @@ namespace android::ftl::details { template <typename T, typename = void> struct StaticString; // Booleans. template <typename T> struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> { static constexpr std::size_t N = to_chars_length_v<T>; struct StaticString<T, std::enable_if_t<is_bool_v<T>>> { static constexpr std::size_t N = 5; // Length of "false". explicit StaticString(T v) : view(to_chars(buffer, v)) {} explicit constexpr StaticString(bool b) : view(b ? "true" : "false") {} to_chars_buffer_t<T> buffer; const std::string_view view; }; // Characters. template <typename T> struct StaticString<T, std::enable_if_t<is_char_v<T>>> { static constexpr std::size_t N = 1; explicit constexpr StaticString(char c) : character(c) {} const char character; const std::string_view view{&character, 1u}; }; // Integers, including the integer value of other character types like char32_t. template <typename T> struct StaticString< T, std::enable_if_t<std::is_integral_v<remove_cvref_t<T>> && !is_bool_v<T> && !is_char_v<T>>> { using U = remove_cvref_t<T>; static constexpr std::size_t N = to_chars_length_v<U>; // TODO: Mark this and to_chars as `constexpr` in C++23. explicit StaticString(U v) : view(to_chars(buffer, v)) {} to_chars_buffer_t<U> buffer; const std::string_view view; }; // Character arrays. template <std::size_t M> struct StaticString<const char (&)[M], void> { static constexpr std::size_t N = M - 1; Loading @@ -50,6 +77,7 @@ struct Truncated { std::string_view view; }; // Strings with constrained length. template <std::size_t M> struct StaticString<Truncated<M>, void> { static constexpr std::size_t N = M; Loading include/ftl/details/type_traits.h +6 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,10 @@ namespace android::ftl::details { template <typename U> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; template <typename T> constexpr bool is_bool_v = std::is_same_v<remove_cvref_t<T>, bool>; template <typename T> constexpr bool is_char_v = std::is_same_v<remove_cvref_t<T>, char>; } // namespace android::ftl::details libs/ftl/concat_test.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -28,8 +28,25 @@ TEST(Concat, Example) { EXPECT_EQ(string.c_str()[string.size()], '\0'); } TEST(Concat, Characters) { EXPECT_EQ(ftl::Concat(u'a', ' ', U'b').str(), "97 98"); } TEST(Concat, References) { int i[] = {-1, 2}; unsigned u = 3; EXPECT_EQ(ftl::Concat(i[0], std::as_const(i[1]), u).str(), "-123"); const bool b = false; const char c = 'o'; EXPECT_EQ(ftl::Concat(b, "tt", c).str(), "falsetto"); } namespace { static_assert(ftl::Concat{true, false, true}.str() == "truefalsetrue"); static_assert(ftl::Concat{':', '-', ')'}.str() == ":-)"); static_assert(ftl::Concat{"foo"}.str() == "foo"); static_assert(ftl::Concat{ftl::truncated<3>("foobar")}.str() == "foo"); Loading Loading
include/ftl/concat.h +3 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ namespace android::ftl { // Lightweight (not allocating nor sprintf-based) concatenation. // Lightweight (not allocating nor sprintf-based) concatenation. The variadic arguments can be // values of integral type (including bool and char), string literals, or strings whose length // is constrained: // // std::string_view name = "Volume"; // ftl::Concat string(ftl::truncated<3>(name), ": ", -3, " dB"); Loading
include/ftl/details/concat.h +32 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <functional> #include <string_view> #include <ftl/details/type_traits.h> #include <ftl/string.h> namespace android::ftl::details { Loading @@ -26,16 +27,42 @@ namespace android::ftl::details { template <typename T, typename = void> struct StaticString; // Booleans. template <typename T> struct StaticString<T, std::enable_if_t<std::is_integral_v<T>>> { static constexpr std::size_t N = to_chars_length_v<T>; struct StaticString<T, std::enable_if_t<is_bool_v<T>>> { static constexpr std::size_t N = 5; // Length of "false". explicit StaticString(T v) : view(to_chars(buffer, v)) {} explicit constexpr StaticString(bool b) : view(b ? "true" : "false") {} to_chars_buffer_t<T> buffer; const std::string_view view; }; // Characters. template <typename T> struct StaticString<T, std::enable_if_t<is_char_v<T>>> { static constexpr std::size_t N = 1; explicit constexpr StaticString(char c) : character(c) {} const char character; const std::string_view view{&character, 1u}; }; // Integers, including the integer value of other character types like char32_t. template <typename T> struct StaticString< T, std::enable_if_t<std::is_integral_v<remove_cvref_t<T>> && !is_bool_v<T> && !is_char_v<T>>> { using U = remove_cvref_t<T>; static constexpr std::size_t N = to_chars_length_v<U>; // TODO: Mark this and to_chars as `constexpr` in C++23. explicit StaticString(U v) : view(to_chars(buffer, v)) {} to_chars_buffer_t<U> buffer; const std::string_view view; }; // Character arrays. template <std::size_t M> struct StaticString<const char (&)[M], void> { static constexpr std::size_t N = M - 1; Loading @@ -50,6 +77,7 @@ struct Truncated { std::string_view view; }; // Strings with constrained length. template <std::size_t M> struct StaticString<Truncated<M>, void> { static constexpr std::size_t N = M; Loading
include/ftl/details/type_traits.h +6 −0 Original line number Diff line number Diff line Loading @@ -24,4 +24,10 @@ namespace android::ftl::details { template <typename U> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>; template <typename T> constexpr bool is_bool_v = std::is_same_v<remove_cvref_t<T>, bool>; template <typename T> constexpr bool is_char_v = std::is_same_v<remove_cvref_t<T>, char>; } // namespace android::ftl::details
libs/ftl/concat_test.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -28,8 +28,25 @@ TEST(Concat, Example) { EXPECT_EQ(string.c_str()[string.size()], '\0'); } TEST(Concat, Characters) { EXPECT_EQ(ftl::Concat(u'a', ' ', U'b').str(), "97 98"); } TEST(Concat, References) { int i[] = {-1, 2}; unsigned u = 3; EXPECT_EQ(ftl::Concat(i[0], std::as_const(i[1]), u).str(), "-123"); const bool b = false; const char c = 'o'; EXPECT_EQ(ftl::Concat(b, "tt", c).str(), "falsetto"); } namespace { static_assert(ftl::Concat{true, false, true}.str() == "truefalsetrue"); static_assert(ftl::Concat{':', '-', ')'}.str() == ":-)"); static_assert(ftl::Concat{"foo"}.str() == "foo"); static_assert(ftl::Concat{ftl::truncated<3>("foobar")}.str() == "foo"); Loading