Backed out 5 changesets (bug 1689967, bug 1685677) for bustage on TestFlatten.cpp. CLOSED TREE

Backed out changeset 129b45a961fb (bug 1689967)
Backed out changeset d354b3d5312c (bug 1685677)
Backed out changeset 3c1b1f51f19c (bug 1685677)
Backed out changeset cc4f20677a7e (bug 1685677)
Backed out changeset bcbba85964cb (bug 1685677)
This commit is contained in:
Csoregi Natalia 2021-02-02 17:05:23 +02:00
Родитель f74165b411
Коммит 74e4cf16bf
6 изменённых файлов: 143 добавлений и 386 удалений

Просмотреть файл

@ -7,7 +7,6 @@
#include "ActorsParent.h"
// Local includes
#include "Flatten.h"
#include "InitializationTypes.h"
#include "OriginScope.h"
#include "QuotaCommon.h"
@ -951,15 +950,15 @@ class OriginInfo final {
bool mDirectoryExists;
};
class OriginInfoAccessTimeComparator {
class OriginInfoLRUComparator {
public:
bool Equals(const NotNull<RefPtr<const OriginInfo>>& a,
const NotNull<RefPtr<const OriginInfo>>& b) const {
bool Equals(const NotNull<RefPtr<OriginInfo>>& a,
const NotNull<RefPtr<OriginInfo>>& b) const {
return a->LockedAccessTime() == b->LockedAccessTime();
}
bool LessThan(const NotNull<RefPtr<const OriginInfo>>& a,
const NotNull<RefPtr<const OriginInfo>>& b) const {
bool LessThan(const NotNull<RefPtr<OriginInfo>>& a,
const NotNull<RefPtr<OriginInfo>>& b) const {
return a->LockedAccessTime() < b->LockedAccessTime();
}
};
@ -1024,11 +1023,14 @@ class GroupInfoPair {
MOZ_COUNTED_DTOR(GroupInfoPair)
private:
RefPtr<GroupInfo> LockedGetGroupInfo(PersistenceType aPersistenceType) {
already_AddRefed<GroupInfo> LockedGetGroupInfo(
PersistenceType aPersistenceType) {
AssertCurrentThreadOwnsQuotaMutex();
MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
return GetGroupInfoForPersistenceType(aPersistenceType);
RefPtr<GroupInfo> groupInfo =
GetGroupInfoForPersistenceType(aPersistenceType);
return groupInfo.forget();
}
void LockedSetGroupInfo(PersistenceType aPersistenceType,
@ -3781,8 +3783,8 @@ uint64_t QuotaManager::CollectOriginsForEviction(
static void GetInactiveOriginInfos(
const nsTArray<NotNull<RefPtr<OriginInfo>>>& aOriginInfos,
const nsTArray<NotNull<DirectoryLockImpl*>>& aLocks,
OriginInfosFlatTraversable& aInactiveOriginInfos) {
for (const auto& originInfo : aOriginInfos) {
nsTArray<NotNull<RefPtr<OriginInfo>>>& aInactiveOriginInfos) {
for (const NotNull<RefPtr<OriginInfo>>& originInfo : aOriginInfos) {
MOZ_ASSERT(originInfo->mGroupInfo->mPersistenceType !=
PERSISTENCE_TYPE_PERSISTENT);
@ -3801,8 +3803,8 @@ uint64_t QuotaManager::CollectOriginsForEviction(
if (!match) {
MOZ_ASSERT(!originInfo->mQuotaObjects.Count(),
"Inactive origin shouldn't have open files!");
aInactiveOriginInfos.InsertElementSorted(
originInfo, OriginInfoAccessTimeComparator());
aInactiveOriginInfos.InsertElementSorted(originInfo,
OriginInfoLRUComparator());
}
}
}
@ -3830,7 +3832,7 @@ uint64_t QuotaManager::CollectOriginsForEviction(
}
}
OriginInfosFlatTraversable inactiveOrigins;
nsTArray<NotNull<RefPtr<OriginInfo>>> inactiveOrigins;
// Enumerate and process inactive origins. This must be protected by the
// mutex.
@ -6437,8 +6439,8 @@ QuotaManager::EnsurePersistentOriginIsInitialized(const QuotaInfo& aQuotaInfo) {
return std::pair(std::move(directory), created);
}();
if (auto& info = mOriginInitializationInfos.GetOrInsert(aQuotaInfo.mOrigin);
!info.mPersistentOriginAttempted) {
auto& info = mOriginInitializationInfos.GetOrInsert(aQuotaInfo.mOrigin);
if (!info.mPersistentOriginAttempted) {
Telemetry::Accumulate(Telemetry::QM_FIRST_INITIALIZATION_ATTEMPT,
kPersistentOriginTelemetryKey,
static_cast<uint32_t>(res.isOk()));
@ -6547,7 +6549,7 @@ nsresult QuotaManager::EnsureTemporaryStorageIsInitialized() {
mTemporaryStorageLimit = GetTemporaryStorageLimit(
/* aAvailableSpaceBytes */ diskSpaceAvailable + mTemporaryStorageUsage);
CleanupTemporaryStorage();
CheckTemporaryStorageLimits();
return NS_OK;
}
@ -7038,8 +7040,8 @@ void QuotaManager::LockedRemoveQuotaForOrigin(
MOZ_ASSERT(pair);
if (RefPtr<GroupInfo> groupInfo =
pair->LockedGetGroupInfo(aPersistenceType)) {
RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
if (groupInfo) {
groupInfo->LockedRemoveOriginInfo(aGroupAndOrigin.mOrigin);
if (!groupInfo->LockedHasOriginInfos()) {
@ -7089,186 +7091,150 @@ already_AddRefed<OriginInfo> QuotaManager::LockedGetOriginInfo(
return nullptr;
}
template <typename Iterator>
void QuotaManager::MaybeInsertNonPersistedOriginInfos(
Iterator aDest, const RefPtr<GroupInfo>& aTemporaryGroupInfo,
const RefPtr<GroupInfo>& aDefaultGroupInfo) {
const auto copy = [&aDest](const GroupInfo& groupInfo) {
std::copy_if(
groupInfo.mOriginInfos.cbegin(), groupInfo.mOriginInfos.cend(), aDest,
[](const auto& originInfo) { return !originInfo->LockedPersisted(); });
};
void QuotaManager::CheckTemporaryStorageLimits() {
AssertIsOnIOThread();
if (aTemporaryGroupInfo) {
MOZ_ASSERT(PERSISTENCE_TYPE_TEMPORARY ==
aTemporaryGroupInfo->GetPersistenceType());
const auto doomedOrigins = [this] {
const auto doomedOriginInfos = [this] {
nsTArray<NotNull<RefPtr<OriginInfo>>> doomedOriginInfos;
MutexAutoLock lock(mQuotaMutex);
copy(*aTemporaryGroupInfo);
}
if (aDefaultGroupInfo) {
MOZ_ASSERT(PERSISTENCE_TYPE_DEFAULT ==
aDefaultGroupInfo->GetPersistenceType());
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
copy(*aDefaultGroupInfo);
}
}
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
template <typename Collect, typename Pred>
QuotaManager::OriginInfosFlatTraversable
QuotaManager::CollectLRUOriginInfosUntil(Collect&& aCollect, Pred&& aPred) {
OriginInfosFlatTraversable originInfos;
uint64_t groupUsage = 0;
std::forward<Collect>(aCollect)(MakeBackInserter(originInfos));
RefPtr<GroupInfo> temporaryGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (temporaryGroupInfo) {
groupUsage += temporaryGroupInfo->mUsage;
}
originInfos.Sort(OriginInfoAccessTimeComparator());
RefPtr<GroupInfo> defaultGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (defaultGroupInfo) {
groupUsage += defaultGroupInfo->mUsage;
}
const auto foundIt = std::find_if(originInfos.cbegin(), originInfos.cend(),
std::forward<Pred>(aPred));
if (groupUsage > 0) {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
originInfos.TruncateLength(foundIt - originInfos.cbegin());
if (groupUsage > quotaManager->GetGroupLimit()) {
nsTArray<NotNull<RefPtr<OriginInfo>>> originInfos;
if (temporaryGroupInfo) {
originInfos.AppendElements(temporaryGroupInfo->mOriginInfos);
}
if (defaultGroupInfo) {
originInfos.AppendElements(defaultGroupInfo->mOriginInfos);
}
originInfos.Sort(OriginInfoLRUComparator());
return originInfos;
}
for (uint32_t i = 0; i < originInfos.Length(); i++) {
const NotNull<RefPtr<OriginInfo>>& originInfo = originInfos[i];
if (originInfo->LockedPersisted()) {
continue;
}
QuotaManager::OriginInfosNestedTraversable
QuotaManager::GetOriginInfosExceedingGroupLimit() const {
MutexAutoLock lock(mQuotaMutex);
OriginInfosNestedTraversable originInfos;
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
uint64_t groupUsage = 0;
const RefPtr<GroupInfo> temporaryGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (temporaryGroupInfo) {
groupUsage += temporaryGroupInfo->mUsage;
}
const RefPtr<GroupInfo> defaultGroupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (defaultGroupInfo) {
groupUsage += defaultGroupInfo->mUsage;
}
if (groupUsage > 0) {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_ASSERT(quotaManager, "Shouldn't be null!");
if (groupUsage > quotaManager->GetGroupLimit()) {
originInfos.AppendElement(CollectLRUOriginInfosUntil(
[&temporaryGroupInfo, &defaultGroupInfo](auto inserter) {
MaybeInsertNonPersistedOriginInfos(
std::move(inserter), temporaryGroupInfo, defaultGroupInfo);
},
[&groupUsage, quotaManager](const auto& originInfo) {
doomedOriginInfos.AppendElement(originInfo);
groupUsage -= originInfo->LockedUsage();
return groupUsage <= quotaManager->GetGroupLimit();
}));
if (groupUsage <= quotaManager->GetGroupLimit()) {
break;
}
}
}
}
}
}
}
return originInfos;
}
uint64_t usage = std::accumulate(
doomedOriginInfos.cbegin(), doomedOriginInfos.cend(), uint64_t(0),
[](uint64_t oldValue, const auto& originInfo) {
return oldValue + originInfo->LockedUsage();
});
QuotaManager::OriginInfosNestedTraversable
QuotaManager::GetOriginInfosExceedingGlobalLimit() const {
MutexAutoLock lock(mQuotaMutex);
if (mTemporaryStorageUsage - usage > mTemporaryStorageLimit) {
nsTArray<NotNull<RefPtr<OriginInfo>>> originInfos;
QuotaManager::OriginInfosNestedTraversable res;
res.AppendElement(CollectLRUOriginInfosUntil(
// XXX The lambda only needs to capture this, but due to Bug 1421435 it
// can't.
[&](auto inserter) {
for (const auto& entry : mGroupInfoPairs) {
const auto& pair = entry.GetData();
MOZ_ASSERT(!entry.GetKey().IsEmpty());
MOZ_ASSERT(pair);
MaybeInsertNonPersistedOriginInfos(
inserter, pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY),
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT));
}
},
[temporaryStorageUsage = mTemporaryStorageUsage,
temporaryStorageLimit = mTemporaryStorageLimit,
doomedUsage = uint64_t{0}](const auto& originInfo) mutable {
if (temporaryStorageUsage - doomedUsage <= temporaryStorageLimit) {
return true;
RefPtr<GroupInfo> groupInfo =
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
}
groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (groupInfo) {
originInfos.AppendElements(groupInfo->mOriginInfos);
}
}
doomedUsage += originInfo->LockedUsage();
return false;
}));
originInfos.RemoveElementsBy(
[&doomedOriginInfos](const auto& originInfo) {
return doomedOriginInfos.Contains(originInfo) ||
originInfo->LockedPersisted();
});
return res;
}
originInfos.Sort(OriginInfoLRUComparator());
void QuotaManager::ClearOrigins(
const OriginInfosNestedTraversable& aDoomedOriginInfos) {
AssertIsOnIOThread();
for (uint32_t i = 0; i < originInfos.Length(); i++) {
if (mTemporaryStorageUsage - usage <= mTemporaryStorageLimit) {
originInfos.TruncateLength(i);
break;
}
// XXX Does this need to be done a) in order and/or b) sequentially?
for (const auto& doomedOriginInfo :
Flatten<OriginInfosFlatTraversable::elem_type>(aDoomedOriginInfos)) {
usage += originInfos[i]->LockedUsage();
}
doomedOriginInfos.AppendElements(originInfos);
}
return doomedOriginInfos;
}();
for (const auto& doomedOriginInfo : doomedOriginInfos) {
#ifdef DEBUG
{
MutexAutoLock lock(mQuotaMutex);
MOZ_ASSERT(!doomedOriginInfo->LockedPersisted());
}
{
MutexAutoLock lock(mQuotaMutex);
MOZ_ASSERT(!doomedOriginInfo->LockedPersisted());
}
#endif
DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
doomedOriginInfo->mOrigin);
}
struct OriginParams {
nsCString mOrigin;
PersistenceType mPersistenceType;
};
nsTArray<OriginParams> clearedOrigins;
{
MutexAutoLock lock(mQuotaMutex);
for (const auto& doomedOriginInfo :
Flatten<OriginInfosFlatTraversable::elem_type>(aDoomedOriginInfos)) {
// LockedRemoveQuotaForOrigin might remove the group info;
// OriginInfo::mGroupInfo is only a raw pointer, so we need to store the
// information for calling OriginClearCompleted below in a separate array.
clearedOrigins.AppendElement(
OriginParams{doomedOriginInfo->mOrigin,
doomedOriginInfo->mGroupInfo->mPersistenceType});
LockedRemoveQuotaForOrigin(
doomedOriginInfo->mGroupInfo->mPersistenceType,
{doomedOriginInfo->mGroupInfo->mGroup, doomedOriginInfo->mOrigin});
DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
doomedOriginInfo->mOrigin);
}
}
for (const auto& clearedOrigin : clearedOrigins) {
OriginClearCompleted(clearedOrigin.mPersistenceType, clearedOrigin.mOrigin,
nsTArray<OriginParams> doomedOrigins;
{
MutexAutoLock lock(mQuotaMutex);
for (const auto& doomedOriginInfo : doomedOriginInfos) {
PersistenceType persistenceType =
doomedOriginInfo->mGroupInfo->mPersistenceType;
const GroupAndOrigin groupAndOrigin = {
doomedOriginInfo->mGroupInfo->mGroup, doomedOriginInfo->mOrigin};
LockedRemoveQuotaForOrigin(persistenceType, groupAndOrigin);
doomedOrigins.EmplaceBack(
OriginParams(persistenceType, groupAndOrigin.mOrigin));
}
}
return doomedOrigins;
}();
for (const OriginParams& doomedOrigin : doomedOrigins) {
OriginClearCompleted(doomedOrigin.mPersistenceType, doomedOrigin.mOrigin,
Nullable<Client::Type>());
}
}
void QuotaManager::CleanupTemporaryStorage() {
AssertIsOnIOThread();
// Evicting origins that exceed their group limit also affects the global
// temporary storage usage, so these steps have to be taken sequentially.
// Combining them doesn't seem worth the added complexity.
ClearOrigins(GetOriginInfosExceedingGroupLimit());
ClearOrigins(GetOriginInfosExceedingGlobalLimit());
if (mTemporaryStorageUsage > mTemporaryStorageLimit) {
// If disk space is still low after origin clear, notify storage pressure.
@ -7343,8 +7309,8 @@ bool QuotaManager::IsSanitizedOriginValid(const nsACString& aSanitizedOrigin) {
int64_t QuotaManager::GenerateDirectoryLockId() {
const int64_t directorylockId = mNextDirectoryLockId;
if (CheckedInt64 result = CheckedInt64(mNextDirectoryLockId) + 1;
result.isValid()) {
CheckedInt64 result = CheckedInt64(mNextDirectoryLockId) + 1;
if (result.isValid()) {
mNextDirectoryLockId = result.value();
} else {
NS_WARNING("Quota manager has run out of ids for directory locks!");

Просмотреть файл

@ -1,118 +0,0 @@
/* -*- 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 DOM_QUOTA_FLATTEN_H_
#define DOM_QUOTA_FLATTEN_H_
#include <iterator>
#include <type_traits>
#include <utility>
// XXX This should be moved to MFBT.
namespace mozilla::dom::quota {
namespace detail {
using std::begin;
using std::end;
template <typename T, typename NestedRange>
auto Flatten(NestedRange&& aRange) -> std::enable_if_t<
std::is_same_v<T, std::decay_t<typename decltype(begin(
std::declval<const NestedRange&>()))::value_type>>,
std::conditional_t<std::is_rvalue_reference_v<NestedRange>,
std::decay_t<NestedRange>, NestedRange>> {
return std::forward<NestedRange>(aRange);
}
template <typename T, typename NestedRange>
struct FlatIter {
using OuterIterator =
decltype(begin(std::declval<const std::decay_t<NestedRange>&>()));
using InnerIterator =
decltype(begin(*begin(std::declval<const std::decay_t<NestedRange>&>())));
explicit FlatIter(const NestedRange& aRange, OuterIterator aIter)
: mOuterIter{std::move(aIter)}, mOuterEnd{end(aRange)} {
InitInner();
}
const T& operator*() const { return *mInnerIter; }
FlatIter& operator++() {
++mInnerIter;
if (mInnerIter == mInnerEnd) {
++mOuterIter;
InitInner();
}
return *this;
}
bool operator!=(const FlatIter& aOther) const {
return mOuterIter != aOther.mOuterIter ||
(mOuterIter != mOuterEnd && mInnerIter != aOther.mInnerIter);
}
private:
void InitInner() {
while (mOuterIter != mOuterEnd) {
const typename OuterIterator::value_type& innerRange = *mOuterIter;
mInnerIter = begin(innerRange);
mInnerEnd = end(innerRange);
if (mInnerIter != mInnerEnd) {
break;
}
++mOuterIter;
}
}
OuterIterator mOuterIter;
const OuterIterator mOuterEnd;
InnerIterator mInnerIter;
InnerIterator mInnerEnd;
};
template <typename T, typename NestedRange>
struct FlatRange {
explicit FlatRange(NestedRange aRange) : mRange{std::move(aRange)} {}
auto begin() const {
using std::begin;
return FlatIter<T, NestedRange>{mRange, begin(mRange)};
}
auto end() const {
using std::end;
return FlatIter<T, NestedRange>{mRange, end(mRange)};
}
private:
NestedRange mRange;
};
template <typename T, typename NestedRange>
auto Flatten(NestedRange&& aRange) -> std::enable_if_t<
!std::is_same_v<
T, std::decay_t<typename decltype(begin(
std::declval<const std::decay_t<NestedRange>&>()))::value_type>>,
FlatRange<T, NestedRange>> {
return FlatRange<T, NestedRange>{std::forward<NestedRange>(aRange)};
}
} // namespace detail
template <typename T, typename NestedRange>
auto Flatten(NestedRange&& aRange) -> decltype(auto) {
return detail::Flatten<T>(std::forward<NestedRange>(aRange));
}
} // namespace mozilla::dom::quota
#endif

Просмотреть файл

@ -114,6 +114,14 @@ class NS_NO_VTABLE OpenDirectoryListener : public RefCountedObject {
virtual ~OpenDirectoryListener() = default;
};
struct OriginParams {
OriginParams(PersistenceType aPersistenceType, const nsACString& aOrigin)
: mOrigin(aOrigin), mPersistenceType(aPersistenceType) {}
nsCString mOrigin;
PersistenceType mPersistenceType;
};
class QuotaManager final : public BackgroundThreadObject {
friend class DirectoryLockImpl;
friend class GroupInfo;
@ -558,19 +566,7 @@ class QuotaManager final : public BackgroundThreadObject {
int64_t aAccessTime, bool aPersisted,
nsIFile* aDirectory);
using OriginInfosFlatTraversable =
nsTArray<NotNull<RefPtr<const OriginInfo>>>;
using OriginInfosNestedTraversable =
nsTArray<nsTArray<NotNull<RefPtr<const OriginInfo>>>>;
OriginInfosNestedTraversable GetOriginInfosExceedingGroupLimit() const;
OriginInfosNestedTraversable GetOriginInfosExceedingGlobalLimit() const;
void ClearOrigins(const OriginInfosNestedTraversable& aDoomedOriginInfos);
void CleanupTemporaryStorage();
void CheckTemporaryStorageLimits();
void DeleteFilesForOrigin(PersistenceType aPersistenceType,
const nsACString& aOrigin);
@ -594,15 +590,6 @@ class QuotaManager final : public BackgroundThreadObject {
void MaybeRecordShutdownStep(Maybe<Client::Type> aClientType,
const nsACString& aStepDescription);
template <typename Iterator>
static void MaybeInsertNonPersistedOriginInfos(
Iterator aDest, const RefPtr<GroupInfo>& aTemporaryGroupInfo,
const RefPtr<GroupInfo>& aDefaultGroupInfo);
template <typename Collect, typename Pred>
static OriginInfosFlatTraversable CollectLRUOriginInfosUntil(
Collect&& aCollect, Pred&& aPred);
// Thread on which IO is performed.
LazyInitializedOnceNotNull<const nsCOMPtr<nsIThread>> mIOThread;
@ -618,7 +605,7 @@ class QuotaManager final : public BackgroundThreadObject {
// Accesses to mQuotaManagerShutdownSteps must be protected by mQuotaMutex.
nsCString mQuotaManagerShutdownSteps;
mutable mozilla::Mutex mQuotaMutex;
mozilla::Mutex mQuotaMutex;
nsClassHashtable<nsCStringHashKey, GroupInfoPair> mGroupInfoPairs;

Просмотреть файл

@ -1,74 +0,0 @@
/* -*- 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/. */
#include "Flatten.h"
#include "gtest/gtest.h"
#include "mozilla/Unused.h"
#include "nsTArray.h"
namespace mozilla::dom::quota {
TEST(Flatten, FlatEmpty)
{
for (const auto& item : Flatten<int>(nsTArray<int>{})) {
Unused << item;
FAIL();
}
}
TEST(Flatten, NestedOuterEmpty)
{
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{})) {
Unused << item;
FAIL();
}
}
TEST(Flatten, NestedInnerEmpty)
{
for (const auto& item :
Flatten<int>(nsTArray<CopyableTArray<int>>{CopyableTArray<int>{}})) {
Unused << item;
FAIL();
}
}
TEST(Flatten, NestedInnerSingular)
{
nsTArray<int> flattened;
for (const auto& item :
Flatten<int>(nsTArray<CopyableTArray<int>>{CopyableTArray<int>{1}})) {
flattened.AppendElement(item);
}
EXPECT_EQ(nsTArray{1}, flattened);
}
TEST(Flatten, NestedInnerSingulars)
{
nsTArray<int> flattened;
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{
CopyableTArray<int>{1}, CopyableTArray<int>{2}})) {
flattened.AppendElement(item);
}
EXPECT_EQ((nsTArray{{1, 2}}), flattened);
}
TEST(Flatten, NestedInnerNonSingulars)
{
nsTArray<int> flattened;
for (const auto& item : Flatten<int>(nsTArray<CopyableTArray<int>>{
CopyableTArray<int>{1, 2}, CopyableTArray<int>{3, 4}})) {
flattened.AppendElement(item);
}
EXPECT_EQ((nsTArray{{1, 2, 3, 4}}), flattened);
}
} // namespace mozilla::dom::quota

Просмотреть файл

@ -7,7 +7,6 @@
UNIFIED_SOURCES = [
"TestCheckedUnsafePtr.cpp",
"TestEncryptedStream.cpp",
"TestFlatten.cpp",
"TestQuotaCommon.cpp",
"TestQuotaManager.cpp",
"TestUsageInfo.cpp",

Просмотреть файл

@ -77,10 +77,7 @@ struct CopyablePtr {
T mPtr;
template <typename U>
explicit CopyablePtr(U&& aPtr) : mPtr{std::forward<U>(aPtr)} {}
template <typename U>
explicit CopyablePtr(CopyablePtr<U> aPtr) : mPtr{std::move(aPtr.mPtr)} {}
explicit CopyablePtr(U aPtr) : mPtr{std::move(aPtr)} {}
};
} // namespace detail