diff -r 000000000000 -r 6474c204b198 xpcom/base/StaticPtr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xpcom/base/StaticPtr.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* 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