Bug 803688 - Remove LinkedListElements from their list when they're destructed, and assert that a LinkedList is empty when it's destructed. r=waldo
authorJustin Lebar <justin.lebar@gmail.com>
Wed, 24 Oct 2012 12:40:35 -0400
changeset 111263 592c3465a74231069e07b10b2a072b54ea0f06b0
parent 111262 161dd84a24fc53105aae2a707cd952946d0704f6
child 111264 37e8ef1c735319f7ec9f2cbe5e6a6460cc59340f
push id23738
push userryanvm@gmail.com
push dateThu, 25 Oct 2012 01:50:40 +0000
treeherdermozilla-central@3fb7c935a625 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs803688
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 803688 - Remove LinkedListElements from their list when they're destructed, and assert that a LinkedList is empty when it's destructed. r=waldo
mfbt/LinkedList.h
--- a/mfbt/LinkedList.h
+++ b/mfbt/LinkedList.h
@@ -8,16 +8,20 @@
 /*
  * The classes LinkedList<T> and LinkedListElement<T> together form a
  * convenient, type-safe doubly-linked list implementation.
  *
  * The class T which will be inserted into the linked list must inherit from
  * LinkedListElement<T>.  A given object may be in only one linked list at a
  * time.
  *
+ * A LinkedListElement automatically removes itself from the list upon
+ * destruction, and a LinkedList will fatally assert in debug builds if it's
+ * non-empty when it's destructed.
+ *
  * For example, you might use LinkedList in a simple observer list class as
  * follows.
  *
  *   class Observer : public LinkedListElement<Observer>
  *   {
  *     public:
  *       void observe(char* topic) { ... }
  *   };
@@ -105,16 +109,21 @@ class LinkedListElement
 
   public:
     LinkedListElement()
       : next(thisDuringConstruction()),
         prev(thisDuringConstruction()),
         isSentinel(false)
     { }
 
+    ~LinkedListElement() {
+      if (!isSentinel && isInList())
+        remove();
+    }
+
     /*
      * Get the next element in the list, or NULL if this is the last element in
      * the list.
      */
     T* getNext() {
       return next->asT();
     }
     const T* getNext() const {
@@ -179,18 +188,17 @@ class LinkedListElement
       NODE_KIND_NORMAL,
       NODE_KIND_SENTINEL
     };
 
     LinkedListElement(NodeKind nodeKind)
       : next(this),
         prev(this),
         isSentinel(nodeKind == NODE_KIND_SENTINEL)
-    {
-    }
+    { }
 
     /*
      * Return |this| cast to T* if we're a normal node, or return NULL if we're
      * a sentinel node.
      */
     T* asT() {
       if (isSentinel)
         return NULL;
@@ -241,16 +249,20 @@ template<typename T>
 class LinkedList
 {
   private:
     LinkedListElement<T> sentinel;
 
   public:
     LinkedList() : sentinel(LinkedListElement<T>::NODE_KIND_SENTINEL) { }
 
+    ~LinkedList() {
+      MOZ_ASSERT(isEmpty());
+    }
+
     /*
      * Add elem to the front of the list.
      */
     void insertFront(T* elem) {
       /* Bypass setNext()'s this->isInList() assertion. */
       sentinel.setNextUnsafe(elem);
     }