diff --git a/mfbt/UniquePtr.h b/mfbt/UniquePtr.h index 89ecf61e68ca..12bd0b0fe07f 100644 --- a/mfbt/UniquePtr.h +++ b/mfbt/UniquePtr.h @@ -569,6 +569,99 @@ operator!=(NullptrT n, const UniquePtr& x) // No operator<, operator>, operator<=, operator>= for now because simplicity. +namespace detail { + +template +struct UniqueSelector +{ + typedef UniquePtr SingleObject; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr UnknownBound; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr KnownBound; +}; + +} // namespace detail + +// We don't have variadic template support everywhere, so just hard-code arities +// 0-4 for now. If you need more arguments, feel free to add the extra +// overloads. +// +// Beware! Due to lack of true nullptr support in gcc 4.4 and 4.5, passing +// literal nullptr to MakeUnique will not work on some platforms. See Move.h +// for more details. + +template +typename detail::UniqueSelector::SingleObject +MakeUnique() +{ + return UniquePtr(new T()); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1) +{ + return UniquePtr(new T(Forward(a1))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2) +{ + return UniquePtr(new T(Forward(a1), Forward(a2))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2, A3&& a3) +{ + return UniquePtr(new T(Forward(a1), Forward(a2), Forward(a3))); +} + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4) +{ + return UniquePtr(new T(Forward(a1), Forward(a2), Forward(a3), Forward(a4))); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUnique(decltype(sizeof(int)) n) +{ + typedef typename RemoveExtent::Type ArrayType; + return UniquePtr(new ArrayType[n]()); +} + +template +typename detail::UniqueSelector::KnownBound +MakeUnique() MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2, A3&& a3) MOZ_DELETE; + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(A1&& a1, A2&& a2, A3&& a3, A4&& a4) MOZ_DELETE; + } // namespace mozilla #endif /* mozilla_UniquePtr_h */ diff --git a/mfbt/tests/TestUniquePtr.cpp b/mfbt/tests/TestUniquePtr.cpp index 796ece045cb5..e6e889f0e981 100644 --- a/mfbt/tests/TestUniquePtr.cpp +++ b/mfbt/tests/TestUniquePtr.cpp @@ -16,6 +16,7 @@ using mozilla::DefaultDelete; using mozilla::IsNullPointer; using mozilla::IsSame; +using mozilla::MakeUnique; using mozilla::Swap; using mozilla::UniquePtr; using mozilla::Vector; @@ -543,6 +544,48 @@ TestArray() return true; } +struct Q +{ + Q() {} + Q(const Q& q) {} + + Q(Q& q, char c) {} + + template + Q(Q q, T&& t, int i) + {} + + Q(int i, long j, double k, void* l) {} +}; + +static int randomInt() { return 4; } + +static bool +TestMakeUnique() +{ + UniquePtr a1(MakeUnique()); + UniquePtr a2(MakeUnique(4)); + + // no args, easy + UniquePtr q0(MakeUnique()); + + // temporary bound to const lval ref + UniquePtr q1(MakeUnique(Q())); + + // passing through a non-const lval ref + UniquePtr q2(MakeUnique(*q1, 'c')); + + // pass by copying, forward a temporary, pass by value + UniquePtr q3(MakeUnique(Q(), UniquePtr(), randomInt())); + + // various type mismatching to test "fuzzy" forwarding + UniquePtr q4(MakeUnique('s', 66LL, 3.141592654, &q3)); + + UniquePtr c1(MakeUnique(5)); + + return true; +} + int main() { @@ -558,4 +601,6 @@ main() return 1; if (!TestArray()) return 1; + if (!TestMakeUnique()) + return 1; }