author | Nathan Froyd <froydnj@mozilla.com> |
Fri, 07 Nov 2014 11:17:41 -0500 | |
changeset 215513 | cf6287a1392711f24a7af4691ea8519dcbf81cf1 |
parent 215512 | d0dc5b25a765a02e3b71eef63305eaadf28a99b0 |
child 215514 | 97408585e41c165f6e5d0fdc0eeedda92cd237b4 |
push id | 27818 |
push user | ryanvm@gmail.com |
push date | Thu, 13 Nov 2014 20:19:09 +0000 |
treeherder | mozilla-central@292ed84594c1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bsmedberg |
bugs | 1095541 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/xpcom/base/AlreadyAddRefed.h @@ -0,0 +1,143 @@ +/* -*- 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/. */ + +/* Typed temporary pointers for reference-counted smart pointers. */ + +#ifndef AlreadyAddRefed_h +#define AlreadyAddRefed_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/NullPtr.h" + +namespace mozilla { + +struct unused_t; + +} // namespace mozilla + +/** + * already_AddRefed cooperaters with nsCOMPtr/nsRefPtr to enable you to assign + * in a pointer _without_ |AddRef|ing it. You might want to use this as a + * return type from a function that returns an already |AddRef|ed pointer. + */ +template<class T> +struct already_AddRefed +{ + /* + * We want to allow returning nullptr from functions returning + * already_AddRefed<T>, for simplicity. But we also don't want to allow + * returning raw T*, instead preferring creation of already_AddRefed<T> from + * an nsRefPtr, nsCOMPtr, or the like. + * + * We address the latter requirement by making the (T*) constructor explicit. + * But |return nullptr| won't consider an explicit constructor, so we need + * another constructor to handle it. Plain old (decltype(nullptr)) doesn't + * cut it, because if nullptr is emulated as __null (with type int or long), + * passing nullptr to an int/long parameter triggers compiler warnings. We + * need a type that no one can pass accidentally; a pointer-to-member-function + * (where no such function exists) does the trick nicely. + * + * That handles the return-value case. What about for locals, argument types, + * and so on? |already_AddRefed<T>(nullptr)| considers both overloads (and + * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity. + * We can target true nullptr using decltype(nullptr), but we can't target + * emulated nullptr the same way, because passing __null to an int/long + * parameter triggers compiler warnings. So just give up on this, and provide + * this behavior through the default constructor. + * + * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when + * nullptr no longer needs to be emulated to support the ancient b2g compiler. + * (The () overload could also be removed, if desired, if we changed callers.) + */ + already_AddRefed() : mRawPtr(nullptr) {} + + // The return and argument types here are arbitrarily selected so no + // corresponding member function exists. + typedef void (already_AddRefed::* MatchNullptr)(double, float); + MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {} + + explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {} + + // Disallowed. Use move semantics instead. + already_AddRefed(const already_AddRefed<T>& aOther) MOZ_DELETE; + + already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {} + + ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); } + + // Specialize the unused operator<< for already_AddRefed, to allow + // nsCOMPtr<nsIFoo> foo; + // unused << foo.forget(); + friend void operator<<(const mozilla::unused_t& aUnused, + const already_AddRefed<T>& aRhs) + { + auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs); + aUnused << mutableAlreadyAddRefed->take(); + } + + MOZ_WARN_UNUSED_RESULT T* take() + { + T* rawPtr = mRawPtr; + mRawPtr = nullptr; + return rawPtr; + } + + /** + * This helper is useful in cases like + * + * already_AddRefed<BaseClass> + * Foo() + * { + * nsRefPtr<SubClass> x = ...; + * return x.forget(); + * } + * + * The autoconversion allows one to omit the idiom + * + * nsRefPtr<BaseClass> y = x.forget(); + * return y.forget(); + */ + template<class U> + operator already_AddRefed<U>() + { + U* tmp = mRawPtr; + mRawPtr = nullptr; + return already_AddRefed<U>(tmp); + } + + /** + * This helper provides a static_cast replacement for already_AddRefed, so + * if you have + * + * already_AddRefed<Parent> F(); + * + * you can write + * + * already_AddRefed<Child> + * G() + * { + * return F().downcast<Child>(); + * } + * + * instead of + * + * return dont_AddRef(static_cast<Child*>(F().get())); + */ + template<class U> + already_AddRefed<U> downcast() + { + U* tmp = static_cast<U*>(mRawPtr); + mRawPtr = nullptr; + return already_AddRefed<U>(tmp); + } + +private: + T* mRawPtr; +}; + +#endif // AlreadyAddRefed_h
--- a/xpcom/base/moz.build +++ b/xpcom/base/moz.build @@ -34,16 +34,17 @@ XPIDL_SOURCES += [ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': XPIDL_SOURCES += [ 'nsIMacUtils.idl', ] XPIDL_MODULE = 'xpcom_base' EXPORTS += [ + 'AlreadyAddRefed.h', 'CodeAddressService.h', 'ErrorList.h', 'nsAgg.h', 'nsAutoPtr.h', 'nsAutoRef.h', 'nsCom.h', 'nscore.h', 'nsCycleCollector.h',
--- a/xpcom/glue/nsCOMPtr.h +++ b/xpcom/glue/nsCOMPtr.h @@ -21,16 +21,17 @@ */ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Move.h" #include "mozilla/NullPtr.h" #include "mozilla/TypeTraits.h" +#include "AlreadyAddRefed.h" #include "nsDebug.h" // for |NS_ABORT_IF_FALSE|, |NS_ASSERTION| #include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al #include "nsCycleCollectionNoteChild.h" /* * WARNING: This file defines several macros for internal use only. These @@ -109,147 +110,16 @@ #endif namespace mozilla { struct unused_t; } // namespace mozilla -/** - * already_AddRefed cooperates with nsCOMPtr to allow you to assign in a - * pointer _without_ |AddRef|ing it. You might want to use this as a return - * type from a function that produces an already |AddRef|ed pointer as a - * result. - * - * See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. - * - * This type should be a nested class inside nsCOMPtr<T>. - * - * Yes, already_AddRefed could have been implemented as an nsCOMPtr_helper to - * avoid adding specialized machinery to nsCOMPtr ... but this is the simplest - * case, and perhaps worth the savings in time and space that its specific - * implementation affords over the more general solution offered by - * nsCOMPtr_helper. - */ -template<class T> -struct already_AddRefed -{ - /* - * We want to allow returning nullptr from functions returning - * already_AddRefed<T>, for simplicity. But we also don't want to allow - * returning raw T*, instead preferring creation of already_AddRefed<T> from - * an nsRefPtr, nsCOMPtr, or the like. - * - * We address the latter requirement by making the (T*) constructor explicit. - * But |return nullptr| won't consider an explicit constructor, so we need - * another constructor to handle it. Plain old (decltype(nullptr)) doesn't - * cut it, because if nullptr is emulated as __null (with type int or long), - * passing nullptr to an int/long parameter triggers compiler warnings. We - * need a type that no one can pass accidentally; a pointer-to-member-function - * (where no such function exists) does the trick nicely. - * - * That handles the return-value case. What about for locals, argument types, - * and so on? |already_AddRefed<T>(nullptr)| considers both overloads (and - * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity. - * We can target true nullptr using decltype(nullptr), but we can't target - * emulated nullptr the same way, because passing __null to an int/long - * parameter triggers compiler warnings. So just give up on this, and provide - * this behavior through the default constructor. - * - * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when - * nullptr no longer needs to be emulated to support the ancient b2g compiler. - * (The () overload could also be removed, if desired, if we changed callers.) - */ - already_AddRefed() : mRawPtr(nullptr) {} - - // The return and argument types here are arbitrarily selected so no - // corresponding member function exists. - typedef void (already_AddRefed::* MatchNullptr)(double, float); - MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {} - - explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {} - - // Disallowed. Use move semantics instead. - already_AddRefed(const already_AddRefed<T>& aOther) MOZ_DELETE; - - already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {} - - ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); } - - // Specialize the unused operator<< for already_AddRefed, to allow - // nsCOMPtr<nsIFoo> foo; - // unused << foo.forget(); - friend void operator<<(const mozilla::unused_t& aUnused, - const already_AddRefed<T>& aRhs) - { - auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs); - aUnused << mutableAlreadyAddRefed->take(); - } - - MOZ_WARN_UNUSED_RESULT T* take() - { - T* rawPtr = mRawPtr; - mRawPtr = nullptr; - return rawPtr; - } - - /** - * This helper is useful in cases like - * - * already_AddRefed<BaseClass> - * Foo() - * { - * nsRefPtr<SubClass> x = ...; - * return x.forget(); - * } - * - * The autoconversion allows one to omit the idiom - * - * nsRefPtr<BaseClass> y = x.forget(); - * return y.forget(); - */ - template<class U> - operator already_AddRefed<U>() - { - U* tmp = mRawPtr; - mRawPtr = nullptr; - return already_AddRefed<U>(tmp); - } - - /** - * This helper provides a static_cast replacement for already_AddRefed, so - * if you have - * - * already_AddRefed<Parent> F(); - * - * you can write - * - * already_AddRefed<Child> - * G() - * { - * return F().downcast<Child>(); - * } - * - * instead of - * - * return dont_AddRef(static_cast<Child*>(F().get())); - */ - template<class U> - already_AddRefed<U> downcast() - { - U* tmp = static_cast<U*>(mRawPtr); - mRawPtr = nullptr; - return already_AddRefed<U>(tmp); - } - -private: - T* mRawPtr; -}; - template<class T> inline already_AddRefed<T> dont_AddRef(T* aRawPtr) { return already_AddRefed<T>(aRawPtr); } template<class T>