mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
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:
parent
3ce36bee8a
commit
9a3dd41f50
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user