Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.5 KiB
207 lines
5.5 KiB
// Copyright 2018 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_H_ |
|
#define ABSL_CONTAINER_INTERNAL_COMMON_H_ |
|
|
|
#include <cassert> |
|
#include <type_traits> |
|
|
|
#include "absl/meta/type_traits.h" |
|
#include "absl/types/optional.h" |
|
|
|
namespace absl { |
|
ABSL_NAMESPACE_BEGIN |
|
namespace container_internal { |
|
|
|
template <class, class = void> |
|
struct IsTransparent : std::false_type {}; |
|
template <class T> |
|
struct IsTransparent<T, absl::void_t<typename T::is_transparent>> |
|
: std::true_type {}; |
|
|
|
template <bool is_transparent> |
|
struct KeyArg { |
|
// Transparent. Forward `K`. |
|
template <typename K, typename key_type> |
|
using type = K; |
|
}; |
|
|
|
template <> |
|
struct KeyArg<false> { |
|
// Not transparent. Always use `key_type`. |
|
template <typename K, typename key_type> |
|
using type = key_type; |
|
}; |
|
|
|
// The node_handle concept from C++17. |
|
// We specialize node_handle for sets and maps. node_handle_base holds the |
|
// common API of both. |
|
template <typename PolicyTraits, typename Alloc> |
|
class node_handle_base { |
|
protected: |
|
using slot_type = typename PolicyTraits::slot_type; |
|
|
|
public: |
|
using allocator_type = Alloc; |
|
|
|
constexpr node_handle_base() = default; |
|
node_handle_base(node_handle_base&& other) noexcept { |
|
*this = std::move(other); |
|
} |
|
~node_handle_base() { destroy(); } |
|
node_handle_base& operator=(node_handle_base&& other) noexcept { |
|
destroy(); |
|
if (!other.empty()) { |
|
alloc_ = other.alloc_; |
|
PolicyTraits::transfer(alloc(), slot(), other.slot()); |
|
other.reset(); |
|
} |
|
return *this; |
|
} |
|
|
|
bool empty() const noexcept { return !alloc_; } |
|
explicit operator bool() const noexcept { return !empty(); } |
|
allocator_type get_allocator() const { return *alloc_; } |
|
|
|
protected: |
|
friend struct CommonAccess; |
|
|
|
struct transfer_tag_t {}; |
|
node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s) |
|
: alloc_(a) { |
|
PolicyTraits::transfer(alloc(), slot(), s); |
|
} |
|
|
|
struct construct_tag_t {}; |
|
template <typename... Args> |
|
node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args) |
|
: alloc_(a) { |
|
PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...); |
|
} |
|
|
|
void destroy() { |
|
if (!empty()) { |
|
PolicyTraits::destroy(alloc(), slot()); |
|
reset(); |
|
} |
|
} |
|
|
|
void reset() { |
|
assert(alloc_.has_value()); |
|
alloc_ = absl::nullopt; |
|
} |
|
|
|
slot_type* slot() const { |
|
assert(!empty()); |
|
return reinterpret_cast<slot_type*>(std::addressof(slot_space_)); |
|
} |
|
allocator_type* alloc() { return std::addressof(*alloc_); } |
|
|
|
private: |
|
absl::optional<allocator_type> alloc_ = {}; |
|
alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {}; |
|
}; |
|
|
|
// For sets. |
|
template <typename Policy, typename PolicyTraits, typename Alloc, |
|
typename = void> |
|
class node_handle : public node_handle_base<PolicyTraits, Alloc> { |
|
using Base = node_handle_base<PolicyTraits, Alloc>; |
|
|
|
public: |
|
using value_type = typename PolicyTraits::value_type; |
|
|
|
constexpr node_handle() {} |
|
|
|
value_type& value() const { return PolicyTraits::element(this->slot()); } |
|
|
|
private: |
|
friend struct CommonAccess; |
|
|
|
using Base::Base; |
|
}; |
|
|
|
// For maps. |
|
template <typename Policy, typename PolicyTraits, typename Alloc> |
|
class node_handle<Policy, PolicyTraits, Alloc, |
|
absl::void_t<typename Policy::mapped_type>> |
|
: public node_handle_base<PolicyTraits, Alloc> { |
|
using Base = node_handle_base<PolicyTraits, Alloc>; |
|
using slot_type = typename PolicyTraits::slot_type; |
|
|
|
public: |
|
using key_type = typename Policy::key_type; |
|
using mapped_type = typename Policy::mapped_type; |
|
|
|
constexpr node_handle() {} |
|
|
|
// When C++17 is available, we can use std::launder to provide mutable |
|
// access to the key. Otherwise, we provide const access. |
|
auto key() const |
|
-> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) { |
|
return PolicyTraits::mutable_key(this->slot()); |
|
} |
|
|
|
mapped_type& mapped() const { |
|
return PolicyTraits::value(&PolicyTraits::element(this->slot())); |
|
} |
|
|
|
private: |
|
friend struct CommonAccess; |
|
|
|
using Base::Base; |
|
}; |
|
|
|
// Provide access to non-public node-handle functions. |
|
struct CommonAccess { |
|
template <typename Node> |
|
static auto GetSlot(const Node& node) -> decltype(node.slot()) { |
|
return node.slot(); |
|
} |
|
|
|
template <typename Node> |
|
static void Destroy(Node* node) { |
|
node->destroy(); |
|
} |
|
|
|
template <typename Node> |
|
static void Reset(Node* node) { |
|
node->reset(); |
|
} |
|
|
|
template <typename T, typename... Args> |
|
static T Transfer(Args&&... args) { |
|
return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...); |
|
} |
|
|
|
template <typename T, typename... Args> |
|
static T Construct(Args&&... args) { |
|
return T(typename T::construct_tag_t{}, std::forward<Args>(args)...); |
|
} |
|
}; |
|
|
|
// Implement the insert_return_type<> concept of C++17. |
|
template <class Iterator, class NodeType> |
|
struct InsertReturnType { |
|
Iterator position; |
|
bool inserted; |
|
NodeType node; |
|
}; |
|
|
|
} // namespace container_internal |
|
ABSL_NAMESPACE_END |
|
} // namespace absl |
|
|
|
#endif // ABSL_CONTAINER_INTERNAL_COMMON_H_
|
|
|