summaryrefslogtreecommitdiffstats
path: root/dom/media/doctor/DDLifetimes.h
blob: 3cfcafc99555231c48bdfc087219428b4df446a2 (plain)
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
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef DDLifetimes_h_
#define DDLifetimes_h_

#include <type_traits>

#include "DDLifetime.h"
#include "DDLoggedTypeTraits.h"
#include "nsClassHashtable.h"
#include "nsTArray.h"

namespace mozilla {

// Managed list of lifetimes.
class DDLifetimes {
 public:
  // DDLifetime for a given aObject, that exists at the aIndex time;
  // otherwise nullptr.
  DDLifetime* FindLifetime(const DDLogObject& aObject,
                           const DDMessageIndex& aIndex);

  // DDLifetime for a given aObject, that exists at the aIndex time;
  // otherwise nullptr.
  const DDLifetime* FindLifetime(const DDLogObject& aObject,
                                 const DDMessageIndex& aIndex) const;

  // Create a lifetime with the given object and construction index&time.
  DDLifetime& CreateLifetime(const DDLogObject& aObject, DDMessageIndex aIndex,
                             const DDTimeStamp& aConstructionTimeStamp);

  // Remove an existing lifetime (assumed to just have been found by
  // FindLifetime()).
  void RemoveLifetime(const DDLifetime* aLifetime);

  // Remove all lifetimes associated with the given HTMLMediaElement.
  void RemoveLifetimesFor(const dom::HTMLMediaElement* aMediaElement);

  // Remove all lifetimes.
  void Clear();

  // Visit all lifetimes associated with an HTMLMediaElement and run
  // `aF(const DDLifetime&)` on each one.
  // If aOnlyHTMLMediaElement is true, only run aF once of that element.
  template <typename F>
  void Visit(const dom::HTMLMediaElement* aMediaElement, F&& aF,
             bool aOnlyHTMLMediaElement = false) const {
    for (const auto& lifetimes : mLifetimes.Values()) {
      for (const DDLifetime& lifetime : *lifetimes) {
        if (lifetime.mMediaElement == aMediaElement) {
          if (aOnlyHTMLMediaElement) {
            if (lifetime.mObject.Pointer() == aMediaElement &&
                lifetime.mObject.TypeName() ==
                    DDLoggedTypeTraits<dom::HTMLMediaElement>::Name()) {
              aF(lifetime);
              break;
            }
            continue;
          }
          static_assert(std::is_same_v<decltype(aF(lifetime)), void>, "");
          aF(lifetime);
        }
      }
    }
  }

  // Visit all lifetimes associated with an HTMLMediaElement and run
  // `aF(const DDLifetime&)` on each one.
  // If aF() returns false, the loop continues.
  // If aF() returns true, the loop stops, and true is returned immediately.
  // If all aF() calls have returned false, false is returned at the end.
  template <typename F>
  bool VisitBreakable(const dom::HTMLMediaElement* aMediaElement,
                      F&& aF) const {
    for (const auto& lifetimes : mLifetimes.Values()) {
      for (const DDLifetime& lifetime : *lifetimes) {
        if (lifetime.mMediaElement == aMediaElement) {
          static_assert(std::is_same_v<decltype(aF(lifetime)), bool>, "");
          if (aF(lifetime)) {
            return true;
          }
        }
      }
    }
    return false;
  }

  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;

 private:
  // Hashtable key to use for each DDLogObject.
  class DDLogObjectHashKey : public PLDHashEntryHdr {
   public:
    typedef const DDLogObject& KeyType;
    typedef const DDLogObject* KeyTypePointer;

    explicit DDLogObjectHashKey(KeyTypePointer aKey) : mValue(*aKey) {}
    DDLogObjectHashKey(const DDLogObjectHashKey& aToCopy)
        : mValue(aToCopy.mValue) {}
    ~DDLogObjectHashKey() = default;

    KeyType GetKey() const { return mValue; }
    bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }

    static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
    static PLDHashNumber HashKey(KeyTypePointer aKey) {
      return HashBytes(aKey, sizeof(DDLogObject));
    }
    enum { ALLOW_MEMMOVE = true };

   private:
    const DDLogObject mValue;
  };

  // Array of all DDLifetimes for a given DDLogObject; they should be
  // distinguished by their construction&destruction times.
  using LifetimesForObject = nsTArray<DDLifetime>;

  // For each DDLogObject, we store an array of all objects that have used this
  // pointer and type.
  nsClassHashtable<DDLogObjectHashKey, LifetimesForObject> mLifetimes;
};

}  // namespace mozilla

#endif  // DDLifetimes_h_