| // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_TWO_KEYS_ADAPTER_MAP_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_TWO_KEYS_ADAPTER_MAP_H_ |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/check.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "third_party/blink/renderer/platform/wtf/hash_map.h" |
| |
| namespace blink { |
| |
| // A map with up to two keys per entry. An element is inserted with a key, this |
| // is the primary key. A secondary key can optionally be set to the same entry |
| // and it may be set at a later point in time than the element was inserted. For |
| // lookup and erasure both keys can be used. |
| // |
| // This was designed to assist the implementation of adapter maps. The adapters |
| // are the glue between the blink and webrtc layer objects. The adapter maps |
| // keep track of which blink and webrtc layer objects have which associated |
| // adapter. This requires two keys per adapter entry: something that can be used |
| // for lookup based on a webrtc layer object and something that can be used for |
| // lookup based on a blink layer object. The primary key is based on the |
| // webrtc/blink object that was used to create the adapter and the secondary key |
| // is based on the resulting blink/webrtc object after the adapter has been |
| // initialized. |
| template <typename PrimaryKey, typename SecondaryKey, typename Value> |
| class TwoKeysAdapterMap { |
| public: |
| // Maps the primary key to the value, increasing |PrimarySize| by one and |
| // allowing lookup of the value based on primary key. Returns a pointer to the |
| // value in the map, the pointer is valid for as long as the value is in the |
| // map. There must not already exist a mapping for this primary key, in other |
| // words |!FindByPrimary(primary)| must hold. |
| Value* Insert(PrimaryKey primary, Value value) { |
| DCHECK(entries_by_primary_.find(primary) == entries_by_primary_.end()); |
| auto* add_result = |
| entries_by_primary_ |
| .insert(std::move(primary), |
| std::unique_ptr<Entry>(new Entry(std::move(value)))) |
| .stored_value; |
| add_result->value->primary_key = add_result->key; |
| return &add_result->value->value; |
| } |
| |
| // Maps the secondary key to the value mapped by the primary key, increasing |
| // |SecondarySize| by one and allowing lookup of the value based on secondary |
| // key. |
| // There must exist a mapping for this primary key and there must not already |
| // exist a mapping for this secondary key, in other words |
| // |FindByPrimary(primary) && !FindBySecondary(secondary)| must hold. |
| void SetSecondaryKey(const PrimaryKey& primary, SecondaryKey secondary) { |
| auto it = entries_by_primary_.find(primary); |
| DCHECK(it != entries_by_primary_.end()); |
| DCHECK(entries_by_secondary_.find(secondary) == |
| entries_by_secondary_.end()); |
| Entry* entry = it->value.get(); |
| auto* add_result = |
| entries_by_secondary_.insert(std::move(secondary), entry).stored_value; |
| entry->secondary_key = add_result->key; |
| } |
| |
| // Returns a pointer to the value mapped by the primary key, or null if the |
| // primary key is not mapped to any value. The pointer is valid for as long as |
| // the value is in the map. |
| Value* FindByPrimary(const PrimaryKey& primary) const { |
| auto it = entries_by_primary_.find(primary); |
| if (it == entries_by_primary_.end()) |
| return nullptr; |
| return &it->value->value; |
| } |
| |
| // Returns a pointer to the value mapped by the secondary key, or null if the |
| // secondary key is not mapped to any value. The pointer is valid for as long |
| // as the value is in the map. |
| Value* FindBySecondary(const SecondaryKey& secondary) const { |
| auto it = entries_by_secondary_.find(secondary); |
| if (it == entries_by_secondary_.end()) |
| return nullptr; |
| return &it->value->value; |
| } |
| |
| // Erases the value associated with the primary key, removing the mapping of |
| // of its primary and secondary key, if it had one. Returns true on removal or |
| // false if there was no value associated with the primary key. |
| bool EraseByPrimary(const PrimaryKey& primary) { |
| auto primary_it = entries_by_primary_.find(primary); |
| if (primary_it == entries_by_primary_.end()) |
| return false; |
| |
| if (primary_it->value->secondary_key.has_value()) { |
| auto secondary_it = |
| entries_by_secondary_.find(*primary_it->value->secondary_key); |
| if (secondary_it != entries_by_secondary_.end()) |
| entries_by_secondary_.erase(secondary_it); |
| } |
| entries_by_primary_.erase(primary_it); |
| return true; |
| } |
| |
| // Erases the value associated with the secondary key, removing the mapping of |
| // of both its primary and secondary keys. Returns true on removal or false if |
| // there was no value associated with the secondary key. |
| bool EraseBySecondary(const SecondaryKey& secondary) { |
| auto secondary_it = entries_by_secondary_.find(secondary); |
| if (secondary_it == entries_by_secondary_.end()) |
| return false; |
| |
| auto primary_it = |
| entries_by_primary_.find(secondary_it->value->primary_key); |
| entries_by_primary_.erase(primary_it); |
| entries_by_secondary_.erase(secondary_it); |
| return true; |
| } |
| |
| // The number of elements in the map. |
| size_t PrimarySize() const { return entries_by_primary_.size(); } |
| // The number of elements in the map which have secondary keys. |
| size_t SecondarySize() const { return entries_by_secondary_.size(); } |
| bool empty() const { return entries_by_primary_.IsEmpty(); } |
| |
| private: |
| struct Entry { |
| Entry(Value value) : value(std::move(value)) {} |
| |
| Value value; |
| |
| // The primary and secondary keys are cached here, instead of the |
| // respective iterators, because WTF::HashMap invalidates iterators |
| // upon changes on the set (eg insertion, deletions). |
| // |
| // Entries are only created in TwoKeysAdapterMap::Insert, which initializes |
| // |primary_key| right afterward (so it can never be read while |
| // uninitialized). |
| PrimaryKey primary_key; |
| |
| // However, for |secondary_key|, calling EraseByPrimaryKey() can |
| // read an uninitialized secondary_key in case it is left uninitialized. |
| // Hence, it is guarded with absl::optional. |
| absl::optional<SecondaryKey> secondary_key; |
| }; |
| |
| using PrimaryMap = WTF::HashMap<PrimaryKey, std::unique_ptr<Entry>>; |
| using SecondaryMap = WTF::HashMap<SecondaryKey, Entry*>; |
| |
| PrimaryMap entries_by_primary_; |
| SecondaryMap entries_by_secondary_; |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_TWO_KEYS_ADAPTER_MAP_H_ |