/* -*- 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 http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_StaticPtr_h #define mozilla_StaticPtr_h #include "mozilla/Assertions.h" #include "mozilla/NullPtr.h" namespace mozilla { /** * StaticAutoPtr and StaticRefPtr are like nsAutoPtr and nsRefPtr, except they * are suitable for use as global variables. * * In particular, a global instance of Static{Auto,Ref}Ptr doesn't cause the * compiler to emit a static initializer (in release builds, anyway). * * In order to accomplish this, Static{Auto,Ref}Ptr must have a trivial * constructor and destructor. As a consequence, it cannot initialize its raw * pointer to 0 on construction, and it cannot delete/release its raw pointer * upon destruction. * * Since the compiler guarantees that all global variables are initialized to * 0, these trivial constructors are safe, so long as you use * Static{Auto,Ref}Ptr as a global variable. If you use Static{Auto,Ref}Ptr as * a stack variable or as a class instance variable, you will get what you * deserve. * * Static{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 class StaticAutoPtr { public: // In debug builds, check that mRawPtr is initialized for us as we expect // by the compiler. In non-debug builds, don't declare a constructor // so that the compiler can see that the constructor is trivial. #ifdef DEBUG StaticAutoPtr() { MOZ_ASSERT(!mRawPtr); } #endif StaticAutoPtr& operator=(T* rhs) { Assign(rhs); 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(); } private: // Disallow copy constructor, but only in debug mode. We only define // a default constructor in debug mode (see above); if we declared // this constructor always, the compiler wouldn't generate a trivial // default constructor for us in non-debug mode. #ifdef DEBUG StaticAutoPtr(StaticAutoPtr &other); #endif void Assign(T* newPtr) { MOZ_ASSERT(!newPtr || mRawPtr != newPtr); T* oldPtr = mRawPtr; mRawPtr = newPtr; delete oldPtr; } T* mRawPtr; }; template class StaticRefPtr { public: // In debug builds, check that mRawPtr is initialized for us as we expect // by the compiler. In non-debug builds, don't declare a constructor // so that the compiler can see that the constructor is trivial. #ifdef DEBUG StaticRefPtr() { MOZ_ASSERT(!mRawPtr); } #endif StaticRefPtr& operator=(T* rhs) { AssignWithAddref(rhs); return *this; } StaticRefPtr& operator=(const StaticRefPtr& rhs) { return (this = rhs.mRawPtr); } T* get() const { return mRawPtr; } operator T*() const { return get(); } T* operator->() const { MOZ_ASSERT(mRawPtr); return get(); } T& operator*() const { return *get(); } private: void AssignWithAddref(T* newPtr) { if (newPtr) { newPtr->AddRef(); } AssignAssumingAddRef(newPtr); } void AssignAssumingAddRef(T* newPtr) { T* oldPtr = mRawPtr; mRawPtr = newPtr; if (oldPtr) { oldPtr->Release(); } } T* mRawPtr; }; namespace StaticPtr_internal { class Zero; } // namespace StaticPtr_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); \ } // StaticAutoPtr (in)equality operators template inline bool operator==(const StaticAutoPtr& lhs, const StaticAutoPtr& rhs) { return lhs.get() == rhs.get(); } template inline bool operator!=(const StaticAutoPtr& lhs, const StaticAutoPtr& rhs) { return !(lhs == rhs); } REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, const U*, lhs.get() == rhs, class T, class U) REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, U*, lhs.get() == rhs, class T, class U) // Let us compare StaticAutoPtr to 0. REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, StaticPtr_internal::Zero*, lhs.get() == nullptr, class T) // StaticRefPtr (in)equality operators template inline bool operator==(const StaticRefPtr& lhs, const StaticRefPtr& rhs) { return lhs.get() == rhs.get(); } template inline bool operator!=(const StaticRefPtr& lhs, const StaticRefPtr& rhs) { return !(lhs == rhs); } REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, const U*, lhs.get() == rhs, class T, class U) REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, U*, lhs.get() == rhs, class T, class U) // Let us compare StaticRefPtr to 0. REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, StaticPtr_internal::Zero*, lhs.get() == nullptr, class T) #undef REFLEXIVE_EQUALITY_OPERATORS } // namespace mozilla #endif