diff --git a/libcxx/include/string b/libcxx/include/string --- a/libcxx/include/string +++ b/libcxx/include/string @@ -4144,9 +4144,10 @@ operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const basic_string<_CharT, _Traits, _Allocator>& __rhs) { - basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); + using _String = basic_string<_CharT, _Traits, _Allocator>; + _String __r(_String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + typename _String::size_type __lhs_sz = __lhs.size(); + typename _String::size_type __rhs_sz = __rhs.size(); __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + __rhs_sz); __r.append(__rhs.data(), __rhs_sz); return __r; @@ -4156,9 +4157,10 @@ basic_string<_CharT, _Traits, _Allocator> operator+(const _CharT* __lhs , const basic_string<_CharT,_Traits,_Allocator>& __rhs) { - basic_string<_CharT, _Traits, _Allocator> __r(__rhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = _Traits::length(__lhs); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); + using _String = basic_string<_CharT, _Traits, _Allocator>; + _String __r(_String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator())); + typename _String::size_type __lhs_sz = _Traits::length(__lhs); + typename _String::size_type __rhs_sz = __rhs.size(); __r.__init(__lhs, __lhs_sz, __lhs_sz + __rhs_sz); __r.append(__rhs.data(), __rhs_sz); return __r; @@ -4168,8 +4170,9 @@ basic_string<_CharT, _Traits, _Allocator> operator+(_CharT __lhs, const basic_string<_CharT,_Traits,_Allocator>& __rhs) { - basic_string<_CharT, _Traits, _Allocator> __r(__rhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = __rhs.size(); + using _String = basic_string<_CharT, _Traits, _Allocator>; + _String __r(_String::__alloc_traits::select_on_container_copy_construction(__rhs.get_allocator())); + typename _String::size_type __rhs_sz = __rhs.size(); __r.__init(&__lhs, 1, 1 + __rhs_sz); __r.append(__rhs.data(), __rhs_sz); return __r; @@ -4180,9 +4183,10 @@ basic_string<_CharT, _Traits, _Allocator> operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, const _CharT* __rhs) { - basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __rhs_sz = _Traits::length(__rhs); + using _String = basic_string<_CharT, _Traits, _Allocator>; + _String __r(_String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + typename _String::size_type __lhs_sz = __lhs.size(); + typename _String::size_type __rhs_sz = _Traits::length(__rhs); __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + __rhs_sz); __r.append(__rhs, __rhs_sz); return __r; @@ -4192,8 +4196,9 @@ basic_string<_CharT, _Traits, _Allocator> operator+(const basic_string<_CharT, _Traits, _Allocator>& __lhs, _CharT __rhs) { - basic_string<_CharT, _Traits, _Allocator> __r(__lhs.get_allocator()); - typename basic_string<_CharT, _Traits, _Allocator>::size_type __lhs_sz = __lhs.size(); + using _String = basic_string<_CharT, _Traits, _Allocator>; + _String __r(_String::__alloc_traits::select_on_container_copy_construction(__lhs.get_allocator())); + typename _String::size_type __lhs_sz = __lhs.size(); __r.__init(__lhs.data(), __lhs_sz, __lhs_sz + 1); __r.push_back(__rhs); return __r; diff --git a/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass.cpp b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass.cpp @@ -0,0 +1,187 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include + +template +class soccc_allocator { + int* soccc_count; + int self_soccc_count; + +public: + using value_type = T; + + constexpr explicit soccc_allocator(int* soccc_count_, int self_coccc_count_ = 0) + : soccc_count(soccc_count_), self_soccc_count(self_coccc_count_) {} + + template + constexpr soccc_allocator(const soccc_allocator& a) : soccc_count(a.soccc_count) {} + + constexpr T* allocate(std::size_t n) { return std::allocator().allocate(n); } + constexpr void deallocate(T* p, std::size_t s) { std::allocator().deallocate(p, s); } + + constexpr soccc_allocator select_on_container_copy_construction() const { + *soccc_count += 1; + return soccc_allocator(soccc_count, self_soccc_count + 1); + } + + constexpr auto get_soccc() { return soccc_count; } + constexpr auto get_self_soccc() { return self_soccc_count; } + + typedef std::true_type propagate_on_container_copy_assignment; + typedef std::true_type propagate_on_container_move_assignment; + typedef std::true_type propagate_on_container_swap; +}; + +bool test() { + using S = std::basic_string, soccc_allocator>; + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs + rhs; + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 1); + assert(soccc_lhs == 1); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs + std::move(rhs); + assert(r.get_allocator().get_soccc() == &soccc_rhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = std::move(lhs) + rhs; + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = std::move(lhs) + std::move(rhs); + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs + rhs.data(); + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 1); + assert(soccc_lhs == 1); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs + rhs[0]; + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 1); + assert(soccc_lhs == 1); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = std::move(lhs) + rhs.data(); + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = std::move(lhs) + rhs[0]; + assert(r.get_allocator().get_soccc() == &soccc_lhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs.data() + rhs; + assert(r.get_allocator().get_soccc() == &soccc_rhs); + assert(r.get_allocator().get_self_soccc() == 1); + assert(soccc_lhs == 0); + assert(soccc_rhs == 1); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs[0] + rhs; + assert(r.get_allocator().get_soccc() == &soccc_rhs); + assert(r.get_allocator().get_self_soccc() == 1); + assert(soccc_lhs == 0); + assert(soccc_rhs == 1); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs.data() + std::move(rhs); + assert(r.get_allocator().get_soccc() == &soccc_rhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + { + int soccc_lhs = 0; + int soccc_rhs = 0; + S lhs(soccc_allocator{&soccc_lhs}); + S rhs(soccc_allocator{&soccc_rhs}); + auto r = lhs[0] + std::move(rhs); + assert(r.get_allocator().get_soccc() == &soccc_rhs); + assert(r.get_allocator().get_self_soccc() == 0); + assert(soccc_lhs == 0); + assert(soccc_rhs == 0); + } + + return true; +} + +int main(int, char**) { + test(); + // static_assert(test()); + + return 0; +}