123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- // 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_
|