diff options
Diffstat (limited to 'xpcom/base/StaticLocalPtr.h')
-rw-r--r-- | xpcom/base/StaticLocalPtr.h | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/xpcom/base/StaticLocalPtr.h b/xpcom/base/StaticLocalPtr.h new file mode 100644 index 0000000000..2e2fc035bd --- /dev/null +++ b/xpcom/base/StaticLocalPtr.h @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_StaticLocalPtr_h +#define mozilla_StaticLocalPtr_h + +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { + +/** + * StaticLocalAutoPtr and StaticLocalRefPtr are like UniquePtr and RefPtr, + * except they are suitable for use as "magic static" local variables -- that + * is, they are able to take advantage of C++11's guarantee of thread safety + * during initialization by atomically constructing both the smart pointer + * itself as well as the object being pointed to. + * + * A static local instance of StaticLocal{Auto,Ref}Ptr does not cause the + * compiler to emit any atexit calls. In order to accomplish this, + * StaticLocal{Auto,Ref}Ptr must have a trivial destructor. As a consequence, + * it does not delete/release its raw pointer upon destruction. + * + * The clang plugin, run as part of our "static analysis" builds, makes it a + * compile-time error to use StaticLocal{Auto,Ref}Ptr as anything except a + * static local variable. + * + * StaticLocal{Auto,Ref}Ptr have a limited interface as compared to + * ns{Auto,Ref}Ptr; this is intentional, since their range of acceptable uses is + * smaller. + */ + +template <typename T> +class MOZ_STATIC_LOCAL_CLASS StaticLocalAutoPtr final { + public: + explicit StaticLocalAutoPtr(T* aRawPtr) : mRawPtr(aRawPtr) {} + + StaticLocalAutoPtr(StaticLocalAutoPtr<T>&& aOther) : mRawPtr(aOther.mRawPtr) { + aOther.mRawPtr = nullptr; + } + + StaticLocalAutoPtr<T>& operator=(T* aRhs) { + Assign(aRhs); + return *this; + } + + T* get() const { return mRawPtr; } + + operator T*() const { return get(); } + + T* operator->() const { + MOZ_ASSERT(mRawPtr); + return get(); + } + + T& operator*() const { return *get(); } + + T* forget() { + T* temp = mRawPtr; + mRawPtr = nullptr; + return temp; + } + + private: + StaticLocalAutoPtr(const StaticLocalAutoPtr<T>& aOther) = delete; + + // We do not allow assignment as the intention of this class is to only + // assign to mRawPtr during construction. + StaticLocalAutoPtr& operator=(const StaticLocalAutoPtr<T>& aOther) = delete; + StaticLocalAutoPtr& operator=(StaticLocalAutoPtr<T>&&) = delete; + + void Assign(T* aNewPtr) { + MOZ_ASSERT(!aNewPtr || mRawPtr != aNewPtr); + T* oldPtr = mRawPtr; + mRawPtr = aNewPtr; + delete oldPtr; + } + + T* mRawPtr; +}; + +template <typename T> +class MOZ_STATIC_LOCAL_CLASS StaticLocalRefPtr final { + public: + explicit StaticLocalRefPtr(T* aRawPtr) : mRawPtr(nullptr) { + AssignWithAddref(aRawPtr); + } + + explicit StaticLocalRefPtr(already_AddRefed<T>& aPtr) : mRawPtr(nullptr) { + AssignAssumingAddRef(aPtr.take()); + } + + explicit StaticLocalRefPtr(already_AddRefed<T>&& aPtr) : mRawPtr(nullptr) { + AssignAssumingAddRef(aPtr.take()); + } + + StaticLocalRefPtr(const StaticLocalRefPtr<T>& aPtr) + : StaticLocalRefPtr(aPtr.mRawPtr) {} + + StaticLocalRefPtr(StaticLocalRefPtr<T>&& aPtr) : mRawPtr(aPtr.mRawPtr) { + aPtr.mRawPtr = nullptr; + } + + StaticLocalRefPtr<T>& operator=(T* aRhs) { + AssignWithAddref(aRhs); + return *this; + } + + already_AddRefed<T> forget() { + T* temp = mRawPtr; + mRawPtr = nullptr; + return already_AddRefed<T>(temp); + } + + T* get() const { return mRawPtr; } + + operator T*() const { return get(); } + + T* operator->() const { + MOZ_ASSERT(mRawPtr); + return get(); + } + + T& operator*() const { return *get(); } + + private: + // We do not allow assignment as the intention of this class is to only + // assign to mRawPtr during construction. + StaticLocalRefPtr<T>& operator=(const StaticLocalRefPtr<T>& aRhs) = delete; + StaticLocalRefPtr<T>& operator=(StaticLocalRefPtr<T>&& aRhs) = delete; + + void AssignWithAddref(T* aNewPtr) { + if (aNewPtr) { + aNewPtr->AddRef(); + } + AssignAssumingAddRef(aNewPtr); + } + + void AssignAssumingAddRef(T* aNewPtr) { + T* oldPtr = mRawPtr; + mRawPtr = aNewPtr; + if (oldPtr) { + oldPtr->Release(); + } + } + + T* MOZ_OWNING_REF mRawPtr; +}; + +namespace StaticLocalPtr_internal { +class Zero; +} // namespace StaticLocalPtr_internal + +#define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \ + template <__VA_ARGS__> \ + inline bool operator==(type1 lhs, type2 rhs) { \ + return eq_fn; \ + } \ + \ + template <__VA_ARGS__> \ + inline bool operator==(type2 lhs, type1 rhs) { \ + return rhs == lhs; \ + } \ + \ + template <__VA_ARGS__> \ + inline bool operator!=(type1 lhs, type2 rhs) { \ + return !(lhs == rhs); \ + } \ + \ + template <__VA_ARGS__> \ + inline bool operator!=(type2 lhs, type1 rhs) { \ + return !(lhs == rhs); \ + } + +// StaticLocalAutoPtr (in)equality operators + +template <class T, class U> +inline bool operator==(const StaticLocalAutoPtr<T>& aLhs, + const StaticLocalAutoPtr<U>& aRhs) { + return aLhs.get() == aRhs.get(); +} + +template <class T, class U> +inline bool operator!=(const StaticLocalAutoPtr<T>& aLhs, + const StaticLocalAutoPtr<U>& aRhs) { + return !(aLhs == aRhs); +} + +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr<T>&, const U*, + lhs.get() == rhs, class T, class U) + +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr<T>&, U*, lhs.get() == rhs, + class T, class U) + +// Let us compare StaticLocalAutoPtr to 0. +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalAutoPtr<T>&, + StaticLocalPtr_internal::Zero*, + lhs.get() == nullptr, class T) + +// StaticLocalRefPtr (in)equality operators + +template <class T, class U> +inline bool operator==(const StaticLocalRefPtr<T>& aLhs, + const StaticLocalRefPtr<U>& aRhs) { + return aLhs.get() == aRhs.get(); +} + +template <class T, class U> +inline bool operator!=(const StaticLocalRefPtr<T>& aLhs, + const StaticLocalRefPtr<U>& aRhs) { + return !(aLhs == aRhs); +} + +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr<T>&, const U*, + lhs.get() == rhs, class T, class U) + +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr<T>&, U*, lhs.get() == rhs, + class T, class U) + +// Let us compare StaticLocalRefPtr to 0. +REFLEXIVE_EQUALITY_OPERATORS(const StaticLocalRefPtr<T>&, + StaticLocalPtr_internal::Zero*, + lhs.get() == nullptr, class T) + +#undef REFLEXIVE_EQUALITY_OPERATORS + +} // namespace mozilla + +// Declared in mozilla/RefPtr.h +template <class T> +template <class U> +RefPtr<T>::RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther) + : RefPtr(aOther.get()) {} + +template <class T> +template <class U> +RefPtr<T>& RefPtr<T>::operator=(const mozilla::StaticLocalRefPtr<U>& aOther) { + return operator=(aOther.get()); +} + +template <class T> +inline already_AddRefed<T> do_AddRef( + const mozilla::StaticLocalRefPtr<T>& aObj) { + RefPtr<T> ref(aObj); + return ref.forget(); +} + +#endif // mozilla_StaticLocalPtr_h |