зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1570395: Add StaticLocalAutoPtr and StaticLocalRefPtr to XPCOM; r=froydnj
This patch adds smart pointers to be used for initializing objects as C++11 "magic statics" -- 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. Unlike Static{Auto,Ref}Ptr, they have non-trivial constructors, though they must still have trivial destructors to prevent emission of atexit calls. The new classes use the new `MOZ_STATIC_LOCAL_CLASS` annotation which ensures their instantiations are static locals and prevents non-trivial destructors. Differential Revision: https://phabricator.services.mozilla.com/D40092 --HG-- rename : xpcom/base/StaticPtr.h => xpcom/base/StaticLocalPtr.h extra : moz-landing-system : lando
This commit is contained in:
Родитель
6773494087
Коммит
a2b73b8abc
|
@ -24,6 +24,8 @@ namespace mozilla {
|
|||
template <class T>
|
||||
class OwningNonNull;
|
||||
template <class T>
|
||||
class StaticLocalRefPtr;
|
||||
template <class T>
|
||||
class StaticRefPtr;
|
||||
#if defined(XP_WIN)
|
||||
namespace mscom {
|
||||
|
@ -146,6 +148,10 @@ class MOZ_IS_REFPTR RefPtr {
|
|||
template <class U>
|
||||
MOZ_IMPLICIT RefPtr(const mozilla::OwningNonNull<U>& aOther);
|
||||
|
||||
// Defined in StaticLocalPtr.h
|
||||
template <class U>
|
||||
MOZ_IMPLICIT RefPtr(const mozilla::StaticLocalRefPtr<U>& aOther);
|
||||
|
||||
// Defined in StaticPtr.h
|
||||
template <class U>
|
||||
MOZ_IMPLICIT RefPtr(const mozilla::StaticRefPtr<U>& aOther);
|
||||
|
@ -210,6 +216,10 @@ class MOZ_IS_REFPTR RefPtr {
|
|||
template <class U>
|
||||
RefPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
|
||||
|
||||
// Defined in StaticLocalPtr.h
|
||||
template <class U>
|
||||
RefPtr<T>& operator=(const mozilla::StaticLocalRefPtr<U>& aOther);
|
||||
|
||||
// Defined in StaticPtr.h
|
||||
template <class U>
|
||||
RefPtr<T>& operator=(const mozilla::StaticRefPtr<U>& aOther);
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/* -*- 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 nsAutoPtr and nsRefPtr,
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
|
@ -126,6 +126,7 @@ EXPORTS.mozilla += [
|
|||
'NSPRLogModulesParser.h',
|
||||
'OwningNonNull.h',
|
||||
'SizeOfState.h',
|
||||
'StaticLocalPtr.h',
|
||||
'StaticMonitor.h',
|
||||
'StaticMutex.h',
|
||||
'StaticPtr.h',
|
||||
|
|
Загрузка…
Ссылка в новой задаче