Changeset View
Changeset View
Standalone View
Standalone View
libcxx/include/string
Show First 20 Lines • Show All 1,535 Lines • ▼ Show 20 Lines | #endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT | ||||
size_type __recommend(size_type __s) _NOEXCEPT | size_type __recommend(size_type __s) _NOEXCEPT | ||||
{ | { | ||||
if (__s < __min_cap) return static_cast<size_type>(__min_cap) - 1; | if (__s < __min_cap) return static_cast<size_type>(__min_cap) - 1; | ||||
size_type __guess = __align_it<sizeof(value_type) < __alignment ? | size_type __guess = __align_it<sizeof(value_type) < __alignment ? | ||||
__alignment/sizeof(value_type) : 1 > (__s+1) - 1; | __alignment/sizeof(value_type) : 1 > (__s+1) - 1; | ||||
if (__guess == __min_cap) ++__guess; | if (__guess == __min_cap) ++__guess; | ||||
return __guess; | return __guess; | ||||
} | } | ||||
static _LIBCPP_INLINE_VISIBILITY size_type | |||||
__recommend_cap(size_type __cap) _NOEXCEPT { | |||||
return __align_it < sizeof(value_type) < __alignment | |||||
? __alignment / sizeof(value_type) | |||||
: 1 > (__cap); | |||||
} | |||||
inline | inline | ||||
void __init(const value_type* __s, size_type __sz, size_type __reserve); | void __init(const value_type* __s, size_type __sz, size_type __reserve); | ||||
inline | inline | ||||
void __init(const value_type* __s, size_type __sz); | void __init(const value_type* __s, size_type __sz); | ||||
inline | inline | ||||
void __init(size_type __n, value_type __c); | void __init(size_type __n, value_type __c); | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | void __move_assign_alloc(basic_string& __c, true_type) | ||||
__alloc() = _VSTD::move(__c.__alloc()); | __alloc() = _VSTD::move(__c.__alloc()); | ||||
} | } | ||||
_LIBCPP_INLINE_VISIBILITY | _LIBCPP_INLINE_VISIBILITY | ||||
void __move_assign_alloc(basic_string&, false_type) | void __move_assign_alloc(basic_string&, false_type) | ||||
_NOEXCEPT | _NOEXCEPT | ||||
{} | {} | ||||
basic_string& __assign_external(const value_type* __s); | |||||
basic_string& __assign_external(const value_type* __s, size_type __n); | |||||
template <bool __is_short> | |||||
value_type* __resize(size_type __n); | |||||
inline value_type* __resize(size_type __n) { | |||||
return __is_long() ? __resize<false>(__n) : __resize<true>(__n); | |||||
} | |||||
inline value_type* __resize_small(size_type __n) _NOEXCEPT { | |||||
pointer __p = __is_long() | |||||
? (__set_long_size(__n), __get_long_pointer()) | |||||
: (__set_short_size(__n), __get_short_pointer()); | |||||
traits_type::assign(__p[__n], value_type()); | |||||
return _VSTD::__to_address(__p); | |||||
} | |||||
inline basic_string& __assign_small_length(const value_type* __s, | |||||
size_type __n) { | |||||
value_type* p = (__n < __min_cap) ? __resize_small(__n) : __resize(__n); | |||||
if (__builtin_constant_p(*__s)) { | |||||
traits_type::copy(p, __s, __n); | |||||
} else { | |||||
traits_type::move(p, __s, __n); | |||||
} | |||||
return *this; | |||||
} | |||||
_LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators(); | _LIBCPP_INLINE_VISIBILITY void __invalidate_all_iterators(); | ||||
_LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type); | _LIBCPP_INLINE_VISIBILITY void __invalidate_iterators_past(size_type); | ||||
friend basic_string operator+<>(const basic_string&, const basic_string&); | friend basic_string operator+<>(const basic_string&, const basic_string&); | ||||
friend basic_string operator+<>(const value_type*, const basic_string&); | friend basic_string operator+<>(const value_type*, const basic_string&); | ||||
friend basic_string operator+<>(value_type, const basic_string&); | friend basic_string operator+<>(value_type, const basic_string&); | ||||
friend basic_string operator+<>(const basic_string&, const value_type*); | friend basic_string operator+<>(const basic_string&, const value_type*); | ||||
friend basic_string operator+<>(const basic_string&, value_type); | friend basic_string operator+<>(const basic_string&, value_type); | ||||
▲ Show 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | basic_string<_CharT, _Traits, _Allocator>::__grow_by_and_replace | ||||
__set_long_pointer(__p); | __set_long_pointer(__p); | ||||
__set_long_cap(__cap+1); | __set_long_cap(__cap+1); | ||||
__old_sz = __n_copy + __n_add + __sec_cp_sz; | __old_sz = __n_copy + __n_add + __sec_cp_sz; | ||||
__set_long_size(__old_sz); | __set_long_size(__old_sz); | ||||
traits_type::assign(__p[__old_sz], value_type()); | traits_type::assign(__p[__old_sz], value_type()); | ||||
} | } | ||||
template <class _CharT, class _Traits, class _Allocator> | template <class _CharT, class _Traits, class _Allocator> | ||||
template <bool __is_short> | |||||
_CharT* basic_string<_CharT, _Traits, _Allocator>::__resize(size_type __n) { | |||||
size_type __old_cap = __is_short ? __min_cap : __get_long_cap(); | |||||
pointer __old_p = __is_short ? __get_short_pointer() : __get_long_pointer(); | |||||
if (__n < __old_cap) { | |||||
__is_short ? __set_short_size(__n) : __set_long_size(__n); | |||||
return _VSTD::__to_address(__old_p); | |||||
} | |||||
const size_type __ms = max_size(); | |||||
if (__n > __ms) this->__throw_length_error(); | |||||
size_type __new_cap; | |||||
if (__is_short) { | |||||
__new_cap = __recommend_cap(_VSTD::max<size_type>(__n + 1, 32)); | |||||
} else { | |||||
__new_cap = (__old_cap < __ms / 2 - __alignment) | |||||
? __recommend_cap(_VSTD::max(__n + 1, 2 * __old_cap)) | |||||
: __ms; | |||||
} | |||||
pointer __p = __alloc_traits::allocate(__alloc(), __new_cap); | |||||
__invalidate_all_iterators(); | |||||
__set_long_pointer(__p); | |||||
__is_short ? __set_short_size(__n) : __set_long_size(__n); | |||||
__set_long_cap(__new_cap); | |||||
if (!__is_short) { | |||||
__alloc_traits::deallocate(__alloc(), __old_p, __old_cap); | |||||
} | |||||
return __p; | |||||
} | |||||
template <class _CharT, class _Traits, class _Allocator> | |||||
void | void | ||||
basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_type __delta_cap, size_type __old_sz, | basic_string<_CharT, _Traits, _Allocator>::__grow_by(size_type __old_cap, size_type __delta_cap, size_type __old_sz, | ||||
size_type __n_copy, size_type __n_del, size_type __n_add) | size_type __n_copy, size_type __n_del, size_type __n_add) | ||||
{ | { | ||||
size_type __ms = max_size(); | size_type __ms = max_size(); | ||||
if (__delta_cap > __ms - __old_cap) | if (__delta_cap > __ms - __old_cap) | ||||
this->__throw_length_error(); | this->__throw_length_error(); | ||||
pointer __old_p = __get_pointer(); | pointer __old_p = __get_pointer(); | ||||
Show All 34 Lines | if (__n < __cap) { | ||||
size_type __sz = __is_short ? __get_short_size() : __get_long_size(); | size_type __sz = __is_short ? __get_short_size() : __get_long_size(); | ||||
__grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s); | __grow_by_and_replace(__cap - 1, __n - __cap + 1, __sz, 0, __sz, __n, __s); | ||||
} | } | ||||
return *this; | return *this; | ||||
} | } | ||||
template <class _CharT, class _Traits, class _Allocator> | template <class _CharT, class _Traits, class _Allocator> | ||||
basic_string<_CharT, _Traits, _Allocator>& | basic_string<_CharT, _Traits, _Allocator>& | ||||
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s, size_type __n) | basic_string<_CharT, _Traits, _Allocator>::__assign_external( | ||||
{ | const value_type* __s, size_type __n) { | ||||
_LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::assign received nullptr"); | |||||
size_type __cap = capacity(); | size_type __cap = capacity(); | ||||
if (__cap >= __n) | if (__cap >= __n) { | ||||
{ | |||||
value_type* __p = _VSTD::__to_address(__get_pointer()); | value_type* __p = _VSTD::__to_address(__get_pointer()); | ||||
traits_type::move(__p, __s, __n); | traits_type::move(__p, __s, __n); | ||||
traits_type::assign(__p[__n], value_type()); | traits_type::assign(__p[__n], value_type()); | ||||
__set_size(__n); | __set_size(__n); | ||||
__invalidate_iterators_past(__n); | __invalidate_iterators_past(__n); | ||||
} | } else { | ||||
else | |||||
{ | |||||
size_type __sz = size(); | size_type __sz = size(); | ||||
__grow_by_and_replace(__cap, __n - __cap, __sz, 0, __sz, __n, __s); | __grow_by_and_replace(__cap, __n - __cap, __sz, 0, __sz, __n, __s); | ||||
} | } | ||||
return *this; | return *this; | ||||
} | } | ||||
template <class _CharT, class _Traits, class _Allocator> | template <class _CharT, class _Traits, class _Allocator> | ||||
basic_string<_CharT, _Traits, _Allocator>& | 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"); | |||||
return (__builtin_constant_p(__n) && __n <= 128 / sizeof(value_type)) | |||||
ldionne: It used to be `__n <= ...`, now it's `__n < ...` -- what am I missing? | |||||
The initial version was aimed at optimizing 2 things:
For this change we should focus only on the former. The latter is better picked up as an FDO / LLVM compiler inlining opportunity. mvels: The initial version was aimed at optimizing 2 things:
- short optimization, i.e., [n] chars <… | |||||
? __assign_small_length(__s, __n) | |||||
: __assign_external(__s, __n); | |||||
} | |||||
template <class _CharT, class _Traits, class _Allocator> | |||||
basic_string<_CharT, _Traits, _Allocator>& | |||||
basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) | basic_string<_CharT, _Traits, _Allocator>::assign(size_type __n, value_type __c) | ||||
{ | { | ||||
size_type __cap = capacity(); | size_type __cap = capacity(); | ||||
if (__cap < __n) | if (__cap < __n) | ||||
{ | { | ||||
size_type __sz = size(); | size_type __sz = size(); | ||||
__grow_by(__cap, __n - __cap, __sz, 0, __sz); | __grow_by(__cap, __n - __cap, __sz, 0, __sz); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | basic_string<_CharT, _Traits, _Allocator>::assign(const _Tp & __t, size_type __pos, size_type __n) | ||||
if (__pos > __sz) | if (__pos > __sz) | ||||
this->__throw_out_of_range(); | this->__throw_out_of_range(); | ||||
return assign(__sv.data() + __pos, _VSTD::min(__n, __sz - __pos)); | return assign(__sv.data() + __pos, _VSTD::min(__n, __sz - __pos)); | ||||
} | } | ||||
template <class _CharT, class _Traits, class _Allocator> | template <class _CharT, class _Traits, class _Allocator> | ||||
basic_string<_CharT, _Traits, _Allocator>& | basic_string<_CharT, _Traits, _Allocator>& | ||||
basic_string<_CharT, _Traits, _Allocator>::__assign_external(const value_type* __s) { | |||||
return __assign_external(__s, traits_type::length(__s)); | |||||
} | |||||
template <class _CharT, class _Traits, class _Allocator> | |||||
basic_string<_CharT, _Traits, _Allocator>& | |||||
basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s) | basic_string<_CharT, _Traits, _Allocator>::assign(const value_type* __s) | ||||
{ | { | ||||
_LIBCPP_ASSERT(__s != nullptr, "string::assign received nullptr"); | _LIBCPP_ASSERT(__s != nullptr, "string::assign received nullptr"); | ||||
return assign(__s, traits_type::length(__s)); | return (__builtin_constant_p(*__s) && traits_type::length(__s) <= 128) | ||||
? __assign_small_length(__s, traits_type::length(__s)) | |||||
: __assign_external(__s); | |||||
} | } | ||||
// append | // append | ||||
template <class _CharT, class _Traits, class _Allocator> | template <class _CharT, class _Traits, class _Allocator> | ||||
basic_string<_CharT, _Traits, _Allocator>& | basic_string<_CharT, _Traits, _Allocator>& | ||||
basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n) | basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_type __n) | ||||
{ | { | ||||
_LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append received nullptr"); | _LIBCPP_ASSERT(__n == 0 || __s != nullptr, "string::append received nullptr"); | ||||
size_type __cap = capacity(); | size_type __cap = capacity(); | ||||
▲ Show 20 Lines • Show All 1,982 Lines • Show Last 20 Lines |
It used to be __n <= ..., now it's __n < ... -- what am I missing?