Skip to content

Commit 199ffa4

Browse files
philnik777yuxuanchen1997
authored andcommitted
[libc++] Use char_traits::copy while inserting when possible (#97201)
Summary: This reduces the number of asm lines from 707 to 519 for this snippet: ```c++ auto test(std::string& str, const char* begin, const char* end) { str.insert(str.begin(), begin, end); } ``` While that's not a performance metric, I've never seen a use of `memcpy` result in a performance regression for any realistic usage. Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60250917
1 parent 9f34b20 commit 199ffa4

File tree

1 file changed

+22
-9
lines changed

1 file changed

+22
-9
lines changed

libcxx/include/string

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1870,6 +1870,23 @@ private:
18701870
template <class _Iterator, class _Sentinel>
18711871
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iterator __first, _Sentinel __last);
18721872

1873+
// Copy [__first, __last) into [__dest, __dest + (__last - __first)). Assumes that the ranges don't overlap.
1874+
template <class _ForwardIter, class _Sent>
1875+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static value_type*
1876+
__copy_non_overlapping_range(_ForwardIter __first, _Sent __last, value_type* __dest) {
1877+
#ifndef _LIBCPP_CXX03_LANG
1878+
if constexpr (__libcpp_is_contiguous_iterator<_ForwardIter>::value &&
1879+
is_same<value_type, __iter_value_type<_ForwardIter>>::value && is_same<_ForwardIter, _Sent>::value) {
1880+
traits_type::copy(__dest, std::__to_address(__first), __last - __first);
1881+
return __dest + (__last - __first);
1882+
}
1883+
#endif
1884+
1885+
for (; __first != __last; ++__first)
1886+
traits_type::assign(*__dest++, *__first);
1887+
return __dest;
1888+
}
1889+
18731890
template <class _ForwardIterator, class _Sentinel>
18741891
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 iterator
18751892
__insert_from_safe_copy(size_type __n, size_type __ip, _ForwardIterator __first, _Sentinel __last) {
@@ -1889,8 +1906,7 @@ private:
18891906
__sz += __n;
18901907
__set_size(__sz);
18911908
traits_type::assign(__p[__sz], value_type());
1892-
for (__p += __ip; __first != __last; ++__p, ++__first)
1893-
traits_type::assign(*__p, *__first);
1909+
__copy_non_overlapping_range(__first, __last, __p + __ip);
18941910

18951911
return begin() + __ip;
18961912
}
@@ -2405,9 +2421,8 @@ basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __fir
24052421
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
24062422
try {
24072423
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
2408-
for (; __first != __last; ++__first, (void)++__p)
2409-
traits_type::assign(*__p, *__first);
2410-
traits_type::assign(*__p, value_type());
2424+
auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__p));
2425+
traits_type::assign(*__end, value_type());
24112426
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
24122427
} catch (...) {
24132428
if (__is_long())
@@ -2873,10 +2888,8 @@ basic_string<_CharT, _Traits, _Allocator>::append(_ForwardIterator __first, _For
28732888
if (__cap - __sz < __n)
28742889
__grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0);
28752890
__annotate_increase(__n);
2876-
pointer __p = __get_pointer() + __sz;
2877-
for (; __first != __last; ++__p, (void)++__first)
2878-
traits_type::assign(*__p, *__first);
2879-
traits_type::assign(*__p, value_type());
2891+
auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__get_pointer() + __sz));
2892+
traits_type::assign(*__end, value_type());
28802893
__set_size(__sz + __n);
28812894
} else {
28822895
const basic_string __temp(__first, __last, __alloc());

0 commit comments

Comments
 (0)