diff --git a/include/iris/string_algo.hpp b/include/iris/string_algo.hpp index f618d6e..bbbe214 100644 --- a/include/iris/string_algo.hpp +++ b/include/iris/string_algo.hpp @@ -270,6 +270,49 @@ template } +// Truncates the tail of the string to `max_length` while replacing the tail with +// `ellipsis` iff `input.size()` exceeded `max_length`. +template +constexpr void abbreviate( + std::basic_string& input, + std::size_t const max_length, + std::type_identity_t> ellipsis +) +{ + if (max_length < ellipsis.size()) { + throw std::length_error{"ellipsis' length is longer than max_length"}; + } + + if (input.size() > max_length) { + input.replace(max_length - ellipsis.size(), std::basic_string::npos, ellipsis); + } +} + +template +constexpr std::string abbreviate_copy( + std::string_view input, + std::size_t const max_length, + std::string_view ellipsis +) +{ + std::string buf(input); + iris::abbreviate(buf, max_length, ellipsis); + return buf; +} + +template +constexpr std::u32string abbreviate_copy( + std::u32string_view input, + std::size_t const max_length, + std::u32string_view ellipsis +) +{ + std::u32string buf(input); + iris::abbreviate(buf, max_length, ellipsis); + return buf; +} + + namespace detail { // Closed range [first, last] of character set diff --git a/test/string_algo.cpp b/test/string_algo.cpp index c62568d..a54a016 100644 --- a/test/string_algo.cpp +++ b/test/string_algo.cpp @@ -205,6 +205,31 @@ TEST_CASE("string_algo: escape") #undef IRIS_TEST_ESCAPE } + +TEST_CASE("string_algo: abbreviate") +{ +#ifdef _MSC_VER + SetConsoleOutputCP(CP_UTF8); +#endif + + { + std::string str; + iris::abbreviate(str, 3, "..."); + CHECK(str == ""sv); + } + + CHECK_THROWS_AS(iris::abbreviate_copy("", 2, "..."), std::length_error); + CHECK_THROWS_AS(iris::abbreviate_copy("aaaaaa", 2, "..."), std::length_error); + + CHECK(iris::abbreviate_copy("fo", 3, "...") == "fo"sv); + CHECK(iris::abbreviate_copy("foo", 3, "...") == "foo"sv); + CHECK(iris::abbreviate_copy("foob", 3, "...") == "..."sv); + + CHECK(iris::abbreviate_copy("foo", 4, "...") == "foo"sv); + CHECK(iris::abbreviate_copy("foob", 4, "...") == "foob"sv); + CHECK(iris::abbreviate_copy("fooba", 4, "...") == "f..."sv); +} + TEST_CASE("string_algo: ordinary_normalize") { #ifdef _MSC_VER