1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
// Copyright 2017 The Chromium Authors
// 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 <optional>
#include <utility>
#include "base/check.h"
#include "base/containers/contains.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(!base::Contains(entries_by_primary_, primary));
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);
CHECK(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_.empty(); }
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 std::optional.
std::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_
|