diff --git a/include/etl/char_traits.h b/include/etl/char_traits.h index 41b5dd4e..da3ed887 100644 --- a/include/etl/char_traits.h +++ b/include/etl/char_traits.h @@ -123,6 +123,22 @@ namespace etl return count; } + //************************************************************************* + ETL_CONSTEXPR14 static size_t length(const char_type* str, size_t max_length) + { + size_t count = 0UL; + + if (str != 0) + { + while ((count < max_length) && (*str++ != 0)) + { + ++count; + } + } + + return count; + } + //************************************************************************* static void assign(char_type& r, const char_type& c) { @@ -241,6 +257,15 @@ namespace etl { return etl::char_traits::length(t); } + + //*************************************************************************** + /// Alternative strlen for all character types, with maximum length. + //*************************************************************************** + template + size_t strlen(const T* t, size_t max_length) + { + return etl::char_traits::length(t, max_length); + } } #endif diff --git a/include/etl/string.h b/include/etl/string.h index 1ea8e416..a1415e2e 100644 --- a/include/etl/string.h +++ b/include/etl/string.h @@ -472,9 +472,9 @@ namespace etl /// Make string from string literal or array //*************************************************************************** template - etl::string make_string(const char(&text)[ARRAY_SIZE]) + etl::string make_string(const char(&text)[ARRAY_SIZE]) { - return etl::string(text, etl::strlen(text)); + return etl::string(text, etl::strlen(text, ARRAY_SIZE - 1)); } //*************************************************************************** @@ -483,7 +483,7 @@ namespace etl template etl::string make_string_with_capacity(const char(&text)[SIZE]) { - return etl::string(text, etl::strlen(text)); + return etl::string(text, etl::strlen(text, SIZE)); } } diff --git a/include/etl/string_view.h b/include/etl/string_view.h index 48bf25ec..3f52133d 100644 --- a/include/etl/string_view.h +++ b/include/etl/string_view.h @@ -809,27 +809,38 @@ namespace etl /// make_string_view. //************************************************************************* template - ETL_CONSTEXPR string_view make_string_view(const char(&text)[ARRAY_SIZE]) + ETL_CONSTEXPR14 string_view make_string_view(const char(&text)[ARRAY_SIZE]) { - return string_view(text, ARRAY_SIZE - 1U); + size_t length = etl::char_traits::length(text, ARRAY_SIZE - 1U); + + return string_view(text, length); } + //*********************************** template - ETL_CONSTEXPR wstring_view make_string_view(const wchar_t(&text)[ARRAY_SIZE]) + ETL_CONSTEXPR14 wstring_view make_string_view(const wchar_t(&text)[ARRAY_SIZE]) { - return wstring_view(text, ARRAY_SIZE - 1U); + size_t length = etl::char_traits::length(text, ARRAY_SIZE - 1U); + + return wstring_view(text, length); } + //*********************************** template - ETL_CONSTEXPR u16string_view make_string_view(const char16_t(&text)[ARRAY_SIZE]) + ETL_CONSTEXPR14 u16string_view make_string_view(const char16_t(&text)[ARRAY_SIZE]) { - return u16string_view(text, ARRAY_SIZE - 1U); + size_t length = etl::char_traits::length(text, ARRAY_SIZE - 1U); + + return u16string_view(text, length); } + //*********************************** template - ETL_CONSTEXPR u32string_view make_string_view(const char32_t(&text)[ARRAY_SIZE]) + ETL_CONSTEXPR14 u32string_view make_string_view(const char32_t(&text)[ARRAY_SIZE]) { - return u32string_view(text, ARRAY_SIZE - 1U); + size_t length = etl::char_traits::length(text, ARRAY_SIZE - 1U); + + return u32string_view(text, length); } //************************************************************************* diff --git a/include/etl/u16string.h b/include/etl/u16string.h index d280f2dd..88f5303b 100644 --- a/include/etl/u16string.h +++ b/include/etl/u16string.h @@ -455,9 +455,9 @@ namespace etl /// Make string from string literal or array //*************************************************************************** template - etl::u16string make_string(const char16_t(&text)[ARRAY_SIZE]) + etl::u16string make_string(const char16_t(&text)[ARRAY_SIZE]) { - return etl::u16string(text, etl::strlen(text)); + return etl::u16string(text, etl::strlen(text, ARRAY_SIZE - 1U)); } //*************************************************************************** @@ -466,7 +466,7 @@ namespace etl template etl::u16string make_string_with_capacity(const char16_t(&text)[SIZE]) { - return etl::u16string(text, etl::strlen(text)); + return etl::u16string(text, etl::strlen(text, SIZE)); } } diff --git a/include/etl/u32string.h b/include/etl/u32string.h index 9edf6347..1dda3291 100644 --- a/include/etl/u32string.h +++ b/include/etl/u32string.h @@ -455,9 +455,9 @@ namespace etl /// Make string from string literal or array //*************************************************************************** template - etl::u32string make_string(const char32_t(&text)[ARRAY_SIZE]) + etl::u32string make_string(const char32_t(&text)[ARRAY_SIZE]) { - return etl::u32string(text, etl::strlen(text)); + return etl::u32string(text, etl::strlen(text, ARRAY_SIZE - 1U)); } //*************************************************************************** @@ -466,7 +466,7 @@ namespace etl template etl::u32string make_string_with_capacity(const char32_t(&text)[SIZE]) { - return etl::u32string(text, etl::strlen(text)); + return etl::u32string(text, etl::strlen(text, SIZE)); } } diff --git a/include/etl/wstring.h b/include/etl/wstring.h index 10b22c18..cde74be3 100644 --- a/include/etl/wstring.h +++ b/include/etl/wstring.h @@ -455,18 +455,18 @@ namespace etl /// Make string from string literal or array //*************************************************************************** template - etl::wstring make_string(const wchar_t(&text)[ARRAY_SIZE]) + etl::wstring make_string(const wchar_t(&text)[ARRAY_SIZE]) { - return etl::wstring(text, etl::strlen(text)); + return etl::wstring(text, etl::strlen(text, ARRAY_SIZE - 1U)); } //*************************************************************************** - /// Make string with max capacity from string literal or char array + /// Make string with max capacity from string literal or array //*************************************************************************** template etl::wstring make_string_with_capacity(const wchar_t(&text)[SIZE]) { - return etl::wstring(text, etl::strlen(text)); + return etl::wstring(text, etl::strlen(text, SIZE)); } } diff --git a/test/test_string_view.cpp b/test/test_string_view.cpp index 4ec0c27e..86c9eefc 100644 --- a/test/test_string_view.cpp +++ b/test/test_string_view.cpp @@ -54,8 +54,12 @@ namespace std::string text_shorter = "Hello Worl"; std::string text_different = "Goodbye!!!!"; - char ctext[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' }; - char* pctext = ctext; + constexpr char cctext[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' }; + constexpr wchar_t cwtext[] = { L'H', L'e', L'l', L'l', L'o', L' ', L'W', L'o', L'r', L'l', L'd', L'\0' }; + constexpr char16_t cu16text[] = { u'H', u'e', u'l', u'l', u'o', u' ', u'W', u'o', u'r', u'l', u'd', u'\0' }; + constexpr char32_t cu32text[] = { U'H', U'e', U'l', U'l', U'o', U' ', U'W', U'o', U'r', U'l', U'd', U'\0' }; + + const char* pctext = cctext; SUITE(test_string_view) { @@ -158,12 +162,94 @@ namespace auto u16view = etl::make_string_view(u"Hello World"); auto u32view = etl::make_string_view(U"Hello World"); + CHECK(std::equal(cview.begin(), cview.end(), text.begin())); + CHECK(std::equal(wview.begin(), wview.end(), wtext.begin())); + CHECK(std::equal(u16view.begin(), u16view.end(), u16text.begin())); + CHECK(std::equal(u32view.begin(), u32view.end(), u32text.begin())); + } + + //************************************************************************* + TEST(test_constexpr_make_string_view) + { + constexpr auto cview = etl::make_string_view(cctext); + constexpr auto wview = etl::make_string_view(cwtext); + constexpr auto u16view = etl::make_string_view(cu16text); + constexpr auto u32view = etl::make_string_view(cu32text); + CHECK(std::equal(cview.begin(), cview.end(), text.begin())); CHECK(std::equal(wview.begin(), wview.end(), text.begin())); CHECK(std::equal(u16view.begin(), u16view.end(), text.begin())); CHECK(std::equal(u32view.begin(), u32view.end(), text.begin())); } + //************************************************************************* + TEST(test_make_string_view_check_consistent_strings_from_arrays_of_char) + { + char text_extra_nulls[10] = { 'H', 'e', 'l', 'l', 'o' }; + char text_no_null[10] = { 'H', 'e', 'l', 'l', 'o' }; + std::string text_expected = "Hello"; + + auto view_extra_nulls = etl::make_string_view(text_extra_nulls); + auto view_no_null = etl::make_string_view(text_no_null); + + CHECK_EQUAL(text_expected.size(), view_extra_nulls.size()); + CHECK_EQUAL(text_expected.size(), view_no_null.size()); + + CHECK(std::equal(view_extra_nulls.begin(), view_extra_nulls.end(), text_expected.begin())); + CHECK(std::equal(view_no_null.begin(), view_no_null.end(), text_expected.begin())); + } + + //************************************************************************* + TEST(test_make_string_view_check_consistent_strings_from_arrays_of_wchar_t) + { + wchar_t text_extra_nulls[10] = { L'H', L'e', L'l', L'l', L'o' }; + wchar_t text_no_null[10] = { L'H', L'e', L'l', L'l', L'o' }; + std::wstring text_expected = L"Hello"; + + auto view_extra_nulls = etl::make_string_view(text_extra_nulls); + auto view_no_null = etl::make_string_view(text_no_null); + + CHECK_EQUAL(text_expected.size(), view_extra_nulls.size()); + CHECK_EQUAL(text_expected.size(), view_no_null.size()); + + CHECK(std::equal(view_extra_nulls.begin(), view_extra_nulls.end(), text_expected.begin())); + CHECK(std::equal(view_no_null.begin(), view_no_null.end(), text_expected.begin())); + } + + //************************************************************************* + TEST(test_make_string_view_check_consistent_strings_from_arrays_of_char16_t) + { + char16_t text_extra_nulls[10] = { u'H', u'e', u'l', u'l', u'o' }; + char16_t text_no_null[10] = { u'H', u'e', u'l', u'l', u'o' }; + std::u16string text_expected = u"Hello"; + + auto view_extra_nulls = etl::make_string_view(text_extra_nulls); + auto view_no_null = etl::make_string_view(text_no_null); + + CHECK_EQUAL(text_expected.size(), view_extra_nulls.size()); + CHECK_EQUAL(text_expected.size(), view_no_null.size()); + + CHECK(std::equal(view_extra_nulls.begin(), view_extra_nulls.end(), text_expected.begin())); + CHECK(std::equal(view_no_null.begin(), view_no_null.end(), text_expected.begin())); + } + + //************************************************************************* + TEST(test_make_string_view_check_consistent_strings_from_arrays_of_char32_t) + { + char32_t text_extra_nulls[10] = { U'H', U'e', U'l', U'l', U'o' }; + char32_t text_no_null[10] = { U'H', U'e', U'l', U'l', U'o' }; + std::u32string text_expected = U"Hello"; + + auto view_extra_nulls = etl::make_string_view(text_extra_nulls); + auto view_no_null = etl::make_string_view(text_no_null); + + CHECK_EQUAL(text_expected.size(), view_extra_nulls.size()); + CHECK_EQUAL(text_expected.size(), view_no_null.size()); + + CHECK(std::equal(view_extra_nulls.begin(), view_extra_nulls.end(), text_expected.begin())); + CHECK(std::equal(view_no_null.begin(), view_no_null.end(), text_expected.begin())); + } + //************************************************************************* #if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST && !defined(ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED) TEST(test_template_deduction) diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 84f706ac..2a3fa8ce 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -2443,7 +2443,8 @@ - + + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 5de3162b..daef9087 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1317,7 +1317,7 @@ ETL\Private - + ETL\Private @@ -1335,6 +1335,9 @@ ETL\Utilities + + ETL\Private +