File: two_keys_adapter_map.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (157 lines) | stat: -rw-r--r-- 6,672 bytes parent folder | download | duplicates (5)
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_