summaryrefslogtreecommitdiff
path: root/absl/container
diff options
context:
space:
mode:
Diffstat (limited to 'absl/container')
-rw-r--r--absl/container/BUILD.bazel2
-rw-r--r--absl/container/internal/container_memory.h14
-rw-r--r--absl/container/internal/raw_hash_set.h28
-rw-r--r--absl/container/internal/raw_hash_set_allocator_test.cc71
4 files changed, 101 insertions, 14 deletions
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index cca5d441..8e72ad03 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -24,7 +24,7 @@ load(
package(default_visibility = ["//visibility:public"])
-licenses(["notice"]) # Apache 2.0
+licenses(["notice"])
cc_library(
name = "compressed_tuple",
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index d02c576d..e67529ec 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -57,8 +57,11 @@ void* Allocate(Alloc* alloc, size_t n) {
using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
+ // On macOS, "mem_alloc" is a #define with one argument defined in
+ // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+ // with the "foo(bar)" syntax.
+ A my_mem_alloc(*alloc);
+ void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
"allocator does not respect alignment");
return p;
@@ -73,8 +76,11 @@ void Deallocate(Alloc* alloc, void* p, size_t n) {
using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- AT::deallocate(mem_alloc, static_cast<M*>(p),
+ // On macOS, "mem_alloc" is a #define with one argument defined in
+ // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
+ // with the "foo(bar)" syntax.
+ A my_mem_alloc(*alloc);
+ AT::deallocate(my_mem_alloc, static_cast<M*>(p),
(n + sizeof(M) - 1) / sizeof(M));
}
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 48a1a8c6..130da13c 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -122,6 +122,16 @@ namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
+template <typename AllocType>
+void SwapAlloc(AllocType& lhs, AllocType& rhs,
+ std::true_type /* propagate_on_container_swap */) {
+ using std::swap;
+ swap(lhs, rhs);
+}
+template <typename AllocType>
+void SwapAlloc(AllocType& /*lhs*/, AllocType& /*rhs*/,
+ std::false_type /* propagate_on_container_swap */) {}
+
template <size_t Width>
class probe_seq {
public:
@@ -169,10 +179,14 @@ struct IsDecomposable<
// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
template <class T>
-constexpr bool IsNoThrowSwappable() {
+constexpr bool IsNoThrowSwappable(std::true_type = {} /* is_swappable */) {
using std::swap;
return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
}
+template <class T>
+constexpr bool IsNoThrowSwappable(std::false_type /* is_swappable */) {
+ return false;
+}
template <typename T>
int TrailingZeros(T x) {
@@ -1231,8 +1245,8 @@ class raw_hash_set {
void swap(raw_hash_set& that) noexcept(
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
- (!AllocTraits::propagate_on_container_swap::value ||
- IsNoThrowSwappable<allocator_type>())) {
+ IsNoThrowSwappable<allocator_type>(
+ typename AllocTraits::propagate_on_container_swap{})) {
using std::swap;
swap(ctrl_, that.ctrl_);
swap(slots_, that.slots_);
@@ -1242,12 +1256,8 @@ class raw_hash_set {
swap(hash_ref(), that.hash_ref());
swap(eq_ref(), that.eq_ref());
swap(infoz_, that.infoz_);
- if (AllocTraits::propagate_on_container_swap::value) {
- swap(alloc_ref(), that.alloc_ref());
- } else {
- // If the allocators do not compare equal it is officially undefined
- // behavior. We choose to do nothing.
- }
+ SwapAlloc(alloc_ref(), that.alloc_ref(),
+ typename AllocTraits::propagate_on_container_swap{});
}
void rehash(size_t n) {
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc
index 7ac4b9f7..1a036085 100644
--- a/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -424,6 +424,77 @@ TEST_F(PropagateOnAll, Swap) {
EXPECT_EQ(0, it->num_copies());
}
+// This allocator is similar to std::pmr::polymorphic_allocator.
+// Note the disabled assignment.
+template <class T>
+class PAlloc {
+ template <class>
+ friend class PAlloc;
+
+ public:
+ // types
+ using value_type = T;
+
+ // traits
+ using propagate_on_container_swap = std::false_type;
+
+ PAlloc() noexcept = default;
+ explicit PAlloc(size_t id) noexcept : id_(id) {}
+ PAlloc(const PAlloc&) noexcept = default;
+ PAlloc& operator=(const PAlloc&) noexcept = delete;
+
+ template <class U>
+ PAlloc(const PAlloc<U>& that) noexcept : id_(that.id_) {} // NOLINT
+
+ template <class U>
+ struct rebind {
+ using other = PAlloc<U>;
+ };
+
+ constexpr PAlloc select_on_container_copy_construction() const { return {}; }
+
+ // public member functions
+ T* allocate(size_t) { return new T; }
+ void deallocate(T* p, size_t) { delete p; }
+
+ friend bool operator==(const PAlloc& a, const PAlloc& b) {
+ return a.id_ == b.id_;
+ }
+ friend bool operator!=(const PAlloc& a, const PAlloc& b) { return !(a == b); }
+
+ private:
+ size_t id_ = std::numeric_limits<size_t>::max();
+};
+
+TEST(NoPropagateOn, Swap) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(PA{2});
+ swap(t1, t2);
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+
+TEST(NoPropagateOn, CopyConstruct) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(t1);
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA());
+}
+
+TEST(NoPropagateOn, Assignment) {
+ using PA = PAlloc<char>;
+ using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
+
+ Table t1(PA{1}), t2(PA{2});
+ t1 = t2;
+ EXPECT_EQ(t1.get_allocator(), PA(1));
+ EXPECT_EQ(t2.get_allocator(), PA(2));
+}
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END