| //===----------------------------------------------------------------------===// |
| // |
| // 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 <cassert> |
| #include <string> |
| |
| #include "test_macros.h" |
| |
| template <class T> |
| 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 <class U> |
| constexpr soccc_allocator(const soccc_allocator<U>& a) : soccc_count(a.get_soccc()) {} |
| |
| constexpr T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); } |
| constexpr void deallocate(T* p, std::size_t s) { std::allocator<T>().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 <class U> |
| constexpr bool operator==(const soccc_allocator<U>& that) const { |
| return soccc_count == that.get_soccc(); |
| } |
| }; |
| |
| template <class CharT> |
| TEST_CONSTEXPR_CXX20 bool test() { |
| using S = std::basic_string<CharT, std::char_traits<CharT>, soccc_allocator<CharT>>; |
| { |
| int soccc_lhs = 0; |
| int soccc_rhs = 0; |
| S lhs(soccc_allocator<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<CharT>{&soccc_lhs}); |
| S rhs(soccc_allocator<CharT>{&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<char>(); |
| #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| test<wchar_t>(); |
| #endif |
| #if TEST_STD_VER > 17 |
| static_assert(test<char>()); |
| #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
| static_assert(test<wchar_t>()); |
| #endif |
| #endif |
| |
| return 0; |
| } |