chromium/third_party/openscreen/src/util/weak_ptr.h

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UTIL_WEAK_PTR_H_
#define UTIL_WEAK_PTR_H_

#include <memory>
#include <utility>

#include "util/osp_logging.h"

namespace openscreen {

// Weak pointers are pointers to an object that do not affect its lifetime,
// and which may be invalidated (i.e. reset to nullptr) by the object, or its
// owner, at any time; most commonly when the object is about to be deleted.
//
// Weak pointers are useful when an object needs to be accessed safely by one
// or more objects other than its owner, and those callers can cope with the
// object vanishing and e.g. tasks posted to it being silently dropped.
// Reference-counting such an object would complicate the ownership graph and
// make it harder to reason about the object's lifetime.
//
// EXAMPLE:
//
//  class Controller {
//   public:
//    void SpawnWorker() { new Worker(weak_factory_.GetWeakPtr()); }
//    void WorkComplete(const Result& result) { ... }
//   private:
//    // Member variables should appear before the WeakPtrFactory, to ensure
//    // that any WeakPtrs to Controller are invalidated before its members
//    // variable's destructors are executed, rendering them invalid.
//    WeakPtrFactory<Controller> weak_factory_{this};
//  };
//
//  class Worker {
//   public:
//    explicit Worker(WeakPtr<Controller> controller)
//        : controller_(std::move(controller)) {}
//   private:
//    void DidCompleteAsynchronousProcessing(const Result& result) {
//      if (controller_)
//        controller_->WorkComplete(result);
//      delete this;
//    }
//    const WeakPtr<Controller> controller_;
//  };
//
// With this implementation a caller may use SpawnWorker() to dispatch multiple
// Workers and subsequently delete the Controller, without waiting for all
// Workers to have completed.
//
// ------------------------- IMPORTANT: Thread-safety -------------------------
//
// Generally, Open Screen code is meant to be single-threaded. For the few
// exceptional cases, the following is relevant:
//
// WeakPtrs may be created from WeakPtrFactory, and also duplicated/moved on any
// thread/sequence. However, they may only be dereferenced on the same
// thread/sequence that will ultimately execute the WeakPtrFactory destructor or
// call InvalidateWeakPtrs(). Otherwise, use-during-free or use-after-free is
// possible.
//
// openscreen::WeakPtr and WeakPtrFactory are similar, but not identical, to
// Chromium's base::WeakPtrFactory. Open Screen WeakPtrs may be safely created
// from WeakPtrFactory on any thread/sequence, since they are backed by the
// thread-safe bookkeeping of std::shared_ptr<>.

template <typename T>
class WeakPtrFactory;

template <typename T>
class WeakPtr {};

// Allow callers to compare WeakPtrs against nullptr to test validity.
template <typename T>
bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {}
template <typename T>
bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {}
template <typename T>
bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {}
template <typename T>
bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {}

template <typename T>
class WeakPtrFactory {};

}  // namespace openscreen

#endif  // UTIL_WEAK_PTR_H_