зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 2 changesets (bug 1396723) for !ElementAccess::Get(mHead).mPrev assertion failures
Backed out changeset 4f17343164b6 (bug 1396723) Backed out changeset b744eba9ca78 (bug 1396723) MozReview-Commit-ID: JbvM6oMxEFl
This commit is contained in:
Родитель
5921d11c6e
Коммит
bc78097d88
|
@ -259,7 +259,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
{
|
||||
friend class Breakpoint;
|
||||
friend class DebuggerMemory;
|
||||
friend struct JSRuntime::GlobalObjectWatchersLinkAccess<Debugger>;
|
||||
friend struct JSRuntime::GlobalObjectWatchersSiblingAccess<Debugger>;
|
||||
friend class SavedStacks;
|
||||
friend class ScriptedOnStepHandler;
|
||||
friend class ScriptedOnPopHandler;
|
||||
|
@ -389,17 +389,26 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
// Whether to enable code coverage on the Debuggee.
|
||||
bool collectCoverageInfo;
|
||||
|
||||
template <typename T>
|
||||
struct DebuggerLinkAccess {
|
||||
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
|
||||
return aThis->debuggerLink;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// List of all js::Breakpoints in this debugger.
|
||||
using BreakpointList =
|
||||
mozilla::DoublyLinkedList<js::Breakpoint,
|
||||
DebuggerLinkAccess<js::Breakpoint>>;
|
||||
DebuggerSiblingAccess<js::Breakpoint>>;
|
||||
BreakpointList breakpoints;
|
||||
|
||||
// The set of GC numbers for which one or more of this Debugger's observed
|
||||
|
@ -1586,17 +1595,26 @@ class BreakpointSite {
|
|||
private:
|
||||
Type type_;
|
||||
|
||||
template <typename T>
|
||||
struct SiteLinkAccess {
|
||||
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
|
||||
return aThis->siteLink;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// List of all js::Breakpoints at this instruction.
|
||||
using BreakpointList =
|
||||
mozilla::DoublyLinkedList<js::Breakpoint,
|
||||
SiteLinkAccess<js::Breakpoint>>;
|
||||
SiteSiblingAccess<js::Breakpoint>>;
|
||||
BreakpointList breakpoints;
|
||||
size_t enabledCount; /* number of breakpoints in the list that are enabled */
|
||||
|
||||
|
|
|
@ -582,15 +582,24 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
struct GlobalObjectWatchersLinkAccess {
|
||||
static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
|
||||
return aThis->onNewGlobalObjectWatchersLink;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
using WatchersList =
|
||||
mozilla::DoublyLinkedList<js::Debugger,
|
||||
GlobalObjectWatchersLinkAccess<js::Debugger>>;
|
||||
GlobalObjectWatchersSiblingAccess<js::Debugger>>;
|
||||
private:
|
||||
/*
|
||||
* List of all enabled Debuggers that have onNewGlobalObject handler
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C; tab-width: 8; c-basic-offset: 8; indent-tabs-mode: t -*- */
|
||||
/* vim:set softtabstop=8 shiftwidth=8 noet: */
|
||||
/*-
|
||||
* Copyright (C) the Mozilla Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer as
|
||||
* the first lines of this file unmodified other than the possible
|
||||
* addition of one or more copyright notices.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice(s), this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef linkedlist_h__
|
||||
#define linkedlist_h__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct LinkedList {
|
||||
LinkedList *next;
|
||||
LinkedList *prev;
|
||||
};
|
||||
|
||||
/* Convert from LinkedList* to foo*. */
|
||||
#define LinkedList_Get(e, type, prop) \
|
||||
(type*)((char*)(e) - offsetof(type, prop))
|
||||
|
||||
/* Insert |e| at the beginning of |l|. */
|
||||
void LinkedList_InsertHead(LinkedList *l, LinkedList *e)
|
||||
{
|
||||
e->next = l;
|
||||
e->prev = l->prev;
|
||||
e->next->prev = e;
|
||||
e->prev->next = e;
|
||||
}
|
||||
|
||||
void LinkedList_Remove(LinkedList *e)
|
||||
{
|
||||
e->prev->next = e->next;
|
||||
e->next->prev = e->prev;
|
||||
e->next = e;
|
||||
e->prev = e;
|
||||
}
|
||||
|
||||
bool LinkedList_IsEmpty(LinkedList *e)
|
||||
{
|
||||
return e->next == e;
|
||||
}
|
||||
|
||||
void LinkedList_Init(LinkedList *e)
|
||||
{
|
||||
e->next = e;
|
||||
e->prev = e;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -112,7 +112,6 @@
|
|||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MacroArgs.h"
|
||||
#include "mozilla/DoublyLinkedList.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#define NO_TLS
|
||||
|
@ -253,6 +252,7 @@ typedef long ssize_t;
|
|||
#endif
|
||||
|
||||
#include "mozjemalloc_types.h"
|
||||
#include "linkedlist.h"
|
||||
|
||||
/* Some tools, such as /dev/dsp wrappers, LD_PRELOAD libraries that
|
||||
* happen to override mmap() and call dlsym() from their overridden
|
||||
|
@ -627,7 +627,7 @@ struct arena_chunk_t {
|
|||
*
|
||||
* We're currently lazy and don't remove a chunk from this list when
|
||||
* all its madvised pages are recommitted. */
|
||||
mozilla::DoublyLinkedListElement<arena_chunk_t> chunks_madvised_elem;
|
||||
LinkedList chunks_madvised_elem;
|
||||
#endif
|
||||
|
||||
/* Number of dirty pages. */
|
||||
|
@ -638,17 +638,6 @@ struct arena_chunk_t {
|
|||
};
|
||||
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
|
||||
|
||||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
template<>
|
||||
struct mozilla::GetDoublyLinkedListElement<arena_chunk_t>
|
||||
{
|
||||
static mozilla::DoublyLinkedListElement<arena_chunk_t>& Get(arena_chunk_t* aThis)
|
||||
{
|
||||
return aThis->chunks_madvised_elem;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct arena_run_t {
|
||||
#if defined(MOZ_DEBUG) || defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
|
||||
uint32_t magic;
|
||||
|
@ -720,7 +709,7 @@ struct arena_t {
|
|||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
/* Head of a linked list of MADV_FREE'd-page-containing chunks this
|
||||
* arena manages. */
|
||||
mozilla::DoublyLinkedList<arena_chunk_t> chunks_madvised;
|
||||
LinkedList chunks_madvised;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -2710,7 +2699,7 @@ arena_chunk_init(arena_t *arena, arena_chunk_t *chunk, bool zeroed)
|
|||
&chunk->map[arena_chunk_header_npages]);
|
||||
|
||||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
new (&chunk->chunks_madvised_elem) mozilla::DoublyLinkedListElement<arena_chunk_t>();
|
||||
LinkedList_Init(&chunk->chunks_madvised_elem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2727,9 +2716,8 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
|
|||
}
|
||||
|
||||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
if (arena->chunks_madvised.ElementProbablyInList(arena->spare)) {
|
||||
arena->chunks_madvised.remove(arena->spare);
|
||||
}
|
||||
/* This is safe to do even if arena->spare is not in the list. */
|
||||
LinkedList_Remove(&arena->spare->chunks_madvised_elem);
|
||||
#endif
|
||||
|
||||
chunk_dealloc((void *)arena->spare, chunksize, ARENA_CHUNK);
|
||||
|
@ -2890,10 +2878,8 @@ arena_purge(arena_t *arena, bool all)
|
|||
if (madvised) {
|
||||
/* The chunk might already be in the list, but this
|
||||
* makes sure it's at the front. */
|
||||
if (arena->chunks_madvised.ElementProbablyInList(chunk)) {
|
||||
arena->chunks_madvised.remove(chunk);
|
||||
}
|
||||
arena->chunks_madvised.pushFront(chunk);
|
||||
LinkedList_Remove(&chunk->chunks_madvised_elem);
|
||||
LinkedList_InsertHead(&arena->chunks_madvised, &chunk->chunks_madvised_elem);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -4037,7 +4023,7 @@ arena_new(arena_t *arena)
|
|||
/* Initialize chunks. */
|
||||
arena_chunk_tree_dirty_new(&arena->chunks_dirty);
|
||||
#ifdef MALLOC_DOUBLE_PURGE
|
||||
new (&arena->chunks_madvised) mozilla::DoublyLinkedList<arena_chunk_t>();
|
||||
LinkedList_Init(&arena->chunks_madvised);
|
||||
#endif
|
||||
arena->spare = nullptr;
|
||||
|
||||
|
@ -5092,9 +5078,12 @@ hard_purge_arena(arena_t *arena)
|
|||
{
|
||||
malloc_spin_lock(&arena->lock);
|
||||
|
||||
while (!arena->chunks_madvised.isEmpty()) {
|
||||
arena_chunk_t *chunk = arena->chunks_madvised.popFront();
|
||||
while (!LinkedList_IsEmpty(&arena->chunks_madvised)) {
|
||||
arena_chunk_t *chunk =
|
||||
LinkedList_Get(arena->chunks_madvised.next,
|
||||
arena_chunk_t, chunks_madvised_elem);
|
||||
hard_purge_chunk(chunk);
|
||||
LinkedList_Remove(&chunk->chunks_madvised_elem);
|
||||
}
|
||||
|
||||
malloc_spin_unlock(&arena->lock);
|
||||
|
|
|
@ -64,15 +64,31 @@
|
|||
|
||||
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>
|
||||
class DoublyLinkedListElement
|
||||
struct DoublyLinkedListElement
|
||||
{
|
||||
template<typename U, typename E> friend class DoublyLinkedList;
|
||||
friend T;
|
||||
friend struct DoublyLinkedSiblingAccess<T>;
|
||||
T* mNext;
|
||||
T* mPrev;
|
||||
|
||||
|
@ -80,36 +96,14 @@ 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 |ElementAccess| provides code to tell this list how to
|
||||
* get a reference to a DoublyLinkedListElement that may reside anywhere.
|
||||
* 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.
|
||||
*/
|
||||
template <typename T, typename ElementAccess = GetDoublyLinkedListElement<T>>
|
||||
template <typename T, typename SiblingAccess = DoublyLinkedSiblingAccess<T>>
|
||||
class DoublyLinkedList final
|
||||
{
|
||||
T* mHead;
|
||||
|
@ -124,7 +118,7 @@ class DoublyLinkedList final
|
|||
}
|
||||
|
||||
static bool ElementNotInList(T* aElm) {
|
||||
return !ElementAccess::Get(aElm).mNext && !ElementAccess::Get(aElm).mPrev;
|
||||
return !SiblingAccess::GetNext(aElm) && !SiblingAccess::GetPrev(aElm);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -147,7 +141,7 @@ public:
|
|||
T* operator ->() const { return mCurrent; }
|
||||
|
||||
Iterator& operator++() {
|
||||
mCurrent = ElementAccess::Get(mCurrent).mNext;
|
||||
mCurrent = SiblingAccess::GetNext(mCurrent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -158,7 +152,7 @@ public:
|
|||
}
|
||||
|
||||
Iterator& operator--() {
|
||||
mCurrent = ElementAccess::Get(mCurrent).mPrev;
|
||||
mCurrent = SiblingAccess::GetPrev(mCurrent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -206,10 +200,10 @@ public:
|
|||
MOZ_ASSERT(ElementNotInList(aElm));
|
||||
MOZ_ASSERT(isStateValid());
|
||||
|
||||
ElementAccess::Get(aElm).mNext = mHead;
|
||||
SiblingAccess::SetNext(aElm, mHead);
|
||||
if (mHead) {
|
||||
MOZ_ASSERT(!ElementAccess::Get(mHead).mPrev);
|
||||
ElementAccess::Get(mHead).mPrev = aElm;
|
||||
MOZ_ASSERT(!SiblingAccess::GetPrev(mHead));
|
||||
SiblingAccess::SetPrev(mHead, aElm);
|
||||
}
|
||||
|
||||
mHead = aElm;
|
||||
|
@ -227,9 +221,9 @@ public:
|
|||
MOZ_ASSERT(isStateValid());
|
||||
|
||||
T* result = mHead;
|
||||
mHead = result ? ElementAccess::Get(result).mNext : nullptr;
|
||||
mHead = result ? SiblingAccess::GetNext(result) : nullptr;
|
||||
if (mHead) {
|
||||
ElementAccess::Get(mHead).mPrev = nullptr;
|
||||
SiblingAccess::SetPrev(mHead, nullptr);
|
||||
}
|
||||
|
||||
if (mTail == result) {
|
||||
|
@ -237,8 +231,8 @@ public:
|
|||
}
|
||||
|
||||
if (result) {
|
||||
ElementAccess::Get(result).mNext = nullptr;
|
||||
ElementAccess::Get(result).mPrev = nullptr;
|
||||
SiblingAccess::SetNext(result, nullptr);
|
||||
SiblingAccess::SetPrev(result, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -253,11 +247,11 @@ public:
|
|||
MOZ_ASSERT(ElementNotInList(aElm));
|
||||
MOZ_ASSERT(isStateValid());
|
||||
|
||||
ElementAccess::Get(aElm).mNext = nullptr;
|
||||
ElementAccess::Get(aElm).mPrev = mTail;
|
||||
SiblingAccess::SetNext(aElm, nullptr);
|
||||
SiblingAccess::SetPrev(aElm, mTail);
|
||||
if (mTail) {
|
||||
MOZ_ASSERT(!ElementAccess::Get(mTail).mNext);
|
||||
ElementAccess::Get(mTail).mNext = aElm;
|
||||
MOZ_ASSERT(!SiblingAccess::GetNext(mTail));
|
||||
SiblingAccess::SetNext(mTail, aElm);
|
||||
}
|
||||
|
||||
mTail = aElm;
|
||||
|
@ -275,9 +269,9 @@ public:
|
|||
MOZ_ASSERT(isStateValid());
|
||||
|
||||
T* result = mTail;
|
||||
mTail = result ? ElementAccess::Get(result).mPrev : nullptr;
|
||||
mTail = result ? SiblingAccess::GetPrev(result) : nullptr;
|
||||
if (mTail) {
|
||||
ElementAccess::Get(mTail).mNext = nullptr;
|
||||
SiblingAccess::SetNext(mTail, nullptr);
|
||||
}
|
||||
|
||||
if (mHead == result) {
|
||||
|
@ -285,8 +279,8 @@ public:
|
|||
}
|
||||
|
||||
if (result) {
|
||||
ElementAccess::Get(result).mNext = nullptr;
|
||||
ElementAccess::Get(result).mPrev = nullptr;
|
||||
SiblingAccess::SetNext(result, nullptr);
|
||||
SiblingAccess::SetPrev(result, nullptr);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -307,13 +301,13 @@ public:
|
|||
}
|
||||
|
||||
T* after = &(*aIter);
|
||||
T* before = ElementAccess::Get(after).mPrev;
|
||||
T* before = SiblingAccess::GetPrev(after);
|
||||
MOZ_ASSERT(before);
|
||||
|
||||
ElementAccess::Get(before).mNext = aElm;
|
||||
ElementAccess::Get(aElm).mPrev = before;
|
||||
ElementAccess::Get(aElm).mNext = after;
|
||||
ElementAccess::Get(after).mPrev = aElm;
|
||||
SiblingAccess::SetNext(before, aElm);
|
||||
SiblingAccess::SetPrev(aElm, before);
|
||||
SiblingAccess::SetNext(aElm, after);
|
||||
SiblingAccess::SetPrev(after, aElm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -321,26 +315,26 @@ public:
|
|||
*/
|
||||
void remove(T* aElm) {
|
||||
MOZ_ASSERT(aElm);
|
||||
MOZ_ASSERT(ElementAccess::Get(aElm).mNext || ElementAccess::Get(aElm).mPrev ||
|
||||
MOZ_ASSERT(SiblingAccess::GetNext(aElm) || SiblingAccess::GetPrev(aElm) ||
|
||||
(aElm == mHead && aElm == mTail),
|
||||
"Attempted to remove element not in this list");
|
||||
|
||||
if (T* prev = ElementAccess::Get(aElm).mPrev) {
|
||||
ElementAccess::Get(prev).mNext = ElementAccess::Get(aElm).mNext;
|
||||
if (T* prev = SiblingAccess::GetPrev(aElm)) {
|
||||
SiblingAccess::SetNext(prev, SiblingAccess::GetNext(aElm));
|
||||
} else {
|
||||
MOZ_ASSERT(mHead == aElm);
|
||||
mHead = ElementAccess::Get(aElm).mNext;
|
||||
mHead = SiblingAccess::GetNext(aElm);
|
||||
}
|
||||
|
||||
if (T* next = ElementAccess::Get(aElm).mNext) {
|
||||
ElementAccess::Get(next).mPrev = ElementAccess::Get(aElm).mPrev;
|
||||
if (T* next = SiblingAccess::GetNext(aElm)) {
|
||||
SiblingAccess::SetPrev(next, SiblingAccess::GetPrev(aElm));
|
||||
} else {
|
||||
MOZ_ASSERT(mTail == aElm);
|
||||
mTail = ElementAccess::Get(aElm).mPrev;
|
||||
mTail = SiblingAccess::GetPrev(aElm);
|
||||
}
|
||||
|
||||
ElementAccess::Get(aElm).mNext = nullptr;
|
||||
ElementAccess::Get(aElm).mPrev = nullptr;
|
||||
SiblingAccess::SetNext(aElm, nullptr);
|
||||
SiblingAccess::SetPrev(aElm, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -358,19 +352,6 @@ public:
|
|||
bool contains(const T& aElm) {
|
||||
return find(aElm) != Iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given element might be in the list. Note that this
|
||||
* assumes the element is either in the list or not in the list, and ignores
|
||||
* the case where the element might be in another list in order to make the
|
||||
* check fast.
|
||||
*/
|
||||
bool ElementProbablyInList(T* aElm) {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return !ElementNotInList(aElm);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -121,31 +121,32 @@ 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; }
|
||||
};
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<>
|
||||
struct GetDoublyLinkedListElement<InTwoLists> {
|
||||
static DoublyLinkedListElement<InTwoLists>& Get(InTwoLists* aThis) { return aThis->mListTwo; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
TestCustomAccessor()
|
||||
{
|
||||
DoublyLinkedList<InTwoLists, InTwoLists::GetListOneTrait> listOne;
|
||||
DoublyLinkedList<InTwoLists> listTwo;
|
||||
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;
|
||||
|
||||
InTwoLists one(1);
|
||||
InTwoLists two(2);
|
||||
|
|
Загрузка…
Ссылка в новой задаче