diff --git a/libcxx/include/__string b/libcxx/include/__string --- a/libcxx/include/__string +++ b/libcxx/include/__string @@ -153,7 +153,6 @@ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::insert(size_type, value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_first_of(value_type const*, size_type, size_type) const) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::replace(size_type, size_type, size_type, value_type)) \ - _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::reserve(size_type)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::append(value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(basic_string const&, size_type, size_type)) \ @@ -165,6 +164,8 @@ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find_last_of(value_type const*, size_type, size_type) const) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by(size_type, size_type, size_type, size_type, size_type, size_type)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__grow_by_and_replace(size_type, size_type, size_type, size_type, size_type, size_type, value_type const*)) \ + _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_maybe_alias(value_type const*, size_type)) \ + _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_maybe_alias(value_type const*)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_no_alias(value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::__assign_no_alias(value_type const*, size_type)) \ _Func(_LIBCPP_FUNC_VIS void basic_string<_CharType>::push_back(value_type)) \ @@ -177,7 +178,6 @@ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(value_type const*) const) \ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*) const) \ _Func(_LIBCPP_FUNC_VIS _CharType& basic_string<_CharType>::at(size_type)) \ - _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>& basic_string<_CharType>::assign(value_type const*)) \ _Func(_LIBCPP_FUNC_VIS basic_string<_CharType>::size_type basic_string<_CharType>::find(value_type const*, size_type, size_type) const) \ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, basic_string const&, size_type, size_type) const) \ _Func(_LIBCPP_FUNC_VIS int basic_string<_CharType>::compare(size_type, size_type, value_type const*, size_type) const) \ diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1571,12 +1571,34 @@ size_type __n_copy, size_type __n_del, size_type __n_add, const value_type* __p_new_stuff); + // `__assign_inline` contains the implementation called by the externally + // instantiated __assign_no_alias() and__assign_maybe_alias() methods. + template + inline void __assign_inline(const value_type* __s, size_type __n); + + // `__assign_in_place` directly assigns the given input string + // into the current instance where the caller has verified both + // that the it fits capacity, as well as that there is no aliasing. + inline void __assign_in_place(const value_type* __s, size_type __n) { + pointer __p = __is_long() ? __get_long_pointer() : __get_short_pointer(); + __is_long() ? __set_long_size(__n) : __set_short_size(__n); + traits_type::copy(_VSTD::__to_address(__p), __s, __n); + traits_type::assign(__p[__n], value_type()); + } + // __assign_no_alias is invoked for assignment operations where we // have proof that the input does not alias the current instance. // For example, operator=(basic_string) performs a 'self' check. template void __assign_no_alias(const value_type* __s, size_type __n); + // `__assign_maybe_alias` is invoked for assignment operations where + // we lack proof that the input does not alias the current instance. + // For example, assign(const char *s) may be invoked with the 's' + // value referring to the contents in 'this' string instance. + void __assign_maybe_alias(const value_type* __s); + void __assign_maybe_alias(const value_type* __s, size_type __n); + _LIBCPP_INLINE_VISIBILITY void __erase_to_end(size_type __pos); @@ -2209,14 +2231,18 @@ // assign template -template -void basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias( +template +void basic_string<_CharT, _Traits, _Allocator>::__assign_inline( const value_type* __s, size_type __n) { size_type __cap = __is_short ? __min_cap : __get_long_cap(); if (__n < __cap) { pointer __p = __is_short ? __get_short_pointer() : __get_long_pointer(); __is_short ? __set_short_size(__n) : __set_long_size(__n); - traits_type::copy(_VSTD::__to_address(__p), __s, __n); + if (__maybe_aliased) { + traits_type::move(_VSTD::__to_address(__p), __s, __n); + } else { + traits_type::copy(_VSTD::__to_address(__p), __s, __n); + } traits_type::assign(__p[__n], value_type()); __invalidate_iterators_past(__n); } else { @@ -2225,26 +2251,43 @@ } } +template +template +void basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias( + const value_type* __s, size_type __n) { + __assign_inline<__is_short, false>(__s, __n); +} + +template +void basic_string<_CharT, _Traits, _Allocator>::__assign_maybe_alias( + const value_type* __s, size_type __n) { + __is_long() ? __assign_inline(__s, __n) + : __assign_inline(__s, __n); +} + +template +void basic_string<_CharT, _Traits, _Allocator>::__assign_maybe_alias( + const value_type* __s) { + size_type __n = traits_type::length(__s); + __is_long() ? __assign_inline(__s, __n) + : __assign_inline(__s, __n); +} + template basic_string<_CharT, _Traits, _Allocator>& -basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n) -{ - _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr"); - size_type __cap = capacity(); - if (__cap >= __n) - { - value_type* __p = _VSTD::__to_address(__get_pointer()); - traits_type::move(__p, __s, __n); - traits_type::assign(__p[__n], value_type()); - __set_size(__n); - __invalidate_iterators_past(__n); - } - else - { - size_type __sz = size(); - __grow_by_and_replace(__cap, __n - __cap, __sz, 0, __sz, __n, __s); +basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, + size_type __n) { + _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr"); + if (_LIBCPP_BUILTIN_CONSTANT_P(__n)) { + if (__n < __min_cap) { + __assign_in_place(__s, __n); + } else { + __assign_maybe_alias(__s, __n); } - return *this; + } else { + __assign_maybe_alias(__s, __n); + } + return *this; } template @@ -2428,13 +2471,22 @@ return assign(__sv.data() + __pos, _VSTD::min(__n, __sz - __pos)); } - template basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s) { - _LIBCPP_ASSERT(__s != nullptr, "string::assign received nullptr"); - return assign(__s, traits_type::length(__s)); + _LIBCPP_ASSERT(__s != nullptr, "string::assign received nullptr"); + if (_LIBCPP_BUILTIN_CONSTANT_P(__s[0])) { + const size_type __n = traits_type::length(__s); + if (__n < __min_cap) { + __assign_in_place(__s, __n); + } else { + __assign_maybe_alias(__s, __n); + } + } else { + __assign_maybe_alias(__s); + } + return *this; } // append