diff --git a/data/doxygen.h b/data/doxygen.h index 8a1e016..1741c99 100644 --- a/data/doxygen.h +++ b/data/doxygen.h @@ -146,6 +146,11 @@ namespace gul17 { * * \section changelog_gul17 GUL17 Versions * + * \subsection UNRELEASED To be released + * + * - Add gul17::null_safe_string_view(const char*, std::size_t), which returns an empty + * string_view if given a null pointer. + * * \subsection V25_7_0 Version 25.7.0 * * - Add gul17::null_safe_string(const char*) and diff --git a/include/gul17/string_util.h b/include/gul17/string_util.h index b938f3c..43f7743 100644 --- a/include/gul17/string_util.h +++ b/include/gul17/string_util.h @@ -230,14 +230,14 @@ hex_string(const Container& container, std::string_view separator = "") * to find a zero-terminated C string and constructs a std::string from it. * * \code - * auto a = safe_string(nullptr); // a == ""s - * auto b = safe_string("ABC"); // b == "ABC"s - * auto c = safe_string("AB\0CD"); // c == "AB"s + * auto a = null_safe_string(nullptr); // a == ""s + * auto b = null_safe_string("ABC"); // b == "ABC"s + * auto c = null_safe_string("AB\0CD"); // c == "AB"s * \endcode * * \param char_ptr Pointer to a null-terminated string or a null pointer * - * \see safe_string(), null_safe_string_view() + * \see null_safe_string_view(), safe_string(), safe_string_view() * * \since version 25.7.0 */ @@ -245,26 +245,51 @@ GUL_EXPORT std::string null_safe_string(const char* char_ptr); /** - * Safely construct a string_view from a char pointer. + * Safely construct a string_view from a C string or a null pointer. * - * If the pointer is null, an empty string_view is constructed. Otherwise, the function + * If the pointer is null, an empty string_view is constructed. Otherwise, the function * assumes to find a zero-terminated C string and constructs a std::string_view from it. * * \code - * auto a = safe_string_view(nullptr); // a == ""sv - * auto b = safe_string_view("ABC"); // b == "ABC"sv - * auto c = safe_string_view("AB\0CD"); // c == "AB"sv + * auto a = null_safe_string_view(nullptr); // a == ""sv + * auto b = null_safe_string_view("ABC"); // b == "ABC"sv + * auto c = null_safe_string_view("AB\0CD"); // c == "AB"sv * \endcode * * \param char_ptr Pointer to a null-terminated string or a null pointer * - * \see safe_string_view(), null_safe_string() + * \see null_safe_string(), safe_string(), safe_string_view() * * \since version 25.7.0 */ GUL_EXPORT std::string_view null_safe_string_view(const char* char_ptr); +/** + * Safely construct a string_view from a char pointer and a length; intermediate null + * bytes do not terminate the string. + * + * If the pointer is null, an empty string_view is constructed. Otherwise, the function + * constructs a std::string_view with the specified length from it. Zero bytes in the + * input range do not terminate the string_view. + * + * \code + * auto a = null_safe_string_view(nullptr, 10); // a == ""sv + * auto b = null_safe_string_view("ABC", 4); // b == "ABC\0"sv + * auto c = null_safe_string_view("AB\0CD", 4); // c == "AB\0C"sv + * \endcode + * + * \param char_ptr Pointer to a string with at least \c length accessible bytes, or a + * null pointer + * \param length Length of the generated string_view (unless the pointer is null) + * + * \see null_safe_string(), safe_string(), safe_string_view() + * + * \since version UNRELEASED + */ +GUL_EXPORT +std::string_view null_safe_string_view(const char* char_ptr, std::size_t length); + /** * Repeat a string N times. * \code @@ -282,7 +307,8 @@ GUL_EXPORT std::string repeat(std::string_view str, std::size_t n); /** - * Safely construct a std::string from a char pointer and a length. + * Safely construct a std::string from a char pointer and a length, respecting null + * termination in the style of a C string. * * If the pointer is null, an empty string is constructed. If there are no zero bytes in * the input range, a string of length \c length is constructed. Otherwise, the input @@ -300,7 +326,7 @@ std::string repeat(std::string_view str, std::size_t n); * \c length accessible bytes, or a null pointer * \param length Maximum length of the generated string * - * \see null_safe_string(), safe_string_view() + * \see null_safe_string(), null_safe_string_view(), safe_string_view() * * \since GUL version 2.6 */ @@ -308,7 +334,8 @@ GUL_EXPORT std::string safe_string(const char* char_ptr, std::size_t length); /** - * Safely construct a string_view from a char pointer and a length. + * Safely construct a string_view from a char pointer and a length, respecting null + * termination in the style of a C string. * * If the pointer is null, an empty string_view is constructed. If there are no zero bytes * in the input range, a string_view of length \c length is constructed. Otherwise, the @@ -326,7 +353,7 @@ std::string safe_string(const char* char_ptr, std::size_t length); * \c length accessible bytes, or a null pointer * \param length Maximum length of the generated string_view * - * \see null_safe_string_view(), safe_string() + * \see null_safe_string(), null_safe_string_view(), safe_string() * * \since GUL version 25.4.0 */ diff --git a/src/string_util.cc b/src/string_util.cc index 7685a01..5454c90 100644 --- a/src/string_util.cc +++ b/src/string_util.cc @@ -50,6 +50,16 @@ std::string_view null_safe_string_view(const char* char_ptr) return result; } +std::string_view null_safe_string_view(const char* char_ptr, std::size_t length) +{ + std::string_view result; + + if (char_ptr) + result = std::string_view(char_ptr, length); + + return result; +} + std::string repeat(std::string_view str, std::size_t n) { std::string result; diff --git a/tests/test_string_util.cc b/tests/test_string_util.cc index db0f25a..d2a6783 100644 --- a/tests/test_string_util.cc +++ b/tests/test_string_util.cc @@ -134,6 +134,20 @@ TEST_CASE("null_safe_string_view(const char*)", "[string_util]") REQUIRE(null_safe_string_view("hi\0there") == "hi"sv); } +TEST_CASE("null_safe_string_view(const char*, std::size_t)", "[string_util]") +{ + using gul17::null_safe_string_view; + + REQUIRE(null_safe_string_view(nullptr, 0ull) == std::string_view{}); + REQUIRE(null_safe_string_view(nullptr, 10ull) == std::string_view{}); + REQUIRE(null_safe_string_view("", 0ull) == ""sv); + REQUIRE(null_safe_string_view("", 1ull) == "\0"sv); + REQUIRE(null_safe_string_view("hello", 5ull) == "hello"sv); + REQUIRE(null_safe_string_view("hello", 2ull) == "he"sv); + REQUIRE(null_safe_string_view("hi\0there", 2ull) == "hi"sv); + REQUIRE(null_safe_string_view("hi\0there", 4ull) == "hi\0t"sv); +} + TEST_CASE("repeat()", "[string_util]") { REQUIRE(repeat("du", 3) == "dududu");