Add common_policy_traits - a subset of hash_policy_traits that can be shared between raw_hash_set and btree.
Also remove the transfer implementations from btree_set.h and flat_hash_set.h, which are equivalent to the default implementations. Motivation: this will simplify upcoming changes related to trivial relocation. PiperOrigin-RevId: 477493403 Change-Id: I75babef4c93dec3a8105f86c58af54199bb1ec9cpull/1283/head
parent
df19c20996
commit
6d9ea2b46f
10 changed files with 279 additions and 156 deletions
@ -0,0 +1,101 @@ |
||||
// Copyright 2022 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ |
||||
#define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_ |
||||
|
||||
#include <cstddef> |
||||
#include <memory> |
||||
#include <new> |
||||
#include <type_traits> |
||||
#include <utility> |
||||
|
||||
#include "absl/meta/type_traits.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
namespace container_internal { |
||||
|
||||
// Defines how slots are initialized/destroyed/moved.
|
||||
template <class Policy, class = void> |
||||
struct common_policy_traits { |
||||
// The actual object stored in the container.
|
||||
using slot_type = typename Policy::slot_type; |
||||
|
||||
|
||||
// PRECONDITION: `slot` is UNINITIALIZED
|
||||
// POSTCONDITION: `slot` is INITIALIZED
|
||||
template <class Alloc, class... Args> |
||||
static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { |
||||
Policy::construct(alloc, slot, std::forward<Args>(args)...); |
||||
} |
||||
|
||||
// PRECONDITION: `slot` is INITIALIZED
|
||||
// POSTCONDITION: `slot` is UNINITIALIZED
|
||||
template <class Alloc> |
||||
static void destroy(Alloc* alloc, slot_type* slot) { |
||||
Policy::destroy(alloc, slot); |
||||
} |
||||
|
||||
// Transfers the `old_slot` to `new_slot`. Any memory allocated by the
|
||||
// allocator inside `old_slot` to `new_slot` can be transferred.
|
||||
//
|
||||
// OPTIONAL: defaults to:
|
||||
//
|
||||
// clone(new_slot, std::move(*old_slot));
|
||||
// destroy(old_slot);
|
||||
//
|
||||
// PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
|
||||
// POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
|
||||
// UNINITIALIZED
|
||||
template <class Alloc> |
||||
static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) { |
||||
transfer_impl(alloc, new_slot, old_slot, 0); |
||||
} |
||||
|
||||
// PRECONDITION: `slot` is INITIALIZED
|
||||
// POSTCONDITION: `slot` is INITIALIZED
|
||||
// Note: we use remove_const_t so that the two overloads have different args
|
||||
// in the case of sets with explicitly const value_types.
|
||||
template <class P = Policy> |
||||
static auto element(absl::remove_const_t<slot_type>* slot) |
||||
-> decltype(P::element(slot)) { |
||||
return P::element(slot); |
||||
} |
||||
template <class P = Policy> |
||||
static auto element(const slot_type* slot) -> decltype(P::element(slot)) { |
||||
return P::element(slot); |
||||
} |
||||
|
||||
private: |
||||
// Use auto -> decltype as an enabler.
|
||||
template <class Alloc, class P = Policy> |
||||
static auto transfer_impl(Alloc* alloc, slot_type* new_slot, |
||||
slot_type* old_slot, int) |
||||
-> decltype((void)P::transfer(alloc, new_slot, old_slot)) { |
||||
P::transfer(alloc, new_slot, old_slot); |
||||
} |
||||
template <class Alloc> |
||||
static void transfer_impl(Alloc* alloc, slot_type* new_slot, |
||||
slot_type* old_slot, char) { |
||||
construct(alloc, new_slot, std::move(element(old_slot))); |
||||
destroy(alloc, old_slot); |
||||
} |
||||
}; |
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
|
@ -0,0 +1,119 @@ |
||||
// Copyright 2022 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/container/internal/common_policy_traits.h" |
||||
|
||||
#include <functional> |
||||
#include <memory> |
||||
#include <new> |
||||
|
||||
#include "gmock/gmock.h" |
||||
#include "gtest/gtest.h" |
||||
|
||||
namespace absl { |
||||
ABSL_NAMESPACE_BEGIN |
||||
namespace container_internal { |
||||
namespace { |
||||
|
||||
using ::testing::MockFunction; |
||||
using ::testing::Return; |
||||
using ::testing::ReturnRef; |
||||
|
||||
using Slot = int; |
||||
|
||||
struct PolicyWithoutOptionalOps { |
||||
using slot_type = Slot; |
||||
using key_type = Slot; |
||||
using init_type = Slot; |
||||
|
||||
static std::function<void(void*, Slot*, Slot)> construct; |
||||
static std::function<void(void*, Slot*)> destroy; |
||||
|
||||
static std::function<Slot&(Slot*)> element; |
||||
}; |
||||
|
||||
std::function<void(void*, Slot*, Slot)> PolicyWithoutOptionalOps::construct; |
||||
std::function<void(void*, Slot*)> PolicyWithoutOptionalOps::destroy; |
||||
|
||||
std::function<Slot&(Slot*)> PolicyWithoutOptionalOps::element; |
||||
|
||||
struct PolicyWithOptionalOps : PolicyWithoutOptionalOps { |
||||
static std::function<void(void*, Slot*, Slot*)> transfer; |
||||
}; |
||||
|
||||
std::function<void(void*, Slot*, Slot*)> PolicyWithOptionalOps::transfer; |
||||
|
||||
struct Test : ::testing::Test { |
||||
Test() { |
||||
PolicyWithoutOptionalOps::construct = [&](void* a1, Slot* a2, Slot a3) { |
||||
construct.Call(a1, a2, std::move(a3)); |
||||
}; |
||||
PolicyWithoutOptionalOps::destroy = [&](void* a1, Slot* a2) { |
||||
destroy.Call(a1, a2); |
||||
}; |
||||
|
||||
PolicyWithoutOptionalOps::element = [&](Slot* a1) -> Slot& { |
||||
return element.Call(a1); |
||||
}; |
||||
|
||||
PolicyWithOptionalOps::transfer = [&](void* a1, Slot* a2, Slot* a3) { |
||||
return transfer.Call(a1, a2, a3); |
||||
}; |
||||
} |
||||
|
||||
std::allocator<Slot> alloc; |
||||
int a = 53; |
||||
|
||||
MockFunction<void(void*, Slot*, Slot)> construct; |
||||
MockFunction<void(void*, Slot*)> destroy; |
||||
|
||||
MockFunction<Slot&(Slot*)> element; |
||||
|
||||
MockFunction<void(void*, Slot*, Slot*)> transfer; |
||||
}; |
||||
|
||||
TEST_F(Test, construct) { |
||||
EXPECT_CALL(construct, Call(&alloc, &a, 53)); |
||||
common_policy_traits<PolicyWithoutOptionalOps>::construct(&alloc, &a, 53); |
||||
} |
||||
|
||||
TEST_F(Test, destroy) { |
||||
EXPECT_CALL(destroy, Call(&alloc, &a)); |
||||
common_policy_traits<PolicyWithoutOptionalOps>::destroy(&alloc, &a); |
||||
} |
||||
|
||||
TEST_F(Test, element) { |
||||
int b = 0; |
||||
EXPECT_CALL(element, Call(&a)).WillOnce(ReturnRef(b)); |
||||
EXPECT_EQ(&b, &common_policy_traits<PolicyWithoutOptionalOps>::element(&a)); |
||||
} |
||||
|
||||
TEST_F(Test, without_transfer) { |
||||
int b = 42; |
||||
EXPECT_CALL(element, Call(&b)).WillOnce(::testing::ReturnRef(b)); |
||||
EXPECT_CALL(construct, Call(&alloc, &a, b)); |
||||
EXPECT_CALL(destroy, Call(&alloc, &b)); |
||||
common_policy_traits<PolicyWithoutOptionalOps>::transfer(&alloc, &a, &b); |
||||
} |
||||
|
||||
TEST_F(Test, with_transfer) { |
||||
int b = 42; |
||||
EXPECT_CALL(transfer, Call(&alloc, &a, &b)); |
||||
common_policy_traits<PolicyWithOptionalOps>::transfer(&alloc, &a, &b); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END |
||||
} // namespace absl
|
Loading…
Reference in new issue