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 idunknown
push userunknown
push dateunknown
reviewerswaldo
bugs803688
milestone19.0a1
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);
     }