michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et ft=cpp : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_StaticPtr_h michael@0: #define mozilla_StaticPtr_h michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * StaticAutoPtr and StaticRefPtr are like nsAutoPtr and nsRefPtr, except they michael@0: * are suitable for use as global variables. michael@0: * michael@0: * In particular, a global instance of Static{Auto,Ref}Ptr doesn't cause the michael@0: * compiler to emit a static initializer (in release builds, anyway). michael@0: * michael@0: * In order to accomplish this, Static{Auto,Ref}Ptr must have a trivial michael@0: * constructor and destructor. As a consequence, it cannot initialize its raw michael@0: * pointer to 0 on construction, and it cannot delete/release its raw pointer michael@0: * upon destruction. michael@0: * michael@0: * Since the compiler guarantees that all global variables are initialized to michael@0: * 0, these trivial constructors are safe, so long as you use michael@0: * Static{Auto,Ref}Ptr as a global variable. If you use Static{Auto,Ref}Ptr as michael@0: * a stack variable or as a class instance variable, you will get what you michael@0: * deserve. michael@0: * michael@0: * Static{Auto,Ref}Ptr have a limited interface as compared to ns{Auto,Ref}Ptr; michael@0: * this is intentional, since their range of acceptable uses is smaller. michael@0: */ michael@0: michael@0: template michael@0: class StaticAutoPtr michael@0: { michael@0: public: michael@0: // In debug builds, check that mRawPtr is initialized for us as we expect michael@0: // by the compiler. In non-debug builds, don't declare a constructor michael@0: // so that the compiler can see that the constructor is trivial. michael@0: #ifdef DEBUG michael@0: StaticAutoPtr() michael@0: { michael@0: MOZ_ASSERT(!mRawPtr); michael@0: } michael@0: #endif michael@0: michael@0: StaticAutoPtr& operator=(T* rhs) michael@0: { michael@0: Assign(rhs); michael@0: return *this; michael@0: } michael@0: michael@0: T* get() const michael@0: { michael@0: return mRawPtr; michael@0: } michael@0: michael@0: operator T*() const michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: T* operator->() const michael@0: { michael@0: MOZ_ASSERT(mRawPtr); michael@0: return get(); michael@0: } michael@0: michael@0: T& operator*() const michael@0: { michael@0: return *get(); michael@0: } michael@0: michael@0: private: michael@0: // Disallow copy constructor, but only in debug mode. We only define michael@0: // a default constructor in debug mode (see above); if we declared michael@0: // this constructor always, the compiler wouldn't generate a trivial michael@0: // default constructor for us in non-debug mode. michael@0: #ifdef DEBUG michael@0: StaticAutoPtr(StaticAutoPtr &other); michael@0: #endif michael@0: michael@0: void Assign(T* newPtr) michael@0: { michael@0: MOZ_ASSERT(!newPtr || mRawPtr != newPtr); michael@0: T* oldPtr = mRawPtr; michael@0: mRawPtr = newPtr; michael@0: delete oldPtr; michael@0: } michael@0: michael@0: T* mRawPtr; michael@0: }; michael@0: michael@0: template michael@0: class StaticRefPtr michael@0: { michael@0: public: michael@0: // In debug builds, check that mRawPtr is initialized for us as we expect michael@0: // by the compiler. In non-debug builds, don't declare a constructor michael@0: // so that the compiler can see that the constructor is trivial. michael@0: #ifdef DEBUG michael@0: StaticRefPtr() michael@0: { michael@0: MOZ_ASSERT(!mRawPtr); michael@0: } michael@0: #endif michael@0: michael@0: StaticRefPtr& operator=(T* rhs) michael@0: { michael@0: AssignWithAddref(rhs); michael@0: return *this; michael@0: } michael@0: michael@0: StaticRefPtr& operator=(const StaticRefPtr& rhs) michael@0: { michael@0: return (this = rhs.mRawPtr); michael@0: } michael@0: michael@0: T* get() const michael@0: { michael@0: return mRawPtr; michael@0: } michael@0: michael@0: operator T*() const michael@0: { michael@0: return get(); michael@0: } michael@0: michael@0: T* operator->() const michael@0: { michael@0: MOZ_ASSERT(mRawPtr); michael@0: return get(); michael@0: } michael@0: michael@0: T& operator*() const michael@0: { michael@0: return *get(); michael@0: } michael@0: michael@0: private: michael@0: void AssignWithAddref(T* newPtr) michael@0: { michael@0: if (newPtr) { michael@0: newPtr->AddRef(); michael@0: } michael@0: AssignAssumingAddRef(newPtr); michael@0: } michael@0: michael@0: void AssignAssumingAddRef(T* newPtr) michael@0: { michael@0: T* oldPtr = mRawPtr; michael@0: mRawPtr = newPtr; michael@0: if (oldPtr) { michael@0: oldPtr->Release(); michael@0: } michael@0: } michael@0: michael@0: T* mRawPtr; michael@0: }; michael@0: michael@0: namespace StaticPtr_internal { michael@0: class Zero; michael@0: } // namespace StaticPtr_internal michael@0: michael@0: #define REFLEXIVE_EQUALITY_OPERATORS(type1, type2, eq_fn, ...) \ michael@0: template<__VA_ARGS__> \ michael@0: inline bool \ michael@0: operator==(type1 lhs, type2 rhs) \ michael@0: { \ michael@0: return eq_fn; \ michael@0: } \ michael@0: \ michael@0: template<__VA_ARGS__> \ michael@0: inline bool \ michael@0: operator==(type2 lhs, type1 rhs) \ michael@0: { \ michael@0: return rhs == lhs; \ michael@0: } \ michael@0: \ michael@0: template<__VA_ARGS__> \ michael@0: inline bool \ michael@0: operator!=(type1 lhs, type2 rhs) \ michael@0: { \ michael@0: return !(lhs == rhs); \ michael@0: } \ michael@0: \ michael@0: template<__VA_ARGS__> \ michael@0: inline bool \ michael@0: operator!=(type2 lhs, type1 rhs) \ michael@0: { \ michael@0: return !(lhs == rhs); \ michael@0: } michael@0: michael@0: // StaticAutoPtr (in)equality operators michael@0: michael@0: template michael@0: inline bool michael@0: operator==(const StaticAutoPtr& lhs, const StaticAutoPtr& rhs) michael@0: { michael@0: return lhs.get() == rhs.get(); michael@0: } michael@0: michael@0: template michael@0: inline bool michael@0: operator!=(const StaticAutoPtr& lhs, const StaticAutoPtr& rhs) michael@0: { michael@0: return !(lhs == rhs); michael@0: } michael@0: michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, const U*, michael@0: lhs.get() == rhs, class T, class U) michael@0: michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, U*, michael@0: lhs.get() == rhs, class T, class U) michael@0: michael@0: // Let us compare StaticAutoPtr to 0. michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticAutoPtr&, StaticPtr_internal::Zero*, michael@0: lhs.get() == nullptr, class T) michael@0: michael@0: // StaticRefPtr (in)equality operators michael@0: michael@0: template michael@0: inline bool michael@0: operator==(const StaticRefPtr& lhs, const StaticRefPtr& rhs) michael@0: { michael@0: return lhs.get() == rhs.get(); michael@0: } michael@0: michael@0: template michael@0: inline bool michael@0: operator!=(const StaticRefPtr& lhs, const StaticRefPtr& rhs) michael@0: { michael@0: return !(lhs == rhs); michael@0: } michael@0: michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, const U*, michael@0: lhs.get() == rhs, class T, class U) michael@0: michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, U*, michael@0: lhs.get() == rhs, class T, class U) michael@0: michael@0: // Let us compare StaticRefPtr to 0. michael@0: REFLEXIVE_EQUALITY_OPERATORS(const StaticRefPtr&, StaticPtr_internal::Zero*, michael@0: lhs.get() == nullptr, class T) michael@0: michael@0: #undef REFLEXIVE_EQUALITY_OPERATORS michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif