//===----------------------------------------------------------------------===// // // 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 // This test ensures that we properly propagate allocators, per https://wg21.link/p1165r1 #include #include #include "test_macros.h" 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.get_soccc()) {} 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() const { return soccc_count; } constexpr auto get_self_soccc() const { 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; template constexpr bool operator==(const soccc_allocator& that) const { return soccc_count == that.get_soccc(); } }; template TEST_CONSTEXPR_CXX20 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(); #ifndef TEST_HAS_NO_WIDE_CHARACTERS test(); #endif #if TEST_STD_VER > 17 static_assert(test()); # ifndef TEST_HAS_NO_WIDE_CHARACTERS static_assert(test()); # endif #endif return 0; }