diff options
author | Nathan Yee <ny.nathan.yee@gmail.com> | 2015-07-14 14:36:37 -0700 |
---|---|---|
committer | Jan Holesovsky <kendy@collabora.com> | 2015-07-22 07:18:22 +0200 |
commit | b59955bf2124b558147033782bf067a3723e4730 (patch) | |
tree | eb009a5eaa41daaba94cb17c5b6368c4b96dff83 /onlineupdate/source/update/inc | |
parent | 591238e8a4f1164adb51d3bada0cd90c3e7c655e (diff) |
online update tdf#68274: fix --enable-online-update=mar on Windows
Change-Id: I397566ae2488799399cad361b24a281d3599cc5b
Diffstat (limited to 'onlineupdate/source/update/inc')
-rw-r--r-- | onlineupdate/source/update/inc/mozilla/Char16.h | 239 | ||||
-rw-r--r-- | onlineupdate/source/update/inc/mozilla/Move.h | 238 | ||||
-rw-r--r-- | onlineupdate/source/update/inc/mozilla/Pair.h | 219 | ||||
-rw-r--r-- | onlineupdate/source/update/inc/mozilla/UniquePtr.h | 659 | ||||
-rw-r--r-- | onlineupdate/source/update/inc/nsAutoRef.h | 670 | ||||
-rw-r--r-- | onlineupdate/source/update/inc/nsWindowsHelpers.h | 159 |
6 files changed, 2184 insertions, 0 deletions
diff --git a/onlineupdate/source/update/inc/mozilla/Char16.h b/onlineupdate/source/update/inc/mozilla/Char16.h new file mode 100644 index 000000000000..f07494f7f47f --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Char16.h @@ -0,0 +1,239 @@ +/* -*- 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/. */ + +/* Implements a UTF-16 character type. */ + +#ifndef mozilla_Char16_h +#define mozilla_Char16_h + +#ifdef __cplusplus + +/* + * C++11 introduces a char16_t type and support for UTF-16 string and character + * literals. C++11's char16_t is a distinct builtin type. Technically, char16_t + * is a 16-bit code unit of a Unicode code point, not a "character". + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + /* + * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h + * typedefs char16_t as an unsigned short prior to MSVC 2015, which + * implemented C++11's distinct char16_t type. We would like to alias + * char16_t to Windows's 16-bit wchar_t so we can declare UTF-16 literals as + * constant expressions (and pass char16_t pointers to Windows APIs). We + * #define _CHAR16T here in order to prevent yvals.h from overriding our + * char16_t typedefs, which we set to wchar_t for C++ code. + * + * In addition, #defining _CHAR16T will prevent yvals.h from defining a + * char32_t type, so we have to undo that damage here and provide our own, + * which is identical to the yvals.h type. + */ +# define MOZ_UTF16_HELPER(s) L##s +# define _CHAR16T +typedef wchar_t char16_t; +typedef unsigned int char32_t; +#else + /* C++11 has a builtin char16_t type. */ +# define MOZ_UTF16_HELPER(s) u##s + /** + * This macro is used to distinguish when char16_t would be a distinct + * typedef from wchar_t. + */ +# define MOZ_CHAR16_IS_NOT_WCHAR +# ifdef WIN32 +# define MOZ_USE_CHAR16_WRAPPER +# endif +#endif + +#ifdef MOZ_USE_CHAR16_WRAPPER +# include <string> + /** + * Win32 API extensively uses wchar_t, which is represented by a separated + * builtin type than char16_t per spec. It's not the case for MSVC prior to + * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and + * char16_t on Windows builds. This class is supposed to make it easier. It + * stores char16_t const pointer, but provides implicit casts for wchar_t as + * well. On other platforms, we simply use + * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as + * similar to this typedef, including providing some casts that are allowed + * by the typedef. + */ +class char16ptr_t +{ +private: + const char16_t* mPtr; + static_assert(sizeof(char16_t) == sizeof(wchar_t), + "char16_t and wchar_t sizes differ"); + +public: + char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} + char16ptr_t(const wchar_t* aPtr) : + mPtr(reinterpret_cast<const char16_t*>(aPtr)) + {} + + /* Without this, nullptr assignment would be ambiguous. */ + constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} + + operator const char16_t*() const + { + return mPtr; + } + operator const wchar_t*() const + { + return reinterpret_cast<const wchar_t*>(mPtr); + } + operator const void*() const + { + return mPtr; + } + operator bool() const + { + return mPtr != nullptr; + } + operator std::wstring() const + { + return std::wstring(static_cast<const wchar_t*>(*this)); + } + + /* Explicit cast operators to allow things like (char16_t*)str. */ + explicit operator char16_t*() const + { + return const_cast<char16_t*>(mPtr); + } + explicit operator wchar_t*() const + { + return const_cast<wchar_t*>(static_cast<const wchar_t*>(*this)); + } + explicit operator int() const + { + return reinterpret_cast<intptr_t>(mPtr); + } + explicit operator unsigned int() const + { + return reinterpret_cast<uintptr_t>(mPtr); + } + explicit operator long() const + { + return reinterpret_cast<intptr_t>(mPtr); + } + explicit operator unsigned long() const + { + return reinterpret_cast<uintptr_t>(mPtr); + } + explicit operator long long() const + { + return reinterpret_cast<intptr_t>(mPtr); + } + explicit operator unsigned long long() const + { + return reinterpret_cast<uintptr_t>(mPtr); + } + + /** + * Some Windows API calls accept BYTE* but require that data actually be + * WCHAR*. Supporting this requires explicit operators to support the + * requisite explicit casts. + */ + explicit operator const char*() const + { + return reinterpret_cast<const char*>(mPtr); + } + explicit operator const unsigned char*() const + { + return reinterpret_cast<const unsigned char*>(mPtr); + } + explicit operator unsigned char*() const + { + return + const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(mPtr)); + } + explicit operator void*() const + { + return const_cast<char16_t*>(mPtr); + } + + /* Some operators used on pointers. */ + char16_t operator[](size_t aIndex) const + { + return mPtr[aIndex]; + } + bool operator==(const char16ptr_t& aOther) const + { + return mPtr == aOther.mPtr; + } + bool operator==(decltype(nullptr)) const + { + return mPtr == nullptr; + } + bool operator!=(const char16ptr_t& aOther) const + { + return mPtr != aOther.mPtr; + } + bool operator!=(decltype(nullptr)) const + { + return mPtr != nullptr; + } + char16ptr_t operator+(int aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned int aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(long long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned long long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + ptrdiff_t operator-(const char16ptr_t& aOther) const + { + return mPtr - aOther.mPtr; + } +}; + +inline decltype((char*)0-(char*)0) +operator-(const char16_t* aX, const char16ptr_t aY) +{ + return aX - static_cast<const char16_t*>(aY); +} + +#else + +typedef const char16_t* char16ptr_t; + +#endif + +/* + * Macro arguments used in concatenation or stringification won't be expanded. + * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to + * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper + * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro + * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the + * CPP manual for a more accurate and precise explanation. + */ +#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) + +static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); +static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?"); +static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); +static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); + +#endif + +#endif /* mozilla_Char16_h */ + diff --git a/onlineupdate/source/update/inc/mozilla/Move.h b/onlineupdate/source/update/inc/mozilla/Move.h new file mode 100644 index 000000000000..f6d0bfc1ca38 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Move.h @@ -0,0 +1,238 @@ +/* -*- 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/. */ + +/* C++11-style, but C++98-usable, "move references" implementation. */ + +#ifndef mozilla_Move_h +#define mozilla_Move_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +/* + * "Move" References + * + * Some types can be copied much more efficiently if we know the original's + * value need not be preserved --- that is, if we are doing a "move", not a + * "copy". For example, if we have: + * + * Vector<T> u; + * Vector<T> v(u); + * + * the constructor for v must apply a copy constructor to each element of u --- + * taking time linear in the length of u. However, if we know we will not need u + * any more once v has been initialized, then we could initialize v very + * efficiently simply by stealing u's dynamically allocated buffer and giving it + * to v --- a constant-time operation, regardless of the size of u. + * + * Moves often appear in container implementations. For example, when we append + * to a vector, we may need to resize its buffer. This entails moving each of + * its extant elements from the old, smaller buffer to the new, larger buffer. + * But once the elements have been migrated, we're just going to throw away the + * old buffer; we don't care if they still have their values. So if the vector's + * element type can implement "move" more efficiently than "copy", the vector + * resizing should by all means use a "move" operation. Hash tables should also + * use moves when resizing their internal array as entries are added and + * removed. + * + * The details of the optimization, and whether it's worth applying, vary + * from one type to the next: copying an 'int' is as cheap as moving it, so + * there's no benefit in distinguishing 'int' moves from copies. And while + * some constructor calls for complex types are moves, many really have to + * be copies, and can't be optimized this way. So we need: + * + * 1) a way for a type (like Vector) to announce that it can be moved more + * efficiently than it can be copied, and provide an implementation of that + * move operation; and + * + * 2) a way for a particular invocation of a copy constructor to say that it's + * really a move, not a copy, and that the value of the original isn't + * important afterwards (although it must still be safe to destroy). + * + * If a constructor has a single argument of type 'T&&' (an 'rvalue reference + * to T'), that indicates that it is a 'move constructor'. That's 1). It should + * move, not copy, its argument into the object being constructed. It may leave + * the original in any safely-destructible state. + * + * If a constructor's argument is an rvalue, as in 'C(f(x))' or 'C(x + y)', as + * opposed to an lvalue, as in 'C(x)', then overload resolution will prefer the + * move constructor, if there is one. The 'mozilla::Move' function, defined in + * this file, is an identity function you can use in a constructor invocation to + * make any argument into an rvalue, like this: C(Move(x)). That's 2). (You + * could use any function that works, but 'Move' indicates your intention + * clearly.) + * + * Where we might define a copy constructor for a class C like this: + * + * C(const C& rhs) { ... copy rhs to this ... } + * + * we would declare a move constructor like this: + * + * C(C&& rhs) { .. move rhs to this ... } + * + * And where we might perform a copy like this: + * + * C c2(c1); + * + * we would perform a move like this: + * + * C c2(Move(c1)); + * + * Note that 'T&&' implicitly converts to 'T&'. So you can pass a 'T&&' to an + * ordinary copy constructor for a type that doesn't support a special move + * constructor, and you'll just get a copy. This means that templates can use + * Move whenever they know they won't use the original value any more, even if + * they're not sure whether the type at hand has a specialized move constructor. + * If it doesn't, the 'T&&' will just convert to a 'T&', and the ordinary copy + * constructor will apply. + * + * A class with a move constructor can also provide a move assignment operator. + * A generic definition would run this's destructor, and then apply the move + * constructor to *this's memory. A typical definition: + * + * C& operator=(C&& rhs) { + * MOZ_ASSERT(&rhs != this, "self-moves are prohibited"); + * this->~C(); + * new(this) C(Move(rhs)); + * return *this; + * } + * + * With that in place, one can write move assignments like this: + * + * c2 = Move(c1); + * + * This destroys c2, moves c1's value to c2, and leaves c1 in an undefined but + * destructible state. + * + * As we say, a move must leave the original in a "destructible" state. The + * original's destructor will still be called, so if a move doesn't + * actually steal all its resources, that's fine. We require only that the + * move destination must take on the original's value; and that destructing + * the original must not break the move destination. + * + * (Opinions differ on whether move assignment operators should deal with move + * assignment of an object onto itself. It seems wise to either handle that + * case, or assert that it does not occur.) + * + * Forwarding: + * + * Sometimes we want copy construction or assignment if we're passed an ordinary + * value, but move construction if passed an rvalue reference. For example, if + * our constructor takes two arguments and either could usefully be a move, it + * seems silly to write out all four combinations: + * + * C::C(X& x, Y& y) : x(x), y(y) { } + * C::C(X& x, Y&& y) : x(x), y(Move(y)) { } + * C::C(X&& x, Y& y) : x(Move(x)), y(y) { } + * C::C(X&& x, Y&& y) : x(Move(x)), y(Move(y)) { } + * + * To avoid this, C++11 has tweaks to make it possible to write what you mean. + * The four constructor overloads above can be written as one constructor + * template like so[0]: + * + * template <typename XArg, typename YArg> + * C::C(XArg&& x, YArg&& y) : x(Forward<XArg>(x)), y(Forward<YArg>(y)) { } + * + * ("'Don't Repeat Yourself'? What's that?") + * + * This takes advantage of two new rules in C++11: + * + * - First, when a function template takes an argument that is an rvalue + * reference to a template argument (like 'XArg&& x' and 'YArg&& y' above), + * then when the argument is applied to an lvalue, the template argument + * resolves to 'T&'; and when it is applied to an rvalue, the template + * argument resolves to 'T'. Thus, in a call to C::C like: + * + * X foo(int); + * Y yy; + * + * C(foo(5), yy) + * + * XArg would resolve to 'X', and YArg would resolve to 'Y&'. + * + * - Second, Whereas C++ used to forbid references to references, C++11 defines + * 'collapsing rules': 'T& &', 'T&& &', and 'T& &&' (that is, any combination + * involving an lvalue reference) now collapse to simply 'T&'; and 'T&& &&' + * collapses to 'T&&'. + * + * Thus, in the call above, 'XArg&&' is 'X&&'; and 'YArg&&' is 'Y& &&', which + * collapses to 'Y&'. Because the arguments are declared as rvalue references + * to template arguments, the lvalue-ness "shines through" where present. + * + * Then, the 'Forward<T>' function --- you must invoke 'Forward' with its type + * argument --- returns an lvalue reference or an rvalue reference to its + * argument, depending on what T is. In our unified constructor definition, that + * means that we'll invoke either the copy or move constructors for x and y, + * depending on what we gave C's constructor. In our call, we'll move 'foo()' + * into 'x', but copy 'yy' into 'y'. + * + * This header file defines Move and Forward in the mozilla namespace. It's up + * to individual containers to annotate moves as such, by calling Move; and it's + * up to individual types to define move constructors and assignment operators + * when valuable. + * + * (C++11 says that the <utility> header file should define 'std::move' and + * 'std::forward', which are just like our 'Move' and 'Forward'; but those + * definitions aren't available in that header on all our platforms, so we + * define them ourselves here.) + * + * 0. This pattern is known as "perfect forwarding". Interestingly, it is not + * actually perfect, and it can't forward all possible argument expressions! + * There is a C++11 issue: you can't form a reference to a bit-field. As a + * workaround, assign the bit-field to a local variable and use that: + * + * // C is as above + * struct S { int x : 1; } s; + * C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those + * int tmp = s.x; + * C(tmp, 0); // OK: tmp not a bit-field + */ + +/** + * Identical to std::Move(); this is necessary until our stlport supports + * std::move(). + */ +template<typename T> +inline typename RemoveReference<T>::Type&& +Move(T&& aX) +{ + return static_cast<typename RemoveReference<T>::Type&&>(aX); +} + +/** + * These two overloads are identical to std::forward(); they are necessary until + * our stlport supports std::forward(). + */ +template<typename T> +inline T&& +Forward(typename RemoveReference<T>::Type& aX) +{ + return static_cast<T&&>(aX); +} + +template<typename T> +inline T&& +Forward(typename RemoveReference<T>::Type&& aX) +{ + static_assert(!IsLvalueReference<T>::value, + "misuse of Forward detected! try the other overload"); + return static_cast<T&&>(aX); +} + +/** Swap |aX| and |aY| using move-construction if possible. */ +template<typename T> +inline void +Swap(T& aX, T& aY) +{ + T tmp(Move(aX)); + aX = Move(aY); + aY = Move(tmp); +} + +} // namespace mozilla + +#endif /* mozilla_Move_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Pair.h b/onlineupdate/source/update/inc/mozilla/Pair.h new file mode 100644 index 000000000000..ad7b86a29c62 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Pair.h @@ -0,0 +1,219 @@ +/* -*- 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/. */ + +/* A class holding a pair of objects that tries to conserve storage space. */ + +#ifndef mozilla_Pair_h +#define mozilla_Pair_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +enum StorageType { AsBase, AsMember }; + +// Optimize storage using the Empty Base Optimization -- that empty base classes +// don't take up space -- to optimize size when one or the other class is +// stateless and can be used as a base class. +// +// The extra conditions on storage for B are necessary so that PairHelper won't +// ambiguously inherit from either A or B, such that one or the other base class +// would be inaccessible. +template<typename A, typename B, + detail::StorageType = + IsEmpty<A>::value ? detail::AsBase : detail::AsMember, + detail::StorageType = + IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value + ? detail::AsBase + : detail::AsMember> +struct PairHelper; + +template<typename A, typename B> +struct PairHelper<A, B, AsMember, AsMember> +{ +protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& aA, BArg&& aB) + : mFirstA(Forward<AArg>(aA)), + mSecondB(Forward<BArg>(aB)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(mSecondB, aOther.mSecondB); + } + +private: + A mFirstA; + B mSecondB; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsMember, AsBase> : private B +{ +protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& aA, BArg&& aB) + : B(Forward<BArg>(aB)), + mFirstA(Forward<AArg>(aA)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return *this; } + const B& second() const { return *this; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(static_cast<B&>(*this), static_cast<B&>(aOther)); + } + +private: + A mFirstA; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsBase, AsMember> : private A +{ +protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward<AArg>(aA)), + mSecondB(Forward<BArg>(aB)) + {} + + A& first() { return *this; } + const A& first() const { return *this; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(static_cast<A&>(*this), static_cast<A&>(aOther)); + Swap(mSecondB, aOther.mSecondB); + } + +private: + B mSecondB; +}; + +template<typename A, typename B> +struct PairHelper<A, B, AsBase, AsBase> : private A, private B +{ +protected: + template<typename AArg, typename BArg> + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward<AArg>(aA)), + B(Forward<BArg>(aB)) + {} + + A& first() { return static_cast<A&>(*this); } + const A& first() const { return static_cast<A&>(*this); } + B& second() { return static_cast<B&>(*this); } + const B& second() const { return static_cast<B&>(*this); } + + void swap(PairHelper& aOther) + { + Swap(static_cast<A&>(*this), static_cast<A&>(aOther)); + Swap(static_cast<B&>(*this), static_cast<B&>(aOther)); + } +}; + +} // namespace detail + +/** + * Pair is the logical concatenation of an instance of A with an instance B. + * Space is conserved when possible. Neither A nor B may be a final class. + * + * It's typically clearer to have individual A and B member fields. Except if + * you want the space-conserving qualities of Pair, you're probably better off + * not using this! + * + * No guarantees are provided about the memory layout of A and B, the order of + * initialization or destruction of A and B, and so on. (This is approximately + * required to optimize space usage.) The first/second names are merely + * conceptual! + */ +template<typename A, typename B> +struct Pair + : private detail::PairHelper<A, B> +{ + typedef typename detail::PairHelper<A, B> Base; + +public: + template<typename AArg, typename BArg> + Pair(AArg&& aA, BArg&& aB) + : Base(Forward<AArg>(aA), Forward<BArg>(aB)) + {} + + Pair(Pair&& aOther) + : Base(Move(aOther.first()), Move(aOther.second())) + { } + + Pair(const Pair& aOther) = default; + + Pair& operator=(Pair&& aOther) + { + MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); + + first() = Move(aOther.first()); + second() = Move(aOther.second()); + + return *this; + } + + Pair& operator=(const Pair& aOther) = default; + + /** The A instance. */ + using Base::first; + /** The B instance. */ + using Base::second; + + /** Swap this pair with another pair. */ + void swap(Pair& aOther) { Base::swap(aOther); } +}; + +template<typename A, class B> +void +Swap(Pair<A, B>& aX, Pair<A, B>& aY) +{ + aX.swap(aY); +} + +/** + * MakePair allows you to construct a Pair instance using type inference. A call + * like this: + * + * MakePair(Foo(), Bar()) + * + * will return a Pair<Foo, Bar>. + */ +template<typename A, typename B> +Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type, + typename RemoveCV<typename RemoveReference<B>::Type>::Type> +MakePair(A&& aA, B&& aB) +{ + return + Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type, + typename RemoveCV<typename RemoveReference<B>::Type>::Type>( + Forward<A>(aA), + Forward<B>(aB)); +} + +} // namespace mozilla + +#endif /* mozilla_Pair_h */ diff --git a/onlineupdate/source/update/inc/mozilla/UniquePtr.h b/onlineupdate/source/update/inc/mozilla/UniquePtr.h new file mode 100644 index 000000000000..d58ffe335c53 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/UniquePtr.h @@ -0,0 +1,659 @@ +/* -*- 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/. */ + +/* Smart pointer managing sole ownership of a resource. */ + +#ifndef mozilla_UniquePtr_h +#define mozilla_UniquePtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/Move.h" +#include "mozilla/Pair.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +template<typename T> class DefaultDelete; +template<typename T, class D = DefaultDelete<T>> class UniquePtr; + +} // namespace mozilla + +namespace mozilla { + +/** + * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be + * transferred out of a UniquePtr through explicit action, but otherwise the + * resource is destroyed when the UniquePtr is destroyed. + * + * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr + * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr + * obviously *can't* copy ownership of its singly-owned resource. So what + * happens if you try to copy one? Bizarrely, ownership is implicitly + * *transferred*, preserving single ownership but breaking code that assumes a + * copy of an object is identical to the original. (This is why auto_ptr is + * prohibited in STL containers.) + * + * UniquePtr solves this problem by being *movable* rather than copyable. + * Instead of passing a |UniquePtr u| directly to the constructor or assignment + * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* + * ownership out of |u|, into the target of the construction/assignment. After + * the transfer completes, |u| contains |nullptr| and may be safely destroyed. + * This preserves single ownership but also allows UniquePtr to be moved by + * algorithms that have been made move-safe. (Note: if |u| is instead a + * temporary expression, don't use |Move()|: just pass the expression, because + * it's already move-ready. For more information see Move.h.) + * + * UniquePtr is also better than std::auto_ptr in that the deletion operation is + * customizable. An optional second template parameter specifies a class that + * (through its operator()(T*)) implements the desired deletion policy. If no + * policy is specified, mozilla::DefaultDelete<T> is used -- which will either + * |delete| or |delete[]| the resource, depending whether the resource is an + * array. Custom deletion policies ideally should be empty classes (no member + * fields, no member fields in base classes, no virtual methods/inheritance), + * because then UniquePtr can be just as efficient as a raw pointer. + * + * Use of UniquePtr proceeds like so: + * + * UniquePtr<int> g1; // initializes to nullptr + * g1.reset(new int); // switch resources using reset() + * g1 = nullptr; // clears g1, deletes the int + * + * UniquePtr<int> g2(new int); // owns that int + * int* p = g2.release(); // g2 leaks its int -- still requires deletion + * delete p; // now freed + * + * struct S { int x; S(int x) : x(x) {} }; + * UniquePtr<S> g3, g4(new S(5)); + * g3 = Move(g4); // g3 owns the S, g4 cleared + * S* p = g3.get(); // g3 still owns |p| + * assert(g3->x == 5); // operator-> works (if .get() != nullptr) + * assert((*g3).x == 5); // also operator* (again, if not cleared) + * Swap(g3, g4); // g4 now owns the S, g3 cleared + * g3.swap(g4); // g3 now owns the S, g4 cleared + * UniquePtr<S> g5(Move(g3)); // g5 owns the S, g3 cleared + * g5.reset(); // deletes the S, g5 cleared + * + * struct FreePolicy { void operator()(void* p) { free(p); } }; + * UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); + * int* ptr = g6.get(); + * g6 = nullptr; // calls free(ptr) + * + * Now, carefully note a few things you *can't* do: + * + * UniquePtr<int> b1; + * b1 = new int; // BAD: can only assign another UniquePtr + * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() + * + * UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr + * UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr + * + * (Note that changing a UniquePtr to store a direct |new| expression is + * permitted, but usually you should use MakeUnique, defined at the end of this + * header.) + * + * A few miscellaneous notes: + * + * UniquePtr, when not instantiated for an array type, can be move-constructed + * and move-assigned, not only from itself but from "derived" UniquePtr<U, E> + * instantiations where U converts to T and E converts to D. If you want to use + * this, you're going to have to specify a deletion policy for both UniquePtr + * instantations, and T pretty much has to have a virtual destructor. In other + * words, this doesn't work: + * + * struct Base { virtual ~Base() {} }; + * struct Derived : Base {}; + * + * UniquePtr<Base> b1; + * // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert + * UniquePtr<Derived> d1(Move(b)); + * + * UniquePtr<Base> b2; + * UniquePtr<Derived, DefaultDelete<Base>> d2(Move(b2)); // okay + * + * UniquePtr is specialized for array types. Specializing with an array type + * creates a smart-pointer version of that array -- not a pointer to such an + * array. + * + * UniquePtr<int[]> arr(new int[5]); + * arr[0] = 4; + * + * What else is different? Deletion of course uses |delete[]|. An operator[] + * is provided. Functionality that doesn't make sense for arrays is removed. + * The constructors and mutating methods only accept array pointers (not T*, U* + * that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|. + * + * It's perfectly okay to return a UniquePtr from a method to assure the related + * resource is properly deleted. You'll need to use |Move()| when returning a + * local UniquePtr. Otherwise you can return |nullptr|, or you can return + * |UniquePtr(ptr)|. + * + * UniquePtr will commonly be a member of a class, with lifetime equivalent to + * that of that class. If you want to expose the related resource, you could + * expose a raw pointer via |get()|, but ownership of a raw pointer is + * inherently unclear. So it's better to expose a |const UniquePtr&| instead. + * This prohibits mutation but still allows use of |get()| when needed (but + * operator-> is preferred). Of course, you can only use this smart pointer as + * long as the enclosing class instance remains live -- no different than if you + * exposed the |get()| raw pointer. + * + * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| + * argument. To specify an inout parameter (where the method may or may not + * take ownership of the resource, or reset it), or to specify an out parameter + * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| + * argument. To unconditionally transfer ownership of a UniquePtr + * into a method, use a |UniquePtr| argument. To conditionally transfer + * ownership of a resource into a method, should the method want it, use a + * |UniquePtr&&| argument. + */ +template<typename T, class D> +class UniquePtr +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair<Pointer, DeleterType> mTuple; + + Pointer& ptr() { return mTuple.first(); } + const Pointer& ptr() const { return mTuple.first(); } + + DeleterType& del() { return mTuple.second(); } + const DeleterType& del() const { return mTuple.second(); } + +public: + /** + * Construct a UniquePtr containing |nullptr|. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast<Pointer>(nullptr), DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + + UniquePtr(Pointer aPtr, + typename Conditional<IsReference<D>::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr<T, reference to function>! Ideally + // you should make deletion use the same function every time, using a + // deleter policy: + // + // // BAD, won't compile with MSVC10, deleter doesn't need to be a + // // variable at all + // typedef void (&FreeSignature)(void*); + // UniquePtr<int, FreeSignature> ptr((int*) malloc(sizeof(int)), free); + // + // // GOOD, compiles with MSVC10, deletion behavior statically known and + // // optimizable + // struct DeleteByFreeing + // { + // void operator()(void* aPtr) { free(aPtr); } + // }; + // + // If deletion really, truly, must be a variable: you might be able to work + // around this with a deleter class that contains the function reference. + // But this workaround is untried and untested, because variable deletion + // behavior really isn't something you should use. + UniquePtr(Pointer aPtr, + typename RemoveReference<D>::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference<D>::value, + "rvalue deleter can't be stored by reference"); + } + + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward<DeleterType>(aOther.getDeleter())) + {} + + MOZ_IMPLICIT + UniquePtr(decltype(nullptr)) + : mTuple(nullptr, DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + + template<typename U, class E> + UniquePtr(UniquePtr<U, E>&& aOther, + typename EnableIf<IsConvertible<typename UniquePtr<U, E>::Pointer, + Pointer>::value && + !IsArray<U>::value && + (IsReference<D>::value + ? IsSame<D, E>::value + : IsConvertible<E, D>::value), + int>::Type aDummy = 0) + : mTuple(aOther.release(), Forward<E>(aOther.getDeleter())) + { + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward<DeleterType>(aOther.getDeleter()); + return *this; + } + + template<typename U, typename E> + UniquePtr& operator=(UniquePtr<U, E>&& aOther) + { + static_assert(IsConvertible<typename UniquePtr<U, E>::Pointer, + Pointer>::value, + "incompatible UniquePtr pointees"); + static_assert(!IsArray<U>::value, + "can't assign from UniquePtr holding an array"); + + reset(aOther.release()); + getDeleter() = Forward<E>(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(decltype(nullptr)) + { + reset(nullptr); + return *this; + } + + T& operator*() const { return *get(); } + Pointer operator->() const + { + MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); + return get(); + } + + explicit operator bool() const { return get() != nullptr; } + + Pointer get() const { return ptr(); } + + DeleterType& getDeleter() { return del(); } + const DeleterType& getDeleter() const { return del(); } + + Pointer release() + { + Pointer p = ptr(); + ptr() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = ptr(); + ptr() = aPtr; + if (old != nullptr) { + getDeleter()(old); + } + } + + void swap(UniquePtr& aOther) + { + mTuple.swap(aOther.mTuple); + } + +private: + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! +}; + +// In case you didn't read the comment by the main definition (you should!): the +// UniquePtr<T[]> specialization exists to manage array pointers. It deletes +// such pointers using delete[], it will reject construction and modification +// attempts using U* or U[]. Otherwise it works like the normal UniquePtr. +template<typename T, class D> +class UniquePtr<T[], D> +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair<Pointer, DeleterType> mTuple; + +public: + /** + * Construct a UniquePtr containing nullptr. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast<Pointer>(nullptr), DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + +private: + // delete[] knows how to handle *only* an array of a single class type. For + // delete[] to work correctly, it must know the size of each element, the + // fields and base classes of each element requiring destruction, and so on. + // So forbid all overloads which would end up invoking delete[] on a pointer + // of the wrong type. + template<typename U> + UniquePtr(U&& aU, + typename EnableIf<IsPointer<U>::value && + IsConvertible<U, Pointer>::value, + int>::Type aDummy = 0) + = delete; + +public: + UniquePtr(Pointer aPtr, + typename Conditional<IsReference<D>::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr<T[], reference to function>! See the + // comment by this constructor in the non-T[] specialization above. + UniquePtr(Pointer aPtr, + typename RemoveReference<D>::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference<D>::value, + "rvalue deleter can't be stored by reference"); + } + +private: + // Forbidden for the same reasons as stated above. + template<typename U, typename V> + UniquePtr(U&& aU, V&& aV, + typename EnableIf<IsPointer<U>::value && + IsConvertible<U, Pointer>::value, + int>::Type aDummy = 0) + = delete; + +public: + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward<DeleterType>(aOther.getDeleter())) + {} + + MOZ_IMPLICIT + UniquePtr(decltype(nullptr)) + : mTuple(nullptr, DeleterType()) + { + static_assert(!IsPointer<D>::value, "must provide a deleter instance"); + static_assert(!IsReference<D>::value, "must provide a deleter instance"); + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward<DeleterType>(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(decltype(nullptr)) + { + reset(); + return *this; + } + + explicit operator bool() const { return get() != nullptr; } + + T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } + Pointer get() const { return mTuple.first(); } + + DeleterType& getDeleter() { return mTuple.second(); } + const DeleterType& getDeleter() const { return mTuple.second(); } + + Pointer release() + { + Pointer p = mTuple.first(); + mTuple.first() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = mTuple.first(); + mTuple.first() = aPtr; + if (old != nullptr) { + mTuple.second()(old); + } + } + + void reset(decltype(nullptr)) + { + Pointer old = mTuple.first(); + mTuple.first() = nullptr; + if (old != nullptr) { + mTuple.second()(old); + } + } + +private: + template<typename U> + void reset(U) = delete; + +public: + void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } + +private: + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! +}; + +/** A default deletion policy using plain old operator delete. */ +template<typename T> +class DefaultDelete +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + template<typename U> + DefaultDelete(const DefaultDelete<U>& aOther, + typename EnableIf<mozilla::IsConvertible<U*, T*>::value, + int>::Type aDummy = 0) + {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete aPtr; + } +}; + +/** A default deletion policy using operator delete[]. */ +template<typename T> +class DefaultDelete<T[]> +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete[] aPtr; + } + +private: + template<typename U> + void operator()(U* aPtr) const = delete; +}; + +template<typename T, class D> +void +Swap(UniquePtr<T, D>& aX, UniquePtr<T, D>& aY) +{ + aX.swap(aY); +} + +template<typename T, class D, typename U, class E> +bool +operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) +{ + return aX.get() == aY.get(); +} + +template<typename T, class D, typename U, class E> +bool +operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) +{ + return aX.get() != aY.get(); +} + +template<typename T, class D> +bool +operator==(const UniquePtr<T, D>& aX, decltype(nullptr)) +{ + return !aX; +} + +template<typename T, class D> +bool +operator==(decltype(nullptr), const UniquePtr<T, D>& aX) +{ + return !aX; +} + +template<typename T, class D> +bool +operator!=(const UniquePtr<T, D>& aX, decltype(nullptr)) +{ + return bool(aX); +} + +template<typename T, class D> +bool +operator!=(decltype(nullptr), const UniquePtr<T, D>& aX) +{ + return bool(aX); +} + +// No operator<, operator>, operator<=, operator>= for now because simplicity. + +namespace detail { + +template<typename T> +struct UniqueSelector +{ + typedef UniquePtr<T> SingleObject; +}; + +template<typename T> +struct UniqueSelector<T[]> +{ + typedef UniquePtr<T[]> UnknownBound; +}; + +template<typename T, decltype(sizeof(int)) N> +struct UniqueSelector<T[N]> +{ + typedef UniquePtr<T[N]> KnownBound; +}; + +} // namespace detail + +/** + * MakeUnique is a helper function for allocating new'd objects and arrays, + * returning a UniquePtr containing the resulting pointer. The semantics of + * MakeUnique<Type>(...) are as follows. + * + * If Type is an array T[n]: + * Disallowed, deleted, no overload for you! + * If Type is an array T[]: + * MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned + * is as if by |new T[n]()|, which value-initializes each element. (If T + * isn't a class type, this will zero each element. If T is a class type, + * then roughly speaking, each element will be constructed using its default + * constructor. See C++11 [dcl.init]p7 for the full gory details.) + * If Type is non-array T: + * The arguments passed to MakeUnique<T>(...) are forwarded into a + * |new T(...)| call, initializing the T as would happen if executing + * |T(...)|. + * + * There are various benefits to using MakeUnique instead of |new| expressions. + * + * First, MakeUnique eliminates use of |new| from code entirely. If objects are + * only created through UniquePtr, then (assuming all explicit release() calls + * are safe, including transitively, and no type-safety casting funniness) + * correctly maintained ownership of the UniquePtr guarantees no leaks are + * possible. (This pays off best if a class is only ever created through a + * factory method on the class, using a private constructor.) + * + * Second, initializing a UniquePtr using a |new| expression requires repeating + * the name of the new'd type, whereas MakeUnique in concert with the |auto| + * keyword names it only once: + * + * UniquePtr<char> ptr1(new char()); // repetitive + * auto ptr2 = MakeUnique<char>(); // shorter + * + * Of course this assumes the reader understands the operation MakeUnique + * performs. In the long run this is probably a reasonable assumption. In the + * short run you'll have to use your judgment about what readers can be expected + * to know, or to quickly look up. + * + * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In + * contrast you can't assign a pointer into a UniquePtr without using the + * cumbersome reset(). + * + * UniquePtr<char> p; + * p = new char; // ERROR + * p.reset(new char); // works, but fugly + * p = MakeUnique<char>(); // preferred + * + * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. + * An exception thrown after |new T| succeeds will leak that memory, unless the + * pointer is assigned to an object that will manage its ownership. UniquePtr + * ably serves this function.) + */ + +template<typename T, typename... Args> +typename detail::UniqueSelector<T>::SingleObject +MakeUnique(Args&&... aArgs) +{ + return UniquePtr<T>(new T(Forward<Args>(aArgs)...)); +} + +template<typename T> +typename detail::UniqueSelector<T>::UnknownBound +MakeUnique(decltype(sizeof(int)) aN) +{ + typedef typename RemoveExtent<T>::Type ArrayType; + return UniquePtr<T>(new ArrayType[aN]()); +} + +template<typename T, typename... Args> +typename detail::UniqueSelector<T>::KnownBound +MakeUnique(Args&&... aArgs) = delete; + +} // namespace mozilla + +#endif /* mozilla_UniquePtr_h */ diff --git a/onlineupdate/source/update/inc/nsAutoRef.h b/onlineupdate/source/update/inc/nsAutoRef.h new file mode 100644 index 000000000000..a159f5954e96 --- /dev/null +++ b/onlineupdate/source/update/inc/nsAutoRef.h @@ -0,0 +1,670 @@ +/* -*- 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 nsAutoRef_h_ +#define nsAutoRef_h_ + +#include "mozilla/Attributes.h" + +template <class T> class nsSimpleRef; +template <class T> class nsAutoRefBase; +template <class T> class nsReturnRef; +template <class T> class nsReturningRef; + +/** + * template <class T> class nsAutoRef + * + * A class that holds a handle to a resource that must be released. + * No reference is added on construction. + * + * No copy constructor nor copy assignment operators are available, so the + * resource will be held until released on destruction or explicitly + * |reset()| or transferred through provided methods. + * + * The publicly available methods are the public methods on this class and its + * public base classes |nsAutoRefBase<T>| and |nsSimpleRef<T>|. + * + * For ref-counted resources see also |nsCountedRef<T>|. + * For function return values see |nsReturnRef<T>|. + * + * For each class |T|, |nsAutoRefTraits<T>| or |nsSimpleRef<T>| must be + * specialized to use |nsAutoRef<T>| and |nsCountedRef<T>|. + * + * @param T A class identifying the type of reference held by the + * |nsAutoRef<T>| and the unique set methods for managing references + * to the resource (defined by |nsAutoRefTraits<T>| or + * |nsSimpleRef<T>|). + * + * Often this is the class representing the resource. Sometimes a + * new possibly-incomplete class may need to be declared. + * + * + * Example: An Automatically closing file descriptor + * + * // References that are simple integral types (as file-descriptors are) + * // usually need a new class to represent the resource and how to handle its + * // references. + * class nsRawFD; + * + * // Specializing nsAutoRefTraits<nsRawFD> describes how to manage file + * // descriptors, so that nsAutoRef<nsRawFD> provides automatic closing of + * // its file descriptor on destruction. + * template <> + * class nsAutoRefTraits<nsRawFD> { + * public: + * // The file descriptor is held in an int. + * typedef int RawRef; + * // -1 means that there is no file associated with the handle. + * static int Void() { return -1; } + * // The file associated with a file descriptor is released with close(). + * static void Release(RawRef aFD) { close(aFD); } + * }; + * + * // A function returning a file descriptor that must be closed. + * nsReturnRef<nsRawFD> get_file(const char *filename) { + * // Constructing from a raw file descriptor assumes ownership. + * nsAutoRef<nsRawFD> fd(open(filename, O_RDONLY)); + * fcntl(fd, F_SETFD, FD_CLOEXEC); + * return fd.out(); + * } + * + * void f() { + * unsigned char buf[1024]; + * + * // Hold a file descriptor for /etc/hosts in fd1. + * nsAutoRef<nsRawFD> fd1(get_file("/etc/hosts")); + * + * nsAutoRef<nsRawFD> fd2; + * fd2.steal(fd1); // fd2 takes the file descriptor from fd1 + * ssize_t count = read(fd1, buf, 1024); // error fd1 has no file + * count = read(fd2, buf, 1024); // reads from /etc/hosts + * + * // If the file descriptor is not stored then it is closed. + * get_file("/etc/login.defs"); // login.defs is closed + * + * // Now use fd1 to hold a file descriptor for /etc/passwd. + * fd1 = get_file("/etc/passwd"); + * + * // The nsAutoRef<nsRawFD> can give up the file descriptor if explicitly + * // instructed, but the caller must then ensure that the file is closed. + * int rawfd = fd1.disown(); + * + * // Assume ownership of another file descriptor. + * fd1.own(open("/proc/1/maps"); + * + * // On destruction, fd1 closes /proc/1/maps and fd2 closes /etc/hosts, + * // but /etc/passwd is not closed. + * } + * + */ + + +template <class T> +class nsAutoRef : public nsAutoRefBase<T> +{ +protected: + typedef nsAutoRef<T> ThisClass; + typedef nsAutoRefBase<T> BaseClass; + typedef nsSimpleRef<T> SimpleRef; + typedef typename BaseClass::RawRefOnly RawRefOnly; + typedef typename BaseClass::LocalSimpleRef LocalSimpleRef; + +public: + nsAutoRef() + { + } + + // Explicit construction is required so as not to risk unintentionally + // releasing the resource associated with a raw ref. + explicit nsAutoRef(RawRefOnly aRefToRelease) + : BaseClass(aRefToRelease) + { + } + + // Construction from a nsReturnRef<T> function return value, which expects + // to give up ownership, transfers ownership. + // (nsReturnRef<T> is converted to const nsReturningRef<T>.) + explicit nsAutoRef(const nsReturningRef<T>& aReturning) + : BaseClass(aReturning) + { + } + + // The only assignment operator provided is for transferring from an + // nsReturnRef smart reference, which expects to pass its ownership to + // another object. + // + // With raw references and other smart references, the type of the lhs and + // its taking and releasing nature is often not obvious from an assignment + // statement. Assignment from a raw ptr especially is not normally + // expected to release the reference. + // + // Use |steal| for taking ownership from other smart refs. + // + // For raw references, use |own| to indicate intention to have the + // resource released. + // + // Or, to create another owner of the same reference, use an nsCountedRef. + + ThisClass& operator=(const nsReturningRef<T>& aReturning) + { + BaseClass::steal(aReturning.mReturnRef); + return *this; + } + + // Conversion to a raw reference allow the nsAutoRef<T> to often be used + // like a raw reference. + operator typename SimpleRef::RawRef() const + { + return this->get(); + } + + // Transfer ownership from another smart reference. + void steal(ThisClass& aOtherRef) + { + BaseClass::steal(aOtherRef); + } + + // Assume ownership of a raw ref. + // + // |own| has similar function to |steal|, and is useful for receiving + // ownership from a return value of a function. It is named differently + // because |own| requires more care to ensure that the function intends to + // give away ownership, and so that |steal| can be safely used, knowing + // that it won't steal ownership from any methods returning raw ptrs to + // data owned by a foreign object. + void own(RawRefOnly aRefToRelease) + { + BaseClass::own(aRefToRelease); + } + + // Exchange ownership with |aOther| + void swap(ThisClass& aOther) + { + LocalSimpleRef temp; + temp.SimpleRef::operator=(*this); + SimpleRef::operator=(aOther); + aOther.SimpleRef::operator=(temp); + } + + // Release the reference now. + void reset() + { + this->SafeRelease(); + LocalSimpleRef empty; + SimpleRef::operator=(empty); + } + + // Pass out the reference for a function return values. + nsReturnRef<T> out() + { + return nsReturnRef<T>(this->disown()); + } + + // operator->() and disown() are provided by nsAutoRefBase<T>. + // The default nsSimpleRef<T> provides get(). + +private: + // No copy constructor + explicit nsAutoRef(ThisClass& aRefToSteal); +}; + +/** + * template <class T> class nsCountedRef + * + * A class that creates (adds) a new reference to a resource on construction + * or assignment and releases on destruction. + * + * This class is similar to nsAutoRef<T> and inherits its methods, but also + * provides copy construction and assignment operators that enable more than + * one concurrent reference to the same resource. + * + * Specialize |nsAutoRefTraits<T>| or |nsSimpleRef<T>| to use this. This + * class assumes that the resource itself counts references and so can only be + * used when |T| represents a reference-counting resource. + */ + +template <class T> +class nsCountedRef : public nsAutoRef<T> +{ +protected: + typedef nsCountedRef<T> ThisClass; + typedef nsAutoRef<T> BaseClass; + typedef nsSimpleRef<T> SimpleRef; + typedef typename BaseClass::RawRef RawRef; + +public: + nsCountedRef() + { + } + + // Construction and assignment from a another nsCountedRef + // or a raw ref copies and increments the ref count. + nsCountedRef(const ThisClass& aRefToCopy) + { + SimpleRef::operator=(aRefToCopy); + SafeAddRef(); + } + ThisClass& operator=(const ThisClass& aRefToCopy) + { + if (this == &aRefToCopy) { + return *this; + } + + this->SafeRelease(); + SimpleRef::operator=(aRefToCopy); + SafeAddRef(); + return *this; + } + + // Implicit conversion from another smart ref argument (to a raw ref) is + // accepted here because construction and assignment safely creates a new + // reference without interfering with the reference to copy. + explicit nsCountedRef(RawRef aRefToCopy) + : BaseClass(aRefToCopy) + { + SafeAddRef(); + } + ThisClass& operator=(RawRef aRefToCopy) + { + this->own(aRefToCopy); + SafeAddRef(); + return *this; + } + + // Construction and assignment from an nsReturnRef function return value, + // which expects to give up ownership, transfers ownership. + explicit nsCountedRef(const nsReturningRef<T>& aReturning) + : BaseClass(aReturning) + { + } + ThisClass& operator=(const nsReturningRef<T>& aReturning) + { + BaseClass::operator=(aReturning); + return *this; + } + +protected: + // Increase the reference count if there is a resource. + void SafeAddRef() + { + if (this->HaveResource()) { + this->AddRef(this->get()); + } + } +}; + +/** + * template <class T> class nsReturnRef + * + * A type for function return values that hold a reference to a resource that + * must be released. See also |nsAutoRef<T>::out()|. + */ + +template <class T> +class nsReturnRef : public nsAutoRefBase<T> +{ +protected: + typedef nsAutoRefBase<T> BaseClass; + typedef typename BaseClass::RawRefOnly RawRefOnly; + +public: + // For constructing a return value with no resource + nsReturnRef() + { + } + + // For returning a smart reference from a raw reference that must be + // released. Explicit construction is required so as not to risk + // unintentionally releasing the resource associated with a raw ref. + MOZ_IMPLICIT nsReturnRef(RawRefOnly aRefToRelease) + : BaseClass(aRefToRelease) + { + } + + // Copy construction transfers ownership + nsReturnRef(nsReturnRef<T>& aRefToSteal) + : BaseClass(aRefToSteal) + { + } + + MOZ_IMPLICIT nsReturnRef(const nsReturningRef<T>& aReturning) + : BaseClass(aReturning) + { + } + + // Conversion to a temporary (const) object referring to this object so + // that the reference may be passed from a function return value + // (temporary) to another smart reference. There is no need to use this + // explicitly. Simply assign a nsReturnRef<T> function return value to a + // smart reference. + operator nsReturningRef<T>() + { + return nsReturningRef<T>(*this); + } + + // No conversion to RawRef operator is provided on nsReturnRef, to ensure + // that the return value is not carelessly assigned to a raw ptr (and the + // resource then released). If passing to a function that takes a raw + // ptr, use get or disown as appropriate. +}; + +/** + * template <class T> class nsReturningRef + * + * A class to allow ownership to be transferred from nsReturnRef function + * return values. + * + * It should not be necessary for clients to reference this + * class directly. Simply pass an nsReturnRef<T> to a parameter taking an + * |nsReturningRef<T>|. + * + * The conversion operator on nsReturnRef constructs a temporary wrapper of + * class nsReturningRef<T> around a non-const reference to the nsReturnRef. + * The wrapper can then be passed as an rvalue parameter. + */ + +template <class T> +class nsReturningRef +{ +private: + friend class nsReturnRef<T>; + + explicit nsReturningRef(nsReturnRef<T>& aReturnRef) + : mReturnRef(aReturnRef) + { + } +public: + nsReturnRef<T>& mReturnRef; +}; + +/** + * template <class T> class nsAutoRefTraits + * + * A class describing traits of references managed by the default + * |nsSimpleRef<T>| implementation and thus |nsAutoRef<T>| and |nsCountedRef|. + * The default |nsSimpleRef<T> is suitable for resources with handles that + * have a void value. (If there is no such void value for a handle, + * specialize |nsSimpleRef<T>|.) + * + * Specializations must be provided for each class |T| according to the + * following pattern: + * + * // The template parameter |T| should be a class such that the set of fields + * // in class nsAutoRefTraits<T> is unique for class |T|. Usually the + * // resource object class is sufficient. For handles that are simple + * // integral typedefs, a new unique possibly-incomplete class may need to be + * // declared. + * + * template <> + * class nsAutoRefTraits<T> + * { + * // Specializations must provide a typedef for RawRef, describing the + * // type of the handle to the resource. + * typedef <handle-type> RawRef; + * + * // Specializations should define Void(), a function returning a value + * // suitable for a handle that does not have an associated resource. + * // + * // The return type must be a suitable as the parameter to a RawRef + * // constructor and operator==. + * // + * // If this method is not accessible then some limited nsAutoRef + * // functionality will still be available, but the default constructor, + * // |reset|, and most transfer of ownership methods will not be available. + * static <return-type> Void(); + * + * // Specializations must define Release() to properly finalize the + * // handle to a non-void custom-deleted or reference-counted resource. + * static void Release(RawRef aRawRef); + * + * // For reference-counted resources, if |nsCountedRef<T>| is to be used, + * // specializations must define AddRef to increment the reference count + * // held by a non-void handle. + * // (AddRef() is not necessary for |nsAutoRef<T>|.) + * static void AddRef(RawRef aRawRef); + * }; + * + * See nsPointerRefTraits for example specializations for simple pointer + * references. See nsAutoRef for an example specialization for a non-pointer + * reference. + */ + +template <class T> class nsAutoRefTraits; + +/** + * template <class T> class nsPointerRefTraits + * + * A convenience class useful as a base class for specializations of + * |nsAutoRefTraits<T>| where the handle to the resource is a pointer to |T|. + * By inheriting from this class, definitions of only Release(RawRef) and + * possibly AddRef(RawRef) need to be added. + * + * Examples of use: + * + * template <> + * class nsAutoRefTraits<PRFileDesc> : public nsPointerRefTraits<PRFileDesc> + * { + * public: + * static void Release(PRFileDesc *ptr) { PR_Close(ptr); } + * }; + * + * template <> + * class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern> + * { + * public: + * static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); } + * static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); } + * }; + */ + +template <class T> +class nsPointerRefTraits +{ +public: + // The handle is a pointer to T. + typedef T* RawRef; + // A nullptr does not have a resource. + static RawRef Void() + { + return nullptr; + } +}; + +/** + * template <class T> class nsSimpleRef + * + * Constructs a non-smart reference, and provides methods to test whether + * there is an associated resource and (if so) get its raw handle. + * + * A default implementation is suitable for resources with handles that have a + * void value. This is not intended for direct use but used by |nsAutoRef<T>| + * and thus |nsCountedRef<T>|. + * + * Specialize this class if there is no particular void value for the resource + * handle. A specialized implementation must also provide Release(RawRef), + * and, if |nsCountedRef<T>| is required, AddRef(RawRef), as described in + * nsAutoRefTraits<T>. + */ + +template <class T> +class nsSimpleRef : protected nsAutoRefTraits<T> +{ +protected: + // The default implementation uses nsAutoRefTrait<T>. + // Specializations need not define this typedef. + typedef nsAutoRefTraits<T> Traits; + // The type of the handle to the resource. + // A specialization must provide a typedef for RawRef. + typedef typename Traits::RawRef RawRef; + + // Construct with no resource. + // + // If this constructor is not accessible then some limited nsAutoRef + // functionality will still be available, but the default constructor, + // |reset|, and most transfer of ownership methods will not be available. + nsSimpleRef() + : mRawRef(Traits::Void()) + { + } + // Construct with a handle to a resource. + // A specialization must provide this. + explicit nsSimpleRef(RawRef aRawRef) + : mRawRef(aRawRef) + { + } + + // Test whether there is an associated resource. A specialization must + // provide this. The function is permitted to always return true if the + // default constructor is not accessible, or if Release (and AddRef) can + // deal with void handles. + bool HaveResource() const + { + return mRawRef != Traits::Void(); + } + +public: + // A specialization must provide get() or loose some functionality. This + // is inherited by derived classes and the specialization may choose + // whether it is public or protected. + RawRef get() const + { + return mRawRef; + } + +private: + RawRef mRawRef; +}; + + +/** + * template <class T> class nsAutoRefBase + * + * Internal base class for |nsAutoRef<T>| and |nsReturnRef<T>|. + * Adds release on destruction to a |nsSimpleRef<T>|. + */ + +template <class T> +class nsAutoRefBase : public nsSimpleRef<T> +{ +protected: + typedef nsAutoRefBase<T> ThisClass; + typedef nsSimpleRef<T> SimpleRef; + typedef typename SimpleRef::RawRef RawRef; + + nsAutoRefBase() + { + } + + // A type for parameters that should be passed a raw ref but should not + // accept implicit conversions (from another smart ref). (The only + // conversion to this type is from a raw ref so only raw refs will be + // accepted.) + class RawRefOnly + { + public: + MOZ_IMPLICIT RawRefOnly(RawRef aRawRef) + : mRawRef(aRawRef) + { + } + operator RawRef() const + { + return mRawRef; + } + private: + RawRef mRawRef; + }; + + // Construction from a raw ref assumes ownership + explicit nsAutoRefBase(RawRefOnly aRefToRelease) + : SimpleRef(aRefToRelease) + { + } + + // Constructors that steal ownership + explicit nsAutoRefBase(ThisClass& aRefToSteal) + : SimpleRef(aRefToSteal.disown()) + { + } + explicit nsAutoRefBase(const nsReturningRef<T>& aReturning) + : SimpleRef(aReturning.mReturnRef.disown()) + { + } + + ~nsAutoRefBase() + { + SafeRelease(); + } + + // An internal class providing access to protected nsSimpleRef<T> + // constructors for construction of temporary simple references (that are + // not ThisClass). + class LocalSimpleRef : public SimpleRef + { + public: + LocalSimpleRef() + { + } + explicit LocalSimpleRef(RawRef aRawRef) + : SimpleRef(aRawRef) + { + } + }; + +private: + ThisClass& operator=(const ThisClass& aSmartRef) = delete; + +public: + RawRef operator->() const + { + return this->get(); + } + + // Transfer ownership to a raw reference. + // + // THE CALLER MUST ENSURE THAT THE REFERENCE IS EXPLICITLY RELEASED. + // + // Is this really what you want to use? Using this removes any guarantee + // of release. Use nsAutoRef<T>::out() for return values, or an + // nsAutoRef<T> modifiable lvalue for an out parameter. Use disown() when + // the reference must be stored in a POD type object, such as may be + // preferred for a namespace-scope object with static storage duration, + // for example. + RawRef disown() + { + RawRef temp = this->get(); + LocalSimpleRef empty; + SimpleRef::operator=(empty); + return temp; + } + +protected: + // steal and own are protected because they make no sense on nsReturnRef, + // but steal is implemented on this class for access to aOtherRef.disown() + // when aOtherRef is an nsReturnRef; + + // Transfer ownership from another smart reference. + void steal(ThisClass& aOtherRef) + { + own(aOtherRef.disown()); + } + // Assume ownership of a raw ref. + void own(RawRefOnly aRefToRelease) + { + SafeRelease(); + LocalSimpleRef ref(aRefToRelease); + SimpleRef::operator=(ref); + } + + // Release a resource if there is one. + void SafeRelease() + { + if (this->HaveResource()) { + this->Release(this->get()); + } + } +}; + +#endif // !defined(nsAutoRef_h_) diff --git a/onlineupdate/source/update/inc/nsWindowsHelpers.h b/onlineupdate/source/update/inc/nsWindowsHelpers.h new file mode 100644 index 000000000000..c9284292691a --- /dev/null +++ b/onlineupdate/source/update/inc/nsWindowsHelpers.h @@ -0,0 +1,159 @@ +/* -*- 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 nsWindowsHelpers_h +#define nsWindowsHelpers_h + +#include <windows.h> +#include "nsAutoRef.h" + +// ---------------------------------------------------------------------------- +// Critical Section helper class +// ---------------------------------------------------------------------------- + +class AutoCriticalSection +{ +public: + AutoCriticalSection(LPCRITICAL_SECTION aSection) + : mSection(aSection) + { + ::EnterCriticalSection(mSection); + } + ~AutoCriticalSection() + { + ::LeaveCriticalSection(mSection); + } +private: + LPCRITICAL_SECTION mSection; +}; + +template<> +class nsAutoRefTraits<HKEY> +{ +public: + typedef HKEY RawRef; + static HKEY Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + RegCloseKey(aFD); + } + } +}; + +template<> +class nsAutoRefTraits<SC_HANDLE> +{ +public: + typedef SC_HANDLE RawRef; + static SC_HANDLE Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + CloseServiceHandle(aFD); + } + } +}; + +template<> +class nsSimpleRef<HANDLE> +{ +protected: + typedef HANDLE RawRef; + + nsSimpleRef() : mRawRef(nullptr) + { + } + + nsSimpleRef(RawRef aRawRef) : mRawRef(aRawRef) + { + } + + bool HaveResource() const + { + return mRawRef && mRawRef != INVALID_HANDLE_VALUE; + } + +public: + RawRef get() const + { + return mRawRef; + } + + static void Release(RawRef aRawRef) + { + if (aRawRef && aRawRef != INVALID_HANDLE_VALUE) { + CloseHandle(aRawRef); + } + } + RawRef mRawRef; +}; + + +template<> +class nsAutoRefTraits<HMODULE> +{ +public: + typedef HMODULE RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + FreeLibrary(aFD); + } + } +}; + +typedef nsAutoRef<HKEY> nsAutoRegKey; +typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle; +typedef nsAutoRef<HANDLE> nsAutoHandle; +typedef nsAutoRef<HMODULE> nsModuleHandle; + +namespace { + +HMODULE inline +LoadLibrarySystem32(LPCWSTR aModule) +{ + WCHAR systemPath[MAX_PATH + 1] = { L'\0' }; + + // If GetSystemPath fails we accept that we'll load the DLLs from the + // normal search path. + GetSystemDirectoryW(systemPath, MAX_PATH + 1); + size_t systemDirLen = wcslen(systemPath); + + // Make the system directory path terminate with a slash + if (systemDirLen && systemPath[systemDirLen - 1] != L'\\') { + systemPath[systemDirLen] = L'\\'; + ++systemDirLen; + // No need to re-nullptr terminate + } + + size_t fileLen = wcslen(aModule); + wcsncpy(systemPath + systemDirLen, aModule, + MAX_PATH - systemDirLen); + if (systemDirLen + fileLen <= MAX_PATH) { + systemPath[systemDirLen + fileLen] = L'\0'; + } else { + systemPath[MAX_PATH] = L'\0'; + } + return LoadLibraryW(systemPath); +} + +} + +#endif |