// 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_RAW_HASH_MAP_H_ #define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_ #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/throw_delegate.h" #include "absl/container/internal/common_policy_traits.h" #include "absl/container/internal/container_memory.h" #include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export #include "absl/meta/type_traits.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace container_internal { template class raw_hash_map : public raw_hash_set { // P is Policy. It's passed as a template argument to support maps that have // incomplete types as values, as in unordered_map. // MappedReference<> may be a non-reference type. template using MappedReference = decltype(P::value( std::addressof(std::declval()))); // MappedConstReference<> may be a non-reference type. template using MappedConstReference = decltype(P::value( std::addressof(std::declval()))); template using key_arg = typename KeyArg::value && IsTransparent::value>:: template type; // NOTE: The mess here is to shorten the code for the (very repetitive) // function overloads, and to allow the lifetime-bound overloads to dispatch // to the non-lifetime-bound overloads, to ensure there is a single source of // truth for each overload set. // // Enabled if an assignment from the given type would require the // source object to remain alive for the life of the element. // // TODO(b/402804213): Remove these traits and simplify the overloads whenever // we have a better mechanism available to handle lifetime analysis. template using LifetimeBoundK = HasValue< Value, std::conditional_t::value, std::false_type, type_traits_internal::IsLifetimeBoundAssignment< typename Policy::key_type, K>>>; template using LifetimeBoundV = HasValue>; template using LifetimeBoundKV = absl::conjunction>, LifetimeBoundV>; public: using key_type = typename Policy::key_type; using mapped_type = typename Policy::mapped_type; static_assert(!std::is_reference::value, ""); // TODO(b/187807849): Evaluate whether to support reference mapped_type and // remove this assertion if/when it is supported. static_assert(!std::is_reference::value, ""); using iterator = typename raw_hash_map::raw_hash_set::iterator; using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator; raw_hash_map() {} using raw_hash_map::raw_hash_set::raw_hash_set; // The last two template parameters ensure that both arguments are rvalues // (lvalue arguments are handled by the overloads below). This is necessary // for supporting bitfield arguments. // // union { int n : 1; }; // flat_hash_map m; // m.insert_or_assign(n, n); // // TODO(b/402804213): Remove these macros whenever we have a better mechanism // available to handle lifetime analysis. #define ABSL_INTERNAL_X(Func, Callee, KQual, VQual, KValue, VValue, Tail, ...) \ template < \ typename K = key_type, class V = mapped_type, \ ABSL_INTERNAL_IF_##KValue##_NOR_##VValue( \ int = (EnableIf::AddPtr, \ IfRRef::AddPtr>>()), \ ABSL_INTERNAL_SINGLE_ARG( \ int &..., \ decltype(EnableIf>()) = \ 0))> \ decltype(auto) Func( \ __VA_ARGS__ key_arg KQual k ABSL_INTERNAL_IF_##KValue( \ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \ V VQual v ABSL_INTERNAL_IF_##VValue(ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY( \ this))) ABSL_ATTRIBUTE_LIFETIME_BOUND { \ return ABSL_INTERNAL_IF_##KValue##_OR_##VValue( \ (this->template Func), Callee)( \ std::forward(k), std::forward(v)) Tail; \ } \ static_assert(true, "This is to force a semicolon.") ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, false, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, false, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, true, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, true, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true, ABSL_INTERNAL_SINGLE_ARG()); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, false, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, false, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, true, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &, true, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false, .first, const_iterator ABSL_INTERNAL_COMMA); ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true, .first, const_iterator ABSL_INTERNAL_COMMA); #undef ABSL_INTERNAL_X // All `try_emplace()` overloads make the same guarantees regarding rvalue // arguments as `std::unordered_map::try_emplace()`, namely that these // functions will not move from rvalue arguments if insertions do not happen. template >(), class... Args, typename std::enable_if< !std::is_convertible::value, int>::type = 0> std::pair try_emplace(key_arg &&k, Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return try_emplace_impl(std::forward(k), std::forward(args)...); } template > = 0, typename std::enable_if< !std::is_convertible::value, int>::type = 0> std::pair try_emplace( key_arg &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this), Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template try_emplace(std::forward(k), std::forward(args)...); } template >(), class... Args, typename std::enable_if< !std::is_convertible::value, int>::type = 0> std::pair try_emplace(const key_arg &k, Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return try_emplace_impl(k, std::forward(args)...); } template > = 0, typename std::enable_if< !std::is_convertible::value, int>::type = 0> std::pair try_emplace( const key_arg &k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this), Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template try_emplace(k, std::forward(args)...); } template >(), class... Args> iterator try_emplace(const_iterator, key_arg &&k, Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return try_emplace(std::forward(k), std::forward(args)...).first; } template > = 0> iterator try_emplace(const_iterator hint, key_arg &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this), Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template try_emplace(hint, std::forward(k), std::forward(args)...); } template >(), class... Args> iterator try_emplace(const_iterator, const key_arg &k, Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return try_emplace(k, std::forward(args)...).first; } template > = 0> iterator try_emplace(const_iterator hint, const key_arg &k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this), Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template try_emplace(hint, std::forward(k), std::forward(args)...); } template MappedReference

at(const key_arg& key) ABSL_ATTRIBUTE_LIFETIME_BOUND { auto it = this->find(key); if (it == this->end()) { base_internal::ThrowStdOutOfRange( "absl::container_internal::raw_hash_map<>::at"); } return Policy::value(&*it); } template MappedConstReference

at(const key_arg& key) const ABSL_ATTRIBUTE_LIFETIME_BOUND { auto it = this->find(key); if (it == this->end()) { base_internal::ThrowStdOutOfRange( "absl::container_internal::raw_hash_map<>::at"); } return Policy::value(&*it); } template >()> MappedReference

operator[](key_arg &&key) ABSL_ATTRIBUTE_LIFETIME_BOUND { // It is safe to use unchecked_deref here because try_emplace // will always return an iterator pointing to a valid item in the table, // since it inserts if nothing is found for the given key. return Policy::value( &this->unchecked_deref(try_emplace(std::forward(key)).first)); } template > = 0> MappedReference

operator[]( key_arg &&key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template operator[](std::forward(key)); } template >()> MappedReference

operator[](const key_arg &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { // It is safe to use unchecked_deref here because try_emplace // will always return an iterator pointing to a valid item in the table, // since it inserts if nothing is found for the given key. return Policy::value(&this->unchecked_deref(try_emplace(key).first)); } template > = 0> MappedReference

operator[]( const key_arg &key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)) ABSL_ATTRIBUTE_LIFETIME_BOUND { return this->template operator[](key); } private: template std::pair insert_or_assign_impl(K&& k, V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND { auto res = this->find_or_prepare_insert(k); if (res.second) { this->emplace_at(res.first, std::forward(k), std::forward(v)); } else { Policy::value(&*res.first) = std::forward(v); } return res; } template std::pair try_emplace_impl(K&& k, Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND { auto res = this->find_or_prepare_insert(k); if (res.second) { this->emplace_at(res.first, std::piecewise_construct, std::forward_as_tuple(std::forward(k)), std::forward_as_tuple(std::forward(args)...)); } return res; } }; } // namespace container_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_