Bug 1445659 - Make it possible to store RefPtr<T> in AutoCleanLinkedList. r=froydnj

Add a trait method that AutoCleanLinkedList delegates to for calling
delete on non-refcounted list elements.

--HG--
extra : histedit_source : 5e8b05f348d734d9045621d858caed946853fc02
This commit is contained in:
Andreas Farre 2018-06-13 06:25:00 +03:00
parent 1ea5273b59
commit b5730bd2b0
3 changed files with 105 additions and 2 deletions

View file

@ -99,6 +99,11 @@ struct LinkedListElementTraits
// to a list.
static void enterList(LinkedListElement<T>* elt) {}
static void exitList(LinkedListElement<T>* elt) {}
// This method is called when AutoCleanLinkedList cleans itself
// during destruction. It can be used to call delete on elements if
// the list is the sole owner.
static void cleanElement(LinkedListElement<T>* elt) { delete elt->asT(); }
};
template<typename T>
@ -111,6 +116,7 @@ struct LinkedListElementTraits<RefPtr<T>>
static void enterList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->AddRef(); }
static void exitList(LinkedListElement<RefPtr<T>>* elt) { elt->asT()->Release(); }
static void cleanElement(LinkedListElement<RefPtr<T>>* elt) {}
};
} /* namespace detail */
@ -655,6 +661,9 @@ private:
template <typename T>
class AutoCleanLinkedList : public LinkedList<T>
{
private:
using Traits = detail::LinkedListElementTraits<T>;
using ClientType = typename detail::LinkedListElementTraits<T>::ClientType;
public:
~AutoCleanLinkedList()
{
@ -669,8 +678,8 @@ public:
void clear()
{
while (T* element = this->popFirst()) {
delete element;
while (ClientType element = this->popFirst()) {
Traits::cleanElement(element);
}
}
};

View file

@ -0,0 +1,93 @@
/* -*- 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 "gtest/gtest.h"
#include "mozilla/LinkedList.h"
#include "mozilla/RefPtr.h"
using mozilla::AutoCleanLinkedList;
using mozilla::LinkedList;
using mozilla::LinkedListElement;
class PtrClass : public LinkedListElement<PtrClass>
{
public:
bool* mResult;
explicit PtrClass(bool* result)
: mResult(result)
{
EXPECT_TRUE(!*mResult);
}
virtual ~PtrClass() {
*mResult = true;
}
};
class InheritedPtrClass : public PtrClass {
public:
bool* mInheritedResult;
InheritedPtrClass(bool* result, bool* inheritedResult)
: PtrClass(result)
, mInheritedResult(inheritedResult)
{
EXPECT_TRUE(!*mInheritedResult);
}
virtual ~InheritedPtrClass() {
*mInheritedResult = true;
}
};
TEST(LinkedList, AutoCleanLinkedList)
{
bool rv1 = false;
bool rv2 = false;
bool rv3 = false;
{
AutoCleanLinkedList<PtrClass> list;
list.insertBack(new PtrClass(&rv1));
list.insertBack(new InheritedPtrClass(&rv2, &rv3));
}
EXPECT_TRUE(rv1);
EXPECT_TRUE(rv2);
EXPECT_TRUE(rv3);
}
class CountedClass final : public LinkedListElement<RefPtr<CountedClass>>
{
public:
int mCount;
void AddRef() { mCount++; }
void Release() { mCount--; }
CountedClass()
: mCount(0)
{
}
~CountedClass() { EXPECT_TRUE(mCount == 0); }
};
TEST(LinkedList, AutoCleanLinkedListRefPtr)
{
RefPtr<CountedClass> elt1 = new CountedClass;
CountedClass* elt2 = new CountedClass;
{
AutoCleanLinkedList<RefPtr<CountedClass>> list;
list.insertBack(elt1);
list.insertBack(elt2);
EXPECT_TRUE(elt1->mCount == 2);
EXPECT_TRUE(elt2->mCount == 1);
}
EXPECT_TRUE(elt1->mCount == 1);
EXPECT_TRUE(elt2->mCount == 0);
}

View file

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'TestLinkedList.cpp',
'TestSpan.cpp',
]