Bug 1396723 - Simplify the trait users of DoublyLinkedList need to define. r=froydnj

While the flexibility of the current trait is nice, it's actually not
used to its fullest anywhere, and is boilerplate-y. While it is useful
to be able to put the links anywhere, there's not much usefulness from
being able to split mNext and mPrev.

So instead of a trait that allows to get/set mNext and mPrev
independently, we just use a trait that tells how to get a reference to
a DoublyLinkedListElement from a list element itself.

--HG--
extra : rebase_source : b7d502754a764670e291acdd56726948db935497
This commit is contained in:
Mike Hommey 2017-09-02 08:09:58 +09:00
parent 3ce36bee8a
commit 9a3dd41f50
4 changed files with 94 additions and 120 deletions

View File

@ -259,7 +259,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
{
friend class Breakpoint;
friend class DebuggerMemory;
friend struct JSRuntime::GlobalObjectWatchersSiblingAccess<Debugger>;
friend struct JSRuntime::GlobalObjectWatchersLinkAccess<Debugger>;
friend class SavedStacks;
friend class ScriptedOnStepHandler;
friend class ScriptedOnPopHandler;
@ -389,26 +389,17 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
// Whether to enable code coverage on the Debuggee.
bool collectCoverageInfo;
template<typename T>
struct DebuggerSiblingAccess {
static T* GetNext(T* elm) {
return elm->debuggerLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->debuggerLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->debuggerLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->debuggerLink.mPrev = prev;
template <typename T>
struct DebuggerLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->debuggerLink;
}
};
// List of all js::Breakpoints in this debugger.
using BreakpointList =
mozilla::DoublyLinkedList<js::Breakpoint,
DebuggerSiblingAccess<js::Breakpoint>>;
DebuggerLinkAccess<js::Breakpoint>>;
BreakpointList breakpoints;
// The set of GC numbers for which one or more of this Debugger's observed
@ -1595,26 +1586,17 @@ class BreakpointSite {
private:
Type type_;
template<typename T>
struct SiteSiblingAccess {
static T* GetNext(T* elm) {
return elm->siteLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->siteLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->siteLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->siteLink.mPrev = prev;
template <typename T>
struct SiteLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->siteLink;
}
};
// List of all js::Breakpoints at this instruction.
using BreakpointList =
mozilla::DoublyLinkedList<js::Breakpoint,
SiteSiblingAccess<js::Breakpoint>>;
SiteLinkAccess<js::Breakpoint>>;
BreakpointList breakpoints;
size_t enabledCount; /* number of breakpoints in the list that are enabled */

View File

@ -582,24 +582,15 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
}
template <typename T>
struct GlobalObjectWatchersSiblingAccess {
static T* GetNext(T* elm) {
return elm->onNewGlobalObjectWatchersLink.mNext;
}
static void SetNext(T* elm, T* next) {
elm->onNewGlobalObjectWatchersLink.mNext = next;
}
static T* GetPrev(T* elm) {
return elm->onNewGlobalObjectWatchersLink.mPrev;
}
static void SetPrev(T* elm, T* prev) {
elm->onNewGlobalObjectWatchersLink.mPrev = prev;
struct GlobalObjectWatchersLinkAccess {
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
return aThis->onNewGlobalObjectWatchersLink;
}
};
using WatchersList =
mozilla::DoublyLinkedList<js::Debugger,
GlobalObjectWatchersSiblingAccess<js::Debugger>>;
GlobalObjectWatchersLinkAccess<js::Debugger>>;
private:
/*
* List of all enabled Debuggers that have onNewGlobalObject handler

View File

@ -64,31 +64,15 @@
namespace mozilla {
/**
* Provides access to a next and previous element pointer named |mNext| and
* |mPrev| respectively. This class is the default and will work if the list
* element derives from DoublyLinkedListElement.
*
* Although designed to work with DoublyLinkedListElement this will als work
* with any class that defines |mNext| and |mPrev| members with the correct
* type.
*/
template <typename T>
struct DoublyLinkedSiblingAccess {
static void SetNext(T* aElm, T* aNext) { aElm->mNext = aNext; }
static T* GetNext(T* aElm) { return aElm->mNext; }
static void SetPrev(T* aElm, T* aPrev) { aElm->mPrev = aPrev; }
static T* GetPrev(T* aElm) { return aElm->mPrev; }
};
/**
* Deriving from this will allow T to be inserted into and removed from a
* DoublyLinkedList.
*/
template <typename T>
struct DoublyLinkedListElement
class DoublyLinkedListElement
{
friend struct DoublyLinkedSiblingAccess<T>;
template<typename U, typename E> friend class DoublyLinkedList;
friend T;
T* mNext;
T* mPrev;
@ -96,14 +80,36 @@ public:
DoublyLinkedListElement() : mNext(nullptr), mPrev(nullptr) {}
};
/**
* Provides access to a DoublyLinkedListElement within T.
*
* The default implementation of this template works for types that derive
* from DoublyLinkedListElement, but one can specialize for their class so
* that some appropriate DoublyLinkedListElement reference is returned.
*
* For more complex cases (multiple DoublyLinkedListElements, for example),
* one can define their own trait class and use that as ElementAccess for
* DoublyLinkedList. See TestDoublyLinkedList.cpp for an example.
*/
template <typename T>
struct GetDoublyLinkedListElement
{
static_assert(mozilla::IsBaseOf<DoublyLinkedListElement<T>, T>::value,
"You need your own specialization of GetDoublyLinkedListElement"
" or use a separate Trait.");
static DoublyLinkedListElement<T>& Get(T* aThis)
{
return *aThis;
}
};
/**
* A doubly linked list. |T| is the type of element stored in this list. |T|
* must contain or have access to unique next and previous element pointers.
* The template argument |SiblingAccess| provides code to tell this list how to
* get and set the next and previous pointers. The actual storage of next/prev
* links may reside anywhere and be encoded in any way.
* The template argument |ElementAccess| provides code to tell this list how to
* get a reference to a DoublyLinkedListElement that may reside anywhere.
*/
template <typename T, typename SiblingAccess = DoublyLinkedSiblingAccess<T>>
template <typename T, typename ElementAccess = GetDoublyLinkedListElement<T>>
class DoublyLinkedList final
{
T* mHead;
@ -118,7 +124,7 @@ class DoublyLinkedList final
}
static bool ElementNotInList(T* aElm) {
return !SiblingAccess::GetNext(aElm) && !SiblingAccess::GetPrev(aElm);
return !ElementAccess::Get(aElm).mNext && !ElementAccess::Get(aElm).mPrev;
}
public:
@ -141,7 +147,7 @@ public:
T* operator ->() const { return mCurrent; }
Iterator& operator++() {
mCurrent = SiblingAccess::GetNext(mCurrent);
mCurrent = ElementAccess::Get(mCurrent).mNext;
return *this;
}
@ -152,7 +158,7 @@ public:
}
Iterator& operator--() {
mCurrent = SiblingAccess::GetPrev(mCurrent);
mCurrent = ElementAccess::Get(mCurrent).mPrev;
return *this;
}
@ -200,10 +206,10 @@ public:
MOZ_ASSERT(ElementNotInList(aElm));
MOZ_ASSERT(isStateValid());
SiblingAccess::SetNext(aElm, mHead);
ElementAccess::Get(aElm).mNext = mHead;
if (mHead) {
MOZ_ASSERT(!SiblingAccess::GetPrev(mHead));
SiblingAccess::SetPrev(mHead, aElm);
MOZ_ASSERT(!ElementAccess::Get(mHead).mPrev);
ElementAccess::Get(mHead).mPrev = aElm;
}
mHead = aElm;
@ -221,9 +227,9 @@ public:
MOZ_ASSERT(isStateValid());
T* result = mHead;
mHead = result ? SiblingAccess::GetNext(result) : nullptr;
mHead = result ? ElementAccess::Get(result).mNext : nullptr;
if (mHead) {
SiblingAccess::SetPrev(mHead, nullptr);
ElementAccess::Get(mHead).mPrev = nullptr;
}
if (mTail == result) {
@ -231,8 +237,8 @@ public:
}
if (result) {
SiblingAccess::SetNext(result, nullptr);
SiblingAccess::SetPrev(result, nullptr);
ElementAccess::Get(result).mNext = nullptr;
ElementAccess::Get(result).mPrev = nullptr;
}
return result;
@ -247,11 +253,11 @@ public:
MOZ_ASSERT(ElementNotInList(aElm));
MOZ_ASSERT(isStateValid());
SiblingAccess::SetNext(aElm, nullptr);
SiblingAccess::SetPrev(aElm, mTail);
ElementAccess::Get(aElm).mNext = nullptr;
ElementAccess::Get(aElm).mPrev = mTail;
if (mTail) {
MOZ_ASSERT(!SiblingAccess::GetNext(mTail));
SiblingAccess::SetNext(mTail, aElm);
MOZ_ASSERT(!ElementAccess::Get(mTail).mNext);
ElementAccess::Get(mTail).mNext = aElm;
}
mTail = aElm;
@ -269,9 +275,9 @@ public:
MOZ_ASSERT(isStateValid());
T* result = mTail;
mTail = result ? SiblingAccess::GetPrev(result) : nullptr;
mTail = result ? ElementAccess::Get(result).mPrev : nullptr;
if (mTail) {
SiblingAccess::SetNext(mTail, nullptr);
ElementAccess::Get(mTail).mNext = nullptr;
}
if (mHead == result) {
@ -279,8 +285,8 @@ public:
}
if (result) {
SiblingAccess::SetNext(result, nullptr);
SiblingAccess::SetPrev(result, nullptr);
ElementAccess::Get(result).mNext = nullptr;
ElementAccess::Get(result).mPrev = nullptr;
}
return result;
@ -301,13 +307,13 @@ public:
}
T* after = &(*aIter);
T* before = SiblingAccess::GetPrev(after);
T* before = ElementAccess::Get(after).mPrev;
MOZ_ASSERT(before);
SiblingAccess::SetNext(before, aElm);
SiblingAccess::SetPrev(aElm, before);
SiblingAccess::SetNext(aElm, after);
SiblingAccess::SetPrev(after, aElm);
ElementAccess::Get(before).mNext = aElm;
ElementAccess::Get(aElm).mPrev = before;
ElementAccess::Get(aElm).mNext = after;
ElementAccess::Get(after).mPrev = aElm;
}
/**
@ -315,26 +321,26 @@ public:
*/
void remove(T* aElm) {
MOZ_ASSERT(aElm);
MOZ_ASSERT(SiblingAccess::GetNext(aElm) || SiblingAccess::GetPrev(aElm) ||
MOZ_ASSERT(ElementAccess::Get(aElm).mNext || ElementAccess::Get(aElm).mPrev ||
(aElm == mHead && aElm == mTail),
"Attempted to remove element not in this list");
if (T* prev = SiblingAccess::GetPrev(aElm)) {
SiblingAccess::SetNext(prev, SiblingAccess::GetNext(aElm));
if (T* prev = ElementAccess::Get(aElm).mPrev) {
ElementAccess::Get(prev).mNext = ElementAccess::Get(aElm).mNext;
} else {
MOZ_ASSERT(mHead == aElm);
mHead = SiblingAccess::GetNext(aElm);
mHead = ElementAccess::Get(aElm).mNext;
}
if (T* next = SiblingAccess::GetNext(aElm)) {
SiblingAccess::SetPrev(next, SiblingAccess::GetPrev(aElm));
if (T* next = ElementAccess::Get(aElm).mNext) {
ElementAccess::Get(next).mPrev = ElementAccess::Get(aElm).mPrev;
} else {
MOZ_ASSERT(mTail == aElm);
mTail = SiblingAccess::GetPrev(aElm);
mTail = ElementAccess::Get(aElm).mPrev;
}
SiblingAccess::SetNext(aElm, nullptr);
SiblingAccess::SetPrev(aElm, nullptr);
ElementAccess::Get(aElm).mNext = nullptr;
ElementAccess::Get(aElm).mPrev = nullptr;
}
/**

View File

@ -121,32 +121,27 @@ TestDoublyLinkedList()
MOZ_RELEASE_ASSERT(++list.begin() == list.find(four));
}
struct InTwoLists {
explicit InTwoLists(unsigned int aValue) : mValue(aValue) {}
DoublyLinkedListElement<InTwoLists> mListOne;
DoublyLinkedListElement<InTwoLists> mListTwo;
unsigned int mValue;
struct GetListOneTrait {
static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists *aThis) { return aThis->mListOne; }
};
};
template<>
struct mozilla::GetDoublyLinkedListElement<InTwoLists> {
static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists* aThis) { return aThis->mListTwo; }
};
static void
TestCustomAccessor()
{
struct InTwoLists {
explicit InTwoLists(unsigned int aValue) : mValue(aValue) {}
DoublyLinkedListElement<InTwoLists> mListOne;
DoublyLinkedListElement<InTwoLists> mListTwo;
unsigned int mValue;
};
struct ListOneSiblingAccess {
static void SetNext(InTwoLists* aElm, InTwoLists* aNext) { aElm->mListOne.mNext = aNext; }
static InTwoLists* GetNext(InTwoLists* aElm) { return aElm->mListOne.mNext; }
static void SetPrev(InTwoLists* aElm, InTwoLists* aPrev) { aElm->mListOne.mPrev = aPrev; }
static InTwoLists* GetPrev(InTwoLists* aElm) { return aElm->mListOne.mPrev; }
};
struct ListTwoSiblingAccess {
static void SetNext(InTwoLists* aElm, InTwoLists* aNext) { aElm->mListTwo.mNext = aNext; }
static InTwoLists* GetNext(InTwoLists* aElm) { return aElm->mListTwo.mNext; }
static void SetPrev(InTwoLists* aElm, InTwoLists* aPrev) { aElm->mListTwo.mPrev = aPrev; }
static InTwoLists* GetPrev(InTwoLists* aElm) { return aElm->mListTwo.mPrev; }
};
DoublyLinkedList<InTwoLists, ListOneSiblingAccess> listOne;
DoublyLinkedList<InTwoLists, ListTwoSiblingAccess> listTwo;
DoublyLinkedList<InTwoLists, InTwoLists::GetListOneTrait> listOne;
DoublyLinkedList<InTwoLists> listTwo;
InTwoLists one(1);
InTwoLists two(2);