xref: /aosp_15_r20/external/openscreen/util/weak_ptr.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #ifndef UTIL_WEAK_PTR_H_
6*3f982cf4SFabien Sanglard #define UTIL_WEAK_PTR_H_
7*3f982cf4SFabien Sanglard 
8*3f982cf4SFabien Sanglard #include <memory>
9*3f982cf4SFabien Sanglard #include <utility>
10*3f982cf4SFabien Sanglard 
11*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
12*3f982cf4SFabien Sanglard 
13*3f982cf4SFabien Sanglard namespace openscreen {
14*3f982cf4SFabien Sanglard 
15*3f982cf4SFabien Sanglard // Weak pointers are pointers to an object that do not affect its lifetime,
16*3f982cf4SFabien Sanglard // and which may be invalidated (i.e. reset to nullptr) by the object, or its
17*3f982cf4SFabien Sanglard // owner, at any time; most commonly when the object is about to be deleted.
18*3f982cf4SFabien Sanglard //
19*3f982cf4SFabien Sanglard // Weak pointers are useful when an object needs to be accessed safely by one
20*3f982cf4SFabien Sanglard // or more objects other than its owner, and those callers can cope with the
21*3f982cf4SFabien Sanglard // object vanishing and e.g. tasks posted to it being silently dropped.
22*3f982cf4SFabien Sanglard // Reference-counting such an object would complicate the ownership graph and
23*3f982cf4SFabien Sanglard // make it harder to reason about the object's lifetime.
24*3f982cf4SFabien Sanglard //
25*3f982cf4SFabien Sanglard // EXAMPLE:
26*3f982cf4SFabien Sanglard //
27*3f982cf4SFabien Sanglard //  class Controller {
28*3f982cf4SFabien Sanglard //   public:
29*3f982cf4SFabien Sanglard //    void SpawnWorker() { new Worker(weak_factory_.GetWeakPtr()); }
30*3f982cf4SFabien Sanglard //    void WorkComplete(const Result& result) { ... }
31*3f982cf4SFabien Sanglard //   private:
32*3f982cf4SFabien Sanglard //    // Member variables should appear before the WeakPtrFactory, to ensure
33*3f982cf4SFabien Sanglard //    // that any WeakPtrs to Controller are invalidated before its members
34*3f982cf4SFabien Sanglard //    // variable's destructors are executed, rendering them invalid.
35*3f982cf4SFabien Sanglard //    WeakPtrFactory<Controller> weak_factory_{this};
36*3f982cf4SFabien Sanglard //  };
37*3f982cf4SFabien Sanglard //
38*3f982cf4SFabien Sanglard //  class Worker {
39*3f982cf4SFabien Sanglard //   public:
40*3f982cf4SFabien Sanglard //    explicit Worker(WeakPtr<Controller> controller)
41*3f982cf4SFabien Sanglard //        : controller_(std::move(controller)) {}
42*3f982cf4SFabien Sanglard //   private:
43*3f982cf4SFabien Sanglard //    void DidCompleteAsynchronousProcessing(const Result& result) {
44*3f982cf4SFabien Sanglard //      if (controller_)
45*3f982cf4SFabien Sanglard //        controller_->WorkComplete(result);
46*3f982cf4SFabien Sanglard //      delete this;
47*3f982cf4SFabien Sanglard //    }
48*3f982cf4SFabien Sanglard //    const WeakPtr<Controller> controller_;
49*3f982cf4SFabien Sanglard //  };
50*3f982cf4SFabien Sanglard //
51*3f982cf4SFabien Sanglard // With this implementation a caller may use SpawnWorker() to dispatch multiple
52*3f982cf4SFabien Sanglard // Workers and subsequently delete the Controller, without waiting for all
53*3f982cf4SFabien Sanglard // Workers to have completed.
54*3f982cf4SFabien Sanglard //
55*3f982cf4SFabien Sanglard // ------------------------- IMPORTANT: Thread-safety -------------------------
56*3f982cf4SFabien Sanglard //
57*3f982cf4SFabien Sanglard // Generally, Open Screen code is meant to be single-threaded. For the few
58*3f982cf4SFabien Sanglard // exceptional cases, the following is relevant:
59*3f982cf4SFabien Sanglard //
60*3f982cf4SFabien Sanglard // WeakPtrs may be created from WeakPtrFactory, and also duplicated/moved on any
61*3f982cf4SFabien Sanglard // thread/sequence. However, they may only be dereferenced on the same
62*3f982cf4SFabien Sanglard // thread/sequence that will ultimately execute the WeakPtrFactory destructor or
63*3f982cf4SFabien Sanglard // call InvalidateWeakPtrs(). Otherwise, use-during-free or use-after-free is
64*3f982cf4SFabien Sanglard // possible.
65*3f982cf4SFabien Sanglard //
66*3f982cf4SFabien Sanglard // openscreen::WeakPtr and WeakPtrFactory are similar, but not identical, to
67*3f982cf4SFabien Sanglard // Chromium's base::WeakPtrFactory. Open Screen WeakPtrs may be safely created
68*3f982cf4SFabien Sanglard // from WeakPtrFactory on any thread/sequence, since they are backed by the
69*3f982cf4SFabien Sanglard // thread-safe bookkeeping of std::shared_ptr<>.
70*3f982cf4SFabien Sanglard 
71*3f982cf4SFabien Sanglard template <typename T>
72*3f982cf4SFabien Sanglard class WeakPtrFactory;
73*3f982cf4SFabien Sanglard 
74*3f982cf4SFabien Sanglard template <typename T>
75*3f982cf4SFabien Sanglard class WeakPtr {
76*3f982cf4SFabien Sanglard  public:
77*3f982cf4SFabien Sanglard   WeakPtr() = default;
78*3f982cf4SFabien Sanglard   ~WeakPtr() = default;
79*3f982cf4SFabien Sanglard 
80*3f982cf4SFabien Sanglard   // Copy/Move constructors and assignment operators.
WeakPtr(const WeakPtr & other)81*3f982cf4SFabien Sanglard   WeakPtr(const WeakPtr& other) : impl_(other.impl_) {}
82*3f982cf4SFabien Sanglard 
WeakPtr(WeakPtr && other)83*3f982cf4SFabien Sanglard   WeakPtr(WeakPtr&& other) noexcept : impl_(std::move(other.impl_)) {}
84*3f982cf4SFabien Sanglard 
85*3f982cf4SFabien Sanglard   WeakPtr& operator=(const WeakPtr& other) {
86*3f982cf4SFabien Sanglard     impl_ = other.impl_;
87*3f982cf4SFabien Sanglard     return *this;
88*3f982cf4SFabien Sanglard   }
89*3f982cf4SFabien Sanglard 
90*3f982cf4SFabien Sanglard   WeakPtr& operator=(WeakPtr&& other) noexcept {
91*3f982cf4SFabien Sanglard     impl_ = std::move(other.impl_);
92*3f982cf4SFabien Sanglard     return *this;
93*3f982cf4SFabien Sanglard   }
94*3f982cf4SFabien Sanglard 
95*3f982cf4SFabien Sanglard   // Create/Assign from nullptr.
WeakPtr(std::nullptr_t)96*3f982cf4SFabien Sanglard   WeakPtr(std::nullptr_t) {}  // NOLINT
97*3f982cf4SFabien Sanglard 
98*3f982cf4SFabien Sanglard   WeakPtr& operator=(std::nullptr_t) {
99*3f982cf4SFabien Sanglard     impl_.reset();
100*3f982cf4SFabien Sanglard     return *this;
101*3f982cf4SFabien Sanglard   }
102*3f982cf4SFabien Sanglard 
103*3f982cf4SFabien Sanglard   // Copy/Move constructors and assignment operators with upcast conversion.
104*3f982cf4SFabien Sanglard   template <typename U>
WeakPtr(const WeakPtr<U> & other)105*3f982cf4SFabien Sanglard   WeakPtr(const WeakPtr<U>& other) : impl_(other.as_std_weak_ptr()) {}
106*3f982cf4SFabien Sanglard 
107*3f982cf4SFabien Sanglard   template <typename U>
WeakPtr(WeakPtr<U> && other)108*3f982cf4SFabien Sanglard   WeakPtr(WeakPtr<U>&& other) noexcept
109*3f982cf4SFabien Sanglard       : impl_(std::move(other).as_std_weak_ptr()) {}
110*3f982cf4SFabien Sanglard 
111*3f982cf4SFabien Sanglard   template <typename U>
112*3f982cf4SFabien Sanglard   WeakPtr& operator=(const WeakPtr<U>& other) {
113*3f982cf4SFabien Sanglard     impl_ = other.as_std_weak_ptr();
114*3f982cf4SFabien Sanglard     return *this;
115*3f982cf4SFabien Sanglard   }
116*3f982cf4SFabien Sanglard 
117*3f982cf4SFabien Sanglard   template <typename U>
118*3f982cf4SFabien Sanglard   WeakPtr& operator=(WeakPtr<U>&& other) noexcept {
119*3f982cf4SFabien Sanglard     impl_ = std::move(other).as_std_weak_ptr();
120*3f982cf4SFabien Sanglard     return *this;
121*3f982cf4SFabien Sanglard   }
122*3f982cf4SFabien Sanglard 
123*3f982cf4SFabien Sanglard   // Accessors.
get()124*3f982cf4SFabien Sanglard   T* get() const { return impl_.lock().get(); }
125*3f982cf4SFabien Sanglard 
126*3f982cf4SFabien Sanglard   T& operator*() const {
127*3f982cf4SFabien Sanglard     T* const pointer = get();
128*3f982cf4SFabien Sanglard     OSP_DCHECK(pointer);
129*3f982cf4SFabien Sanglard     return *pointer;
130*3f982cf4SFabien Sanglard   }
131*3f982cf4SFabien Sanglard 
132*3f982cf4SFabien Sanglard   T* operator->() const {
133*3f982cf4SFabien Sanglard     T* const pointer = get();
134*3f982cf4SFabien Sanglard     OSP_DCHECK(pointer);
135*3f982cf4SFabien Sanglard     return pointer;
136*3f982cf4SFabien Sanglard   }
137*3f982cf4SFabien Sanglard 
138*3f982cf4SFabien Sanglard   // Allow conditionals to test validity, e.g. if (weak_ptr) {...}
139*3f982cf4SFabien Sanglard   explicit operator bool() const { return get() != nullptr; }
140*3f982cf4SFabien Sanglard 
141*3f982cf4SFabien Sanglard   // Conversion to std::weak_ptr<T>. It is unsafe to convert in the other
142*3f982cf4SFabien Sanglard   // direction. See comments for private constructors, below.
as_std_weak_ptr()143*3f982cf4SFabien Sanglard   const std::weak_ptr<T>& as_std_weak_ptr() const& { return impl_; }
as_std_weak_ptr()144*3f982cf4SFabien Sanglard   std::weak_ptr<T> as_std_weak_ptr() && { return std::move(impl_); }
145*3f982cf4SFabien Sanglard 
146*3f982cf4SFabien Sanglard  private:
147*3f982cf4SFabien Sanglard   friend class WeakPtrFactory<T>;
148*3f982cf4SFabien Sanglard 
149*3f982cf4SFabien Sanglard   // Called by WeakPtrFactory<T> and the WeakPtr<T> upcast conversion
150*3f982cf4SFabien Sanglard   // constructors and assigners. These are purposely not being exposed publicly
151*3f982cf4SFabien Sanglard   // because that would allow a WeakPtr<T> to be valid/invalid by a different
152*3f982cf4SFabien Sanglard   // ownership/threading model than the intended one (see top-level comments).
153*3f982cf4SFabien Sanglard   template <typename U>
WeakPtr(const std::weak_ptr<U> & other)154*3f982cf4SFabien Sanglard   explicit WeakPtr(const std::weak_ptr<U>& other) : impl_(other) {}
155*3f982cf4SFabien Sanglard 
156*3f982cf4SFabien Sanglard   template <typename U>
WeakPtr(std::weak_ptr<U> && other)157*3f982cf4SFabien Sanglard   explicit WeakPtr(std::weak_ptr<U>&& other) noexcept
158*3f982cf4SFabien Sanglard       : impl_(std::move(other)) {}
159*3f982cf4SFabien Sanglard 
160*3f982cf4SFabien Sanglard   std::weak_ptr<T> impl_;
161*3f982cf4SFabien Sanglard };
162*3f982cf4SFabien Sanglard 
163*3f982cf4SFabien Sanglard // Allow callers to compare WeakPtrs against nullptr to test validity.
164*3f982cf4SFabien Sanglard template <typename T>
165*3f982cf4SFabien Sanglard bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
166*3f982cf4SFabien Sanglard   return weak_ptr.get() != nullptr;
167*3f982cf4SFabien Sanglard }
168*3f982cf4SFabien Sanglard template <typename T>
169*3f982cf4SFabien Sanglard bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
170*3f982cf4SFabien Sanglard   return weak_ptr.get() != nullptr;
171*3f982cf4SFabien Sanglard }
172*3f982cf4SFabien Sanglard template <typename T>
173*3f982cf4SFabien Sanglard bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
174*3f982cf4SFabien Sanglard   return weak_ptr.get() == nullptr;
175*3f982cf4SFabien Sanglard }
176*3f982cf4SFabien Sanglard template <typename T>
177*3f982cf4SFabien Sanglard bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
178*3f982cf4SFabien Sanglard   return weak_ptr == nullptr;
179*3f982cf4SFabien Sanglard }
180*3f982cf4SFabien Sanglard 
181*3f982cf4SFabien Sanglard template <typename T>
182*3f982cf4SFabien Sanglard class WeakPtrFactory {
183*3f982cf4SFabien Sanglard  public:
WeakPtrFactory(T * instance)184*3f982cf4SFabien Sanglard   explicit WeakPtrFactory(T* instance) { Reset(instance); }
185*3f982cf4SFabien Sanglard   WeakPtrFactory(WeakPtrFactory&& other) noexcept = default;
186*3f982cf4SFabien Sanglard   WeakPtrFactory& operator=(WeakPtrFactory&& other) noexcept = default;
187*3f982cf4SFabien Sanglard 
188*3f982cf4SFabien Sanglard   // Thread-safe: WeakPtrs may be created on any thread/seuence. They may also
189*3f982cf4SFabien Sanglard   // be copied and moved on any thread/sequence. However, they MUST only be
190*3f982cf4SFabien Sanglard   // dereferenced on the same thread/sequence that calls the destructor or
191*3f982cf4SFabien Sanglard   // InvalidateWeakPtrs().
GetWeakPtr()192*3f982cf4SFabien Sanglard   WeakPtr<T> GetWeakPtr() const {
193*3f982cf4SFabien Sanglard     return WeakPtr<T>(std::weak_ptr<T>(bookkeeper_));
194*3f982cf4SFabien Sanglard   }
195*3f982cf4SFabien Sanglard 
196*3f982cf4SFabien Sanglard   // Destruction and Invalidation: These must be called on the same
197*3f982cf4SFabien Sanglard   // thread/sequence that dereferences any WeakPtrs to avoid use-after-free
198*3f982cf4SFabien Sanglard   // bugs.
199*3f982cf4SFabien Sanglard   ~WeakPtrFactory() = default;
InvalidateWeakPtrs()200*3f982cf4SFabien Sanglard   void InvalidateWeakPtrs() { Reset(bookkeeper_.get()); }
201*3f982cf4SFabien Sanglard 
202*3f982cf4SFabien Sanglard  private:
203*3f982cf4SFabien Sanglard   WeakPtrFactory(const WeakPtrFactory& other) = delete;
204*3f982cf4SFabien Sanglard   WeakPtrFactory& operator=(const WeakPtrFactory& other) = delete;
205*3f982cf4SFabien Sanglard 
Reset(T * instance)206*3f982cf4SFabien Sanglard   void Reset(T* instance) {
207*3f982cf4SFabien Sanglard     // T is owned externally to WeakPtrFactory. Thus, provide a no-op Deleter.
208*3f982cf4SFabien Sanglard     bookkeeper_ = {instance, [](T* instance) {}};
209*3f982cf4SFabien Sanglard   }
210*3f982cf4SFabien Sanglard 
211*3f982cf4SFabien Sanglard   // Manages the std::weak_ptr's referring to T. Does not own T.
212*3f982cf4SFabien Sanglard   std::shared_ptr<T> bookkeeper_;
213*3f982cf4SFabien Sanglard };
214*3f982cf4SFabien Sanglard 
215*3f982cf4SFabien Sanglard }  // namespace openscreen
216*3f982cf4SFabien Sanglard 
217*3f982cf4SFabien Sanglard #endif  // UTIL_WEAK_PTR_H_
218