diff --git a/stl/inc/xstring b/stl/inc/xstring index 8b7fc948540..d9be25f12d5 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2695,10 +2695,12 @@ private: template _CONSTEXPR20 void _Construct_from_iter(_Iter _First, const _Sent _Last, _Size _Count = {}) { - // Pre: _First models input_iterator or meets the Cpp17InputIterator requirements - // Pre: [_First, _Last) is a valid range + // Pre: _Iter models input_iterator or meets the Cpp17InputIterator requirements. + // Pre: [_First, _Last) is a valid range. + // Pre: if _Iter models forward_iterator or meets the Cpp17ForwardIterator requirements, + // then is_same_v<_Size, size_type> holds. // Pre: if is_same_v<_Size, size_type>, _Count is the length of [_First, _Last). - // Pre: *this is in small mode; the lifetime of the SSO elements has already begun + // Pre: *this is in small mode; the lifetime of the SSO elements has already begun. auto& _My_data = _Mypair._Myval2; auto& _Al = _Getal(); @@ -2722,35 +2724,47 @@ private: } _Tidy_deallocate_guard _Guard{this}; - for (; _First != _Last; ++_First) { - if constexpr (!is_same_v<_Size, size_type>) { - if (_My_data._Mysize == _My_data._Myres) { // Need to grow - if (_My_data._Mysize == max_size()) { - _Xlen_string(); // result too long - } - _Elem* const _Old_ptr = _My_data._Myptr(); - size_type _New_capacity = _Calculate_growth(_My_data._Mysize + 1); - const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws + constexpr bool _Can_construct_by_copy = + _Is_specialization_v<_Traits, char_traits> && _Is_EcharT<_Elem> && is_same_v<_Size, size_type>; - _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); - if (_My_data._Large_mode_engaged()) { // Need to deallocate old storage - _Deallocate_for_capacity(_Al, _My_data._Bx._Ptr, _My_data._Myres); - _My_data._Bx._Ptr = _New_ptr; - } else { - _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); + if constexpr (_Can_construct_by_copy) { + const auto _Data = _My_data._Myptr(); + _STD _Copy_n_unchecked4(_STD move(_First), _Count, _Data); + _My_data._Mysize = _Count; + _Data[_Count] = _Elem(); + } else { + for (; _First != _Last; ++_First) { + if constexpr (!is_same_v<_Size, size_type>) { + if (_My_data._Mysize == _My_data._Myres) { // Need to grow + if (_My_data._Mysize == max_size()) { + _Xlen_string(); // result too long + } + + _Elem* const _Old_ptr = _My_data._Myptr(); + size_type _New_capacity = _Calculate_growth(_My_data._Mysize + 1); + const pointer _New_ptr = _Allocate_for_capacity(_Al, _New_capacity); // throws + + _Traits::copy(_Unfancy(_New_ptr), _Old_ptr, _My_data._Mysize); + if (_My_data._Large_mode_engaged()) { // Need to deallocate old storage + _Deallocate_for_capacity(_Al, _My_data._Bx._Ptr, _My_data._Myres); + _My_data._Bx._Ptr = _New_ptr; + } else { + _Construct_in_place(_My_data._Bx._Ptr, _New_ptr); + } + _My_data._Myres = _New_capacity; } - _My_data._Myres = _New_capacity; } + + _Elem* const _Ptr = _My_data._Myptr(); + _Traits::assign(_Ptr[_My_data._Mysize], *_First); + ++_My_data._Mysize; } _Elem* const _Ptr = _My_data._Myptr(); - _Traits::assign(_Ptr[_My_data._Mysize], *_First); - ++_My_data._Mysize; + _Traits::assign(_Ptr[_My_data._Mysize], _Elem()); } - _Elem* const _Ptr = _My_data._Myptr(); - _Traits::assign(_Ptr[_My_data._Mysize], _Elem()); _ASAN_STRING_CREATE(*this); _Guard._Target = nullptr; _Proxy._Release(); diff --git a/tests/std/tests/P1206R7_string_from_range/test.cpp b/tests/std/tests/P1206R7_string_from_range/test.cpp index b94a62dc326..f9f4daecb35 100644 --- a/tests/std/tests/P1206R7_string_from_range/test.cpp +++ b/tests/std/tests/P1206R7_string_from_range/test.cpp @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#pragma warning(disable : 4365) // conversion from 'X' to 'Y', signed/unsigned mismatch + #include +#include #include +#include #include #include #include @@ -44,6 +48,12 @@ constexpr bool test_string(Rng&& rng, const T* expected) { static constexpr char hw[] = "Hello, world!"; static constexpr auto span_hw = span{hw}.first(); +static constexpr signed char hw_s[] = "Hello, world!"; +static constexpr auto span_hw_s = span{hw_s}.first(); + +static constexpr unsigned char hw_u[] = "Hello, world!"; +static constexpr auto span_hw_u = span{hw_u}.first(); + struct string_instantiator { template static void call() { @@ -52,9 +62,76 @@ struct string_instantiator { } }; +#ifdef __cpp_char8_t +static constexpr char8_t hw_u8[] = u8"Hello, world!"; +static constexpr auto span_hw_u8 = span{hw_u8}.first(); + +struct u8string_instantiator { + template + static void call() { + test_string(R{span_hw_u8}, hw_u8); + STATIC_ASSERT(test_string(R{span_hw_u8}, hw_u8)); + } +}; +#endif // defined(__cpp_char8_t) + +static constexpr char16_t hw_u16[] = u"Hello, world!"; +static constexpr auto span_hw_u16 = span{hw_u16}.first(); + +static constexpr int_least16_t hw_u16s[]{ + u'H', u'e', u'l', u'l', u'o', u',', u' ', u'w', u'o', u'r', u'l', u'd', u'!', u'\0'}; +static constexpr auto span_hw_u16s = span{hw_u16s}.first(); + +static constexpr uint_least16_t hw_u16u[]{ + u'H', u'e', u'l', u'l', u'o', u',', u' ', u'w', u'o', u'r', u'l', u'd', u'!', u'\0'}; +static constexpr auto span_hw_u16u = span{hw_u16u}.first(); + +struct u16string_instantiator { + template + static void call() { + test_string(R{span_hw_u16}, hw_u16); + STATIC_ASSERT(test_string(R{span_hw_u16}, hw_u16)); + } +}; + +static constexpr char32_t hw_u32[] = U"Hello, world!"; +static constexpr auto span_hw_u32 = span{hw_u32}.first(); + +static constexpr int_least32_t hw_u32s[]{ + U'H', U'e', U'l', U'l', U'o', U',', U' ', U'w', U'o', U'r', U'l', U'd', U'!', U'\0'}; +static constexpr auto span_hw_u32s = span{hw_u32s}.first(); + +static constexpr uint_least32_t hw_u32u[]{ + U'H', U'e', U'l', U'l', U'o', U',', U' ', U'w', U'o', U'r', U'l', U'd', U'!', U'\0'}; +static constexpr auto span_hw_u32u = span{hw_u32u}.first(); + +static constexpr long hw_slong[]{U'H', U'e', U'l', U'l', U'o', U',', U' ', U'w', U'o', U'r', U'l', U'd', U'!', U'\0'}; +static constexpr auto span_hw_slong = span{hw_slong}.first(); + +static constexpr unsigned long hw_ulong[]{ + U'H', U'e', U'l', U'l', U'o', U',', U' ', U'w', U'o', U'r', U'l', U'd', U'!', U'\0'}; +static constexpr auto span_hw_ulong = span{hw_ulong}.first(); + +struct u32string_instantiator { + template + static void call() { + test_string(R{span_hw_u32}, hw_u32); + STATIC_ASSERT(test_string(R{span_hw_u32}, hw_u32)); + } +}; + +using swchar_t = make_signed_t; +using uwchar_t = make_unsigned_t; + static constexpr wchar_t whw[] = L"Hello, world!"; static constexpr auto span_whw = span{whw}.first(); +static constexpr swchar_t whw_s[]{L'H', L'e', L'l', L'l', L'o', L',', L' ', L'w', L'o', L'r', L'l', L'd', L'!', L'\0'}; +static constexpr auto span_whw_s = span{whw_s}.first(); + +static constexpr uwchar_t whw_u[]{L'H', L'e', L'l', L'l', L'o', L',', L' ', L'w', L'o', L'r', L'l', L'd', L'!', L'\0'}; +static constexpr auto span_whw_u = span{whw_u}.first(); + struct wstring_instantiator { template static void call() { @@ -71,7 +148,32 @@ using move_only_view = test::range(const Span& sp, const CharT* cstr) { + vector vec(sp.data(), sp.data() + sp.size()); + test_string(vec, cstr); + }; + + test_lvalue_vector_helper(span_hw, hw); + test_lvalue_vector_helper(span_hw_s, hw); + test_lvalue_vector_helper(span_hw_u, hw); +#ifdef __cpp_char8_t + test_lvalue_vector_helper(span_hw_u8, hw); + + test_lvalue_vector_helper(span_hw_u8, hw_u8); + test_lvalue_vector_helper(span_hw, hw_u8); + test_lvalue_vector_helper(span_hw_s, hw_u8); + test_lvalue_vector_helper(span_hw_u, hw_u8); +#endif // defined(__cpp_char8_t) + + test_lvalue_vector_helper(span_hw_u16, hw_u16); + test_lvalue_vector_helper(span_hw_u16s, hw_u16); + test_lvalue_vector_helper(span_hw_u16u, hw_u16); + test_lvalue_vector_helper(span_whw, hw_u16); + + test_lvalue_vector_helper(span_hw_u32, hw_u32); + test_lvalue_vector_helper(span_hw_u32s, hw_u32); + test_lvalue_vector_helper(span_hw_u32u, hw_u32); + test_lvalue_vector_helper(span_hw_slong, hw_u32); + test_lvalue_vector_helper(span_hw_ulong, hw_u32); + + test_lvalue_vector_helper(span_whw, whw); + test_lvalue_vector_helper(span_whw_s, whw); + test_lvalue_vector_helper(span_whw_u, whw); + test_lvalue_vector_helper(span_hw_u16, whw); return true; } @@ -120,6 +331,20 @@ void test_lvalue_forward_list() { forward_list lst(span_hw.data(), span_hw.data() + span_hw.size()); test_string(lst, hw); } +#ifdef __cpp_char8_t + { + forward_list lst(span_hw_u8.data(), span_hw_u8.data() + span_hw_u8.size()); + test_string(lst, hw_u8); + } +#endif // defined(__cpp_char8_t) + { + forward_list lst(span_hw_u16.data(), span_hw_u16.data() + span_hw_u16.size()); + test_string(lst, hw_u16); + } + { + forward_list lst(span_hw_u32.data(), span_hw_u32.data() + span_hw_u32.size()); + test_string(lst, hw_u32); + } { forward_list lst(span_whw.data(), span_whw.data() + span_whw.size()); test_string(lst, whw); @@ -138,6 +363,9 @@ int main() { test_c_array(); STATIC_ASSERT(test_c_array()); + test_std_array(); + STATIC_ASSERT(test_std_array()); + test_lvalue_vector(); STATIC_ASSERT(test_lvalue_vector()); @@ -145,4 +373,10 @@ int main() { test_in(); test_in(); + +#ifdef __cpp_char8_t + test_contiguous(); +#endif // defined(__cpp_char8_t) + test_contiguous(); + test_contiguous(); }