// Copyright (c) 2017 Marshall A. Greenblatt. Portions copyright (c) 2011 // Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the name Chromium Embedded // Framework nor the names of its contributors may be used to endorse // or promote products derived from this software without specific prior // written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_ #define CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_ #pragma once #if defined(USING_CHROMIUM_INCLUDES) // When building CEF include the Chromium header directly. #include "base/memory/scoped_refptr.h" #else // !USING_CHROMIUM_INCLUDES // The following is substantially similar to the Chromium implementation. // If the Chromium implementation diverges the below implementation should be // updated to match. #include #include #include #include #include "include/base/cef_logging.h" template class scoped_refptr; namespace base { template class RefCounted; template class RefCountedThreadSafe; class SequencedTaskRunner; class WrappedPromise; template scoped_refptr AdoptRef(T* t); namespace internal { class BasePromise; } // namespace internal namespace cef_subtle { enum AdoptRefTag { kAdoptRefTag }; enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; template constexpr bool IsRefCountPreferenceOverridden(const T*, const RefCounted*) { return !std::is_same, std::decay_t>::value; } template constexpr bool IsRefCountPreferenceOverridden( const T*, const RefCountedThreadSafe*) { return !std::is_same, std::decay_t>::value; } constexpr bool IsRefCountPreferenceOverridden(...) { return false; } } // namespace cef_subtle // Creates a scoped_refptr from a raw pointer without incrementing the reference // count. Use this only for a newly created object whose reference count starts // from 1 instead of 0. template scoped_refptr AdoptRef(T* obj) { using Tag = std::decay_t; static_assert(std::is_same::value, "Use AdoptRef only if the reference count starts from one."); DCHECK(obj); DCHECK(obj->HasOneRef()); obj->Adopted(); return scoped_refptr(obj, cef_subtle::kAdoptRefTag); } namespace cef_subtle { template scoped_refptr AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { return scoped_refptr(obj); } template scoped_refptr AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { return AdoptRef(obj); } } // namespace cef_subtle // Constructs an instance of T, which is a ref counted type, and wraps the // object into a scoped_refptr. template scoped_refptr MakeRefCounted(Args&&... args) { T* obj = new T(std::forward(args)...); return cef_subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); } // Takes an instance of T, which is a ref counted type, and wraps the object // into a scoped_refptr. template scoped_refptr WrapRefCounted(T* t) { return scoped_refptr(t); } } // namespace base /// /// A smart pointer class for reference counted objects. Use this class instead /// of calling AddRef and Release manually on a reference counted object to /// avoid common memory leaks caused by forgetting to Release an object /// reference. Sample usage: /// ///
///   class MyFoo : public RefCounted {
///    ...
///    private:
///     friend class RefCounted;  // Allow destruction by RefCounted<>.
///     ~MyFoo();                        // Destructor must be
///     private/protected.
///   };
///
///   void some_function() {
///     scoped_refptr foo = MakeRefCounted();
///     foo->Method(param);
///     // |foo| is released when this function returns
///   }
///
///   void some_other_function() {
///     scoped_refptr foo = MakeRefCounted();
///     ...
///     foo.reset();  // explicitly releases |foo|
///     ...
///     if (foo)
///       foo->Method(param);
///   }
/// 
/// /// The above examples show how scoped_refptr acts like a pointer to T. /// Given two scoped_refptr classes, it is also possible to exchange /// references between the two objects, like so: /// ///
///   {
///     scoped_refptr a = MakeRefCounted();
///     scoped_refptr b;
///
///     b.swap(a);
///     // now, |b| references the MyFoo object, and |a| references nullptr.
///   }
/// 
/// /// To make both |a| and |b| in the above example reference the same MyFoo /// object, simply use the assignment operator: /// ///
///   {
///     scoped_refptr a = MakeRefCounted();
///     scoped_refptr b;
///
///     b = a;
///     // now, |a| and |b| each own a reference to the same MyFoo object.
///   }
/// 
/// /// Also see Chromium's ownership and calling conventions: /// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions /// Specifically: /// If the function (at least sometimes) takes a ref on a refcounted object, /// declare the param as scoped_refptr. The caller can decide whether it /// wishes to transfer ownership (by calling std::move(t) when passing t) or /// retain its ref (by simply passing t directly). /// In other words, use scoped_refptr like you would a std::unique_ptr except /// in the odd case where it's required to hold on to a ref while handing one /// to another component (if a component merely needs to use t on the stack /// without keeping a ref: pass t as a raw T*). /// template class TRIVIAL_ABI scoped_refptr { public: typedef T element_type; constexpr scoped_refptr() = default; // Allow implicit construction from nullptr. constexpr scoped_refptr(std::nullptr_t) {} // Constructs from a raw pointer. Note that this constructor allows implicit // conversion from T* to scoped_refptr which is strongly discouraged. If // you are creating a new ref-counted object please use // base::MakeRefCounted() or base::WrapRefCounted(). Otherwise you // should move or copy construct from an existing scoped_refptr to the // ref-counted object. scoped_refptr(T* p) : ptr_(p) { if (ptr_) AddRef(ptr_); } // Copy constructor. This is required in addition to the copy conversion // constructor below. scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {} // Copy conversion constructor. template ::value>::type> scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {} // Move constructor. This is required in addition to the move conversion // constructor below. scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; } // Move conversion constructor. template ::value>::type> scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; } ~scoped_refptr() { static_assert(!base::cef_subtle::IsRefCountPreferenceOverridden( static_cast(nullptr), static_cast(nullptr)), "It's unsafe to override the ref count preference." " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE" " from subclasses."); if (ptr_) Release(ptr_); } T* get() const { return ptr_; } T& operator*() const { DCHECK(ptr_); return *ptr_; } T* operator->() const { DCHECK(ptr_); return ptr_; } scoped_refptr& operator=(std::nullptr_t) { reset(); return *this; } scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); } // Unified assignment operator. scoped_refptr& operator=(scoped_refptr r) noexcept { swap(r); return *this; } // Sets managed object to null and releases reference to the previous managed // object, if it existed. void reset() { scoped_refptr().swap(*this); } // Returns the owned pointer (if any), releasing ownership to the caller. The // caller is responsible for managing the lifetime of the reference. [[nodiscard]] T* release(); void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); } explicit operator bool() const { return ptr_ != nullptr; } template bool operator==(const scoped_refptr& rhs) const { return ptr_ == rhs.get(); } template bool operator!=(const scoped_refptr& rhs) const { return !operator==(rhs); } template bool operator<(const scoped_refptr& rhs) const { return ptr_ < rhs.get(); } protected: T* ptr_ = nullptr; private: template friend scoped_refptr base::AdoptRef(U*); friend class ::base::SequencedTaskRunner; // Friend access so these classes can use the constructor below as part of a // binary size optimization. friend class ::base::internal::BasePromise; friend class ::base::WrappedPromise; scoped_refptr(T* p, base::cef_subtle::AdoptRefTag) : ptr_(p) {} // Friend required for move constructors that set r.ptr_ to null. template friend class scoped_refptr; // Non-inline helpers to allow: // class Opaque; // extern template class scoped_refptr; // Otherwise the compiler will complain that Opaque is an incomplete type. static void AddRef(T* ptr); static void Release(T* ptr); }; template T* scoped_refptr::release() { T* ptr = ptr_; ptr_ = nullptr; return ptr; } // static template void scoped_refptr::AddRef(T* ptr) { ptr->AddRef(); } // static template void scoped_refptr::Release(T* ptr) { ptr->Release(); } template bool operator==(const scoped_refptr& lhs, const U* rhs) { return lhs.get() == rhs; } template bool operator==(const T* lhs, const scoped_refptr& rhs) { return lhs == rhs.get(); } template bool operator==(const scoped_refptr& lhs, std::nullptr_t null) { return !static_cast(lhs); } template bool operator==(std::nullptr_t null, const scoped_refptr& rhs) { return !static_cast(rhs); } template bool operator!=(const scoped_refptr& lhs, const U* rhs) { return !operator==(lhs, rhs); } template bool operator!=(const T* lhs, const scoped_refptr& rhs) { return !operator==(lhs, rhs); } template bool operator!=(const scoped_refptr& lhs, std::nullptr_t null) { return !operator==(lhs, null); } template bool operator!=(std::nullptr_t null, const scoped_refptr& rhs) { return !operator==(null, rhs); } template std::ostream& operator<<(std::ostream& out, const scoped_refptr& p) { return out << p.get(); } template void swap(scoped_refptr& lhs, scoped_refptr& rhs) noexcept { lhs.swap(rhs); } #endif // !USING_CHROMIUM_INCLUDES #endif // CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_