[libcxx-commits] [libcxx] 1cfa485 - [libc++] Implement P1165R1 (Make stateful allocator propagation more consistent)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Feb 17 13:01:07 PST 2022


Author: Nikolas Klauser
Date: 2022-02-17T22:00:48+01:00
New Revision: 1cfa4857693b405d21272414442b635d9678916e

URL: https://github.com/llvm/llvm-project/commit/1cfa4857693b405d21272414442b635d9678916e
DIFF: https://github.com/llvm/llvm-project/commit/1cfa4857693b405d21272414442b635d9678916e.diff

LOG: [libc++] Implement P1165R1 (Make stateful allocator propagation more consistent)

Reviewed By: Quuxplusone, ldionne, #libc

Spies: libcxx-commits

Differential Revision: https://reviews.llvm.org/D119112

Added: 
    libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/include/string

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index c57a7ded2e4f9..1e24ad6b3c550 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -39,6 +39,7 @@ New Features
 ------------
 
  - Implemented P0627R6 (Function to mark unreachable code)
+ - Implemented P1165R1 (Make stateful allocator propagation more consistent for operator+(basic_string))
 
 API Changes
 -----------

diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index cf983a4b4829f..438e1f07b896c 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -72,7 +72,7 @@
 "`P1085R2 <https://wg21.link/P1085R2>`__","LWG","Should Span be Regular?","San Diego","|Complete|","8.0"
 "`P1123R0 <https://wg21.link/P1123R0>`__","LWG","Editorial Guidance for merging P0019r8 and P0528r3","San Diego","* *",""
 "`P1148R0 <https://wg21.link/P1148R0>`__","LWG","Cleaning up Clause 20","San Diego","* *",""
-"`P1165R1 <https://wg21.link/P1165R1>`__","LWG","Make stateful allocator propagation more consistent for ``operator+(basic_string)``\ ","San Diego","* *",""
+"`P1165R1 <https://wg21.link/P1165R1>`__","LWG","Make stateful allocator propagation more consistent for ``operator+(basic_string)``\ ","San Diego","|Complete|","15.0"
 "`P1209R0 <https://wg21.link/P1209R0>`__","LWG","Adopt Consistent Container Erasure from Library Fundamentals 2 for C++20","San Diego","|Complete|","8.0"
 "`P1210R0 <https://wg21.link/P1210R0>`__","LWG","Completing the Rebase of Library Fundamentals, Version 3, Working Draft","San Diego","* *",""
 "`P1236R1 <https://wg21.link/P1236R1>`__","CWG","Alternative Wording for P0907R4 Signed Integers are Two's Complement","San Diego","* *",""

diff  --git a/libcxx/include/string b/libcxx/include/string
index 892df770756e2..d33f6edf97e9a 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -4161,9 +4161,10 @@ basic_string<_CharT, _Traits, _Allocator>
 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;
@@ -4173,9 +4174,10 @@ template<class _CharT, class _Traits, class _Allocator>
 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;
@@ -4185,8 +4187,9 @@ template<class _CharT, class _Traits, class _Allocator>
 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;
@@ -4197,9 +4200,10 @@ inline
 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;
@@ -4209,8 +4213,9 @@ template<class _CharT, class _Traits, class _Allocator>
 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
index 0000000000000..e25bff5fd7ad7
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.nonmembers/string_op+/allocator_propagation.pass.cpp
@@ -0,0 +1,200 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.soccc_count) {}
+
+  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() { 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;
+};
+
+template <class CharT>
+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;
+}


        


More information about the libcxx-commits mailing list