Remove homebrew List implementation

Use std::list instead of gestures::List
Include helper function where needed for .at needs
Changed LookaheadFilterInterpreter::free_list_ to be a vector
Added QStateList test for coverage improvement

BUG=b:270612476
TEST=USE="coverage" FEATURES="test noclean" emerge-brya chromeos-base/gestures

Change-Id: I0857ff48f8d386f15b887d25349c734f2710f946
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/gestures/+/4303073
Auto-Submit: Denis Brockus <dbrockus@chromium.org>
Code-Coverage: Henry Barnor <hbarnor@chromium.org>
Commit-Queue: Denis Brockus <dbrockus@chromium.org>
Reviewed-by: Harry Cutts <hcutts@chromium.org>
Tested-by: Denis Brockus <dbrockus@chromium.org>
diff --git a/Android.bp b/Android.bp
index eb7d8ac..8be85fa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -132,7 +132,6 @@
         "src/immediate_interpreter_unittest.cc",
         "src/integral_gesture_filter_interpreter_unittest.cc",
         "src/interpreter_unittest.cc",
-        "src/list_unittest.cc",
         "src/logging_filter_interpreter_unittest.cc",
         "src/lookahead_filter_interpreter_unittest.cc",
         "src/mouse_interpreter_unittest.cc",
diff --git a/Makefile b/Makefile
index 53c9d66..d04ce98 100644
--- a/Makefile
+++ b/Makefile
@@ -60,7 +60,6 @@
 	$(OBJDIR)/immediate_interpreter_unittest.o \
 	$(OBJDIR)/integral_gesture_filter_interpreter_unittest.o \
 	$(OBJDIR)/interpreter_unittest.o \
-	$(OBJDIR)/list_unittest.o \
 	$(OBJDIR)/logging_filter_interpreter_unittest.o \
 	$(OBJDIR)/lookahead_filter_interpreter_unittest.o \
 	$(OBJDIR)/non_linearity_filter_interpreter_unittest.o \
diff --git a/include/list.h b/include/list.h
index d5d94c4..c822e7a 100644
--- a/include/list.h
+++ b/include/list.h
@@ -5,104 +5,27 @@
 #ifndef GESTURES_LIST_H__
 #define GESTURES_LIST_H__
 
+#include <list>
 #include "include/logging.h"
 #include "include/memory_manager.h"
 
 namespace gestures {
 
-// Elt must have the following members:
-// Elt* next_;
-// Elt* prev_;
-
 template<typename Elt>
-class List {
+class MemoryManagedList : public std::list<Elt*> {
  public:
-  List() { Init(); }
-  ~List() { DeleteAll(); }
-
-  // inserts new_elt before existing. Assumes existing is in list already.
-  void InsertBefore(Elt *existing, Elt* new_elt) {
-    size_++;
-    Elt* pre_new = existing->prev_;
-    pre_new->next_ = new_elt;
-    new_elt->prev_ = pre_new;
-    new_elt->next_ = existing;
-    existing->prev_ = new_elt;
-  }
-
-  Elt* Unlink(Elt* existing) {
-    if (Empty()) {
-      Err("Can't pop from empty list!");
-      return NULL;
-    }
-    size_--;
-    existing->prev_->next_ = existing->next_;
-    existing->next_->prev_ = existing->prev_;
-    existing->prev_ = existing->next_ = NULL;
-    return existing;
-  }
-
-  void PushFront(Elt* elt) { InsertBefore(sentinel_.next_, elt); }
-  Elt* PopFront() { return Unlink(sentinel_.next_); }
-  void PushBack(Elt* elt) { InsertBefore(&sentinel_, elt); }
-  Elt* PopBack() { return Unlink(sentinel_.prev_); }
-
-  virtual void DeleteAll() {
-    while (!Empty())
-      delete PopFront();
-  }
-
-  Elt* Head() const { return sentinel_.next_; }
-  Elt* Tail() const { return sentinel_.prev_; }
-  size_t size() const { return size_; }
-  bool Empty() const { return size() == 0; }
-
-  // Iterator-like methods
-  Elt* Begin() const { return Head(); }
-  Elt* End() const { return const_cast<Elt*>(&sentinel_); }
-
-  void Init() {
-    size_ = 0;
-    sentinel_.next_ = sentinel_.prev_ = &sentinel_;
-  }
-
- private:
-  // sentinel element
-  Elt sentinel_;
-
-  size_t size_;
-};
-
-
-template<typename Elt>
-class MemoryManagedList : public List<Elt> {
- public:
-  using List<Elt>::Empty;
-  using List<Elt>::PopBack;
-  using List<Elt>::PopFront;
-  using List<Elt>::PushBack;
-  using List<Elt>::PushFront;
-
   MemoryManagedList() { };
-  ~MemoryManagedList() { DeleteAll(); }
+  ~MemoryManagedList() { clear(); }
 
   void Init(MemoryManager<Elt>* memory_manager) {
     memory_manager_ = memory_manager;
-    List<Elt>::Init();
-  }
-
-  Elt* NewElt() {
-    Elt* elt = memory_manager_->Allocate();
-    AssertWithReturnValue(elt, NULL);
-    elt->next_ = elt->prev_ = NULL;
-    return elt;
   }
 
   Elt* PushNewEltBack() {
     AssertWithReturnValue(memory_manager_, NULL);
     Elt* elt = NewElt();
     AssertWithReturnValue(elt, NULL);
-    PushBack(elt);
+    this->push_back(elt);
     return elt;
   }
 
@@ -110,26 +33,35 @@
     AssertWithReturnValue(memory_manager_, NULL);
     Elt* elt = NewElt();
     AssertWithReturnValue(elt, NULL);
-    PushFront(elt);
+    this->push_front(elt);
     return elt;
   }
 
   void DeleteFront() {
     AssertWithReturn(memory_manager_);
-    memory_manager_->Free(PopFront());
+    memory_manager_->Free(this->front());
+    this->pop_front();
   }
 
   void DeleteBack() {
     AssertWithReturn(memory_manager_);
-    memory_manager_->Free(PopBack());
+    memory_manager_->Free(this->pop_back());
   }
 
-  virtual void DeleteAll() {
-    while (!Empty())
+  void clear() {
+    while (!this->empty())
       DeleteFront();
   }
+
  private:
   MemoryManager<Elt>* memory_manager_;
+
+  Elt* NewElt() {
+    Elt* elt = memory_manager_->Allocate();
+    AssertWithReturnValue(elt, NULL);
+    elt->next_ = elt->prev_ = NULL;
+    return elt;
+  }
 };
 
 
diff --git a/include/lookahead_filter_interpreter.h b/include/lookahead_filter_interpreter.h
index 33dcc9b..31aefe4 100644
--- a/include/lookahead_filter_interpreter.h
+++ b/include/lookahead_filter_interpreter.h
@@ -3,15 +3,16 @@
 // found in the LICENSE file.
 
 #include <algorithm>
+#include <list>
 #include <map>
 #include <memory>
+#include <vector>
 
 #include <gtest/gtest.h>  // For FRIEND_TEST
 
 #include "include/filter_interpreter.h"
 #include "include/finger_metrics.h"
 #include "include/gestures.h"
-#include "include/list.h"
 #include "include/prop_registry.h"
 #include "include/tracer.h"
 
@@ -33,6 +34,8 @@
   FRIEND_TEST(LookaheadFilterInterpreterTest, SimpleTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, VariableDelayTest);
+  FRIEND_TEST(LookaheadFilterInterpreterTest, QStateListTest);
+
  public:
   LookaheadFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
                              Tracer* tracer);
@@ -108,8 +111,12 @@
 
   stime_t ExtraVariableDelay() const;
 
-  List<QState> queue_;
-  List<QState> free_list_;
+  class QStateList : public std::list<QState*> {
+  public:
+    QState* at(int offset);
+  } queue_;
+
+  std::vector<QState*> free_list_;
 
   // The last id assigned to a contact (part of drumroll suppression)
   short last_id_;
diff --git a/src/list_unittest.cc b/src/list_unittest.cc
deleted file mode 100644
index 9c8ea74..0000000
--- a/src/list_unittest.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2011 The ChromiumOS Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <algorithm>
-#include <set>
-
-#include <gtest/gtest.h>
-
-#include "include/list.h"
-#include "include/util.h"
-
-namespace gestures {
-
-class ListTest : public ::testing::Test {};
-
-namespace {
-struct Node {
-  explicit Node() : val_(-1) {}
-  explicit Node(int val) : val_(val) {}
-  int val_;
-  Node* next_;
-  Node* prev_;
-};
-
-void VerifyList(List<Node>& list) {
-  Node* first = list.Head()->prev_;  // sentinel
-  Node* second = list.Head();  // next elt (sentinel or first element)
-  std::set<Node*> seen_nodes;
-  if (!list.Empty())
-    EXPECT_NE(first, second);
-  else
-    EXPECT_EQ(first, second);
-  seen_nodes.insert(second);
-  for (size_t i = 0; i <= list.size(); ++i) {
-    EXPECT_EQ(first->next_, second);
-    EXPECT_EQ(second->prev_, first);
-    if (i < list.size()) {
-      first = second;
-      second = second->next_;
-      EXPECT_FALSE(SetContainsValue(seen_nodes, second));
-      seen_nodes.insert(second);
-    }
-  }
-  EXPECT_EQ(seen_nodes.size(), list.size() + 1);
-  // second should now be sentinal tail
-  Node* sen_tail = list.Tail()->next_;
-  EXPECT_EQ(second, sen_tail);
-}
-}
-
-TEST(ListTest, SimpleTest) {
-  List<Node> list;
-  VerifyList(list);
-  EXPECT_TRUE(list.Empty());
-  EXPECT_EQ(0, list.size());
-  list.PushFront(new Node(4));
-  VerifyList(list);
-  EXPECT_FALSE(list.Empty());
-  EXPECT_EQ(1, list.size());
-  list.PushFront(new Node(5));
-  VerifyList(list);
-  EXPECT_EQ(2, list.size());
-  EXPECT_EQ(4, list.Tail()->val_);
-  EXPECT_EQ(5, list.Head()->val_);
-  list.PushBack(new Node(3));
-  VerifyList(list);
-  EXPECT_EQ(3, list.size());
-
-  Node* node = list.PopFront();
-  VerifyList(list);
-  ASSERT_TRUE(node);
-  EXPECT_EQ(5, node->val_);
-  delete node;
-
-  node = list.PopBack();
-  VerifyList(list);
-  ASSERT_TRUE(node);
-  EXPECT_EQ(3, node->val_);
-  delete node;
-
-  node = list.PopBack();
-  VerifyList(list);
-  ASSERT_TRUE(node);
-  EXPECT_EQ(4, node->val_);
-  delete node;
-
-  node = list.PopBack();
-  VerifyList(list);
-  EXPECT_EQ(NULL, node);
-}
-
-}  // namespace gestures
diff --git a/src/lookahead_filter_interpreter.cc b/src/lookahead_filter_interpreter.cc
index f7abaf5..f60b0f5 100644
--- a/src/lookahead_filter_interpreter.cc
+++ b/src/lookahead_filter_interpreter.cc
@@ -19,9 +19,12 @@
 static const stime_t kMaxDelay = 0.09;  // 90ms
 }
 
+static const size_t kMaxQNodes = 16;
+
 LookaheadFilterInterpreter::LookaheadFilterInterpreter(
     PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
     : FilterInterpreter(NULL, next, tracer, false),
+      free_list_(kMaxQNodes),
       last_id_(0), max_fingers_per_hwstate_(0), interpreter_due_(-1.0),
       last_interpreted_time_(-1.0),
       min_nonsuppress_speed_(prop_reg, "Input Queue Min Nonsuppression Speed",
@@ -46,40 +49,42 @@
 void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate,
                                                        stime_t* timeout) {
   // Push back into queue
-  if (free_list_.Empty()) {
+  if (free_list_.empty()) {
     Err("Can't accept new hwstate b/c we're out of nodes!");
     Err("Now: %f, interpreter_due_ %f", hwstate->timestamp, interpreter_due_);
     Err("Dump of queue:");
-    for (QState* it = queue_.Begin(); it != queue_.End(); it = it->next_)
-      Err("Due: %f%s", it->due_, it->completed_ ? " (c)" : "");
+    for (const auto& element : queue_)
+      Err("Due: %f%s", element->due_, element->completed_ ? " (c)" : "");
     return;
   }
-  QState* node = free_list_.PopFront();
+  QState* node = free_list_.back();
+  free_list_.pop_back();
   node->set_state(*hwstate);
   double delay = max(0.0, min<stime_t>(kMaxDelay, min_delay_.val_));
   node->due_ = hwstate->timestamp + delay;
   node->completed_ = false;
-  if (queue_.Empty())
+  if (queue_.empty())
     node->output_ids_.clear();
   else
-    node->output_ids_ = queue_.Tail()->output_ids_;
-  // At this point, if ExtraVariableDelay() > 0, queue_.Tail()->due_ may have
+    node->output_ids_ = queue_.back()->output_ids_;
+  // At this point, if ExtraVariableDelay() > 0, queue_.back()->due_ may have
   // ExtraVariableDelay() applied, but node->due_ does not, yet.
-  if (!queue_.Empty() &&
-      (queue_.Tail()->due_ - node->due_ > ExtraVariableDelay())) {
+  if (!queue_.empty() &&
+      (queue_.back()->due_ - node->due_ > ExtraVariableDelay())) {
     Err("Clock changed backwards. Flushing queue.");
     stime_t next_timeout = NO_DEADLINE;
-    QState* q_node = queue_.Head();
+    auto q_node_iter = queue_.begin();
     do {
-      if (!q_node->completed_)
-        next_->SyncInterpret(&q_node->state_, &next_timeout);
-      q_node = q_node->next_;
-      free_list_.PushBack(queue_.PopFront());
-    } while (!queue_.Empty());
+      if (!(*q_node_iter)->completed_)
+        next_->SyncInterpret(&(*q_node_iter)->state_, &next_timeout);
+      ++q_node_iter;
+      free_list_.push_back(queue_.front());
+      queue_.pop_front();
+    } while (!queue_.empty());
     interpreter_due_ = -1.0;
     last_interpreted_time_ = -1.0;
   }
-  queue_.PushBack(node);
+  queue_.push_back(node);
   AssignTrackingIds();
   AttemptInterpolation();
   UpdateInterpreterDue(interpreter_due_ < 0.0 ?
@@ -88,7 +93,7 @@
   HandleTimerImpl(hwstate->timestamp, timeout);
 
   // Copy finger flags for upstream filters.
-  QState* q_node = queue_.Head();
+  QState* q_node = queue_.front();
   if (q_node->state_.SameFingersAs(*hwstate)) {
     for (size_t i = 0; i < hwstate->finger_cnt; i++) {
       hwstate->fingers[i].flags = q_node->state_.fingers[i].flags;
@@ -143,7 +148,7 @@
     // Always reassign trackingID on the very first hwstate so that
     // the next hwstate can inherit the trackingID mapping.
     if (queue_.size() == 1) {
-      QState* tail = queue_.Tail();
+      QState* tail = queue_.back();
       HardwareState* hs = &tail->state_;
       for (size_t i = 0; i < hs->finger_cnt; i++) {
         FingerState* fs = &hs->fingers[i];
@@ -156,11 +161,11 @@
     return;
   }
 
-  QState* tail = queue_.Tail();
+  auto tail = queue_.at(-1);
   HardwareState* hs = &tail->state_;
-  QState* prev_qs = queue_.size() < 2 ? NULL : tail->prev_;
+  QState* prev_qs = queue_.size() < 2 ? NULL : queue_.at(-2);
   HardwareState* prev_hs = prev_qs ? &prev_qs->state_ : NULL;
-  QState* prev2_qs = queue_.size() < 3 ? NULL : prev_qs->prev_;
+  QState* prev2_qs = queue_.size() < 3 ? NULL : queue_.at(-3);
   HardwareState* prev2_hs = prev2_qs ? &prev2_qs->state_ : NULL;
 
   RemoveMissingIdsFromMap(&tail->output_ids_, *hs);
@@ -356,11 +361,12 @@
     return;
   if (queue_.size() < 2)
     return;  // Not enough data to know
-  HardwareState& hs = queue_.Tail()->state_;
-  if (queue_.Tail()->state_.timestamp != now)
+  HardwareState& hs = queue_.back()->state_;
+  if (queue_.back()->state_.timestamp != now)
     return;  // We didn't push a new hardware state now
-  // See if latest hwstate has finger that previous doesn't
-  HardwareState& prev_hs = queue_.Tail()->prev_->state_;
+  // See if latest hwstate has finger that previous doesn't.
+  // Get the state_ of back->prev
+  HardwareState& prev_hs = queue_.at(-2)->state_;
   if (hs.finger_cnt > prev_hs.finger_cnt) {
     // Finger was added.
     ProduceGesture(Gesture(kGestureFling, prev_hs.timestamp, hs.timestamp,
@@ -396,18 +402,20 @@
 void LookaheadFilterInterpreter::AttemptInterpolation() {
   if (queue_.size() < 2)
     return;
-  QState* new_node = queue_.Tail();
-  QState* prev = new_node->prev_;
+  QState* new_node = queue_.at(-1);
+  QState* prev = queue_.at(-2);
   if (new_node->state_.timestamp - prev->state_.timestamp <
-      split_min_period_.val_)
+      split_min_period_.val_) {
     return;  // Nodes came in too quickly to need interpolation
+  }
   if (!prev->state_.SameFingersAs(new_node->state_))
     return;
-  QState* node = free_list_.PopFront();
-  if (!node) {
+  if (free_list_.empty()) {
     Err("out of nodes?");
     return;
   }
+  QState* node = free_list_.back();
+  free_list_.pop_back();
   node->state_.fingers = node->fs_.get();
   node->completed_ = false;
   Interpolate(prev->state_, new_node->state_, &node->state_);
@@ -418,11 +426,10 @@
   if (node->state_.timestamp <= last_interpreted_time_) {
     // Time wouldn't seem monotonically increasing w/ this new event, so
     // discard it.
-    free_list_.PushBack(node);
-    return;
+    free_list_.push_back(node);
+  } else {
+    queue_.insert(--queue_.end(), node);
   }
-
-  queue_.InsertBefore(new_node, node);
 }
 
 void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now,
@@ -440,12 +447,16 @@
       last_interpreted_time_ = now;
       next_->HandleTimer(now, &next_timeout);
     } else {
-      if (queue_.Empty())
+      if (queue_.empty())
         break;
       // Get next uncompleted and overdue hwstate
-      QState* node = queue_.Head();
-      while (node != queue_.Tail() && node->completed_)
-        node = node->next_;
+      auto node = queue_.back();
+      for (auto state : queue_) {
+        if (!state->completed_) {
+          node = state;
+          break;
+        }
+      }
       if (node->completed_ || node->due_ > now)
         break;
       next_timeout = NO_DEADLINE;
@@ -471,8 +482,10 @@
       next_->SyncInterpret(&hs_copy, &next_timeout);
 
       // Clear previously completed nodes, but keep at least two nodes.
-      while (queue_.size() > 2 && queue_.Head()->completed_)
-        free_list_.PushBack(queue_.PopFront());
+      while (queue_.size() > 2 && queue_.front()->completed_) {
+        free_list_.push_back(queue_.front());
+        queue_.pop_front();
+      }
 
       // Mark current node completed. This should be the only completed
       // node in the queue.
@@ -489,7 +502,7 @@
 }
 
 void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) {
-  QState* node = queue_.Head();
+  QState* node = queue_.front();
 
   float distance_sq = 0.0;
   // Slow movements should potentially be suppressed
@@ -516,10 +529,11 @@
     return;
   }
   // Speed is slow. Suppress if fingers have changed.
-  for (QState* iter = node->next_; iter != queue_.End(); iter = iter->next_)
-    if (!node->state_.SameFingersAs(iter->state_) ||
-        (node->state_.buttons_down != iter->state_.buttons_down))
+  for (auto iter = ++queue_.begin(); iter != queue_.end(); ++iter) {
+    if (!node->state_.SameFingersAs((*iter)->state_) ||
+        (node->state_.buttons_down != (*iter)->state_.buttons_down))
       return; // suppress
+  }
 
   ProduceGesture(gesture);
 }
@@ -532,11 +546,10 @@
   // timeout, so we use -DBL_MAX as the invalid value.
   stime_t next_hwstate_timeout = -DBL_MAX;
   // Scan queue_ to find when next hwstate is due.
-  for (QState* node = queue_.Begin(); node != queue_.End();
-       node = node->next_) {
-    if (node->completed_)
+  for (auto elem : queue_) {
+    if (elem->completed_)
       continue;
-    next_hwstate_timeout = node->due_ - now;
+    next_hwstate_timeout = elem->due_ - now;
     break;
   }
 
@@ -557,12 +570,11 @@
     MetricsProperties* mprops,
     GestureConsumer* consumer) {
   FilterInterpreter::Initialize(hwprops, NULL, mprops, consumer);
-  const size_t kMaxQNodes = 16;
-  queue_.DeleteAll();
-  free_list_.DeleteAll();
+  queue_.clear();
+  free_list_.clear();
   for (size_t i = 0; i < kMaxQNodes; ++i) {
     QState* node = new QState(hwprops_->max_finger_cnt);
-    free_list_.PushBack(node);
+    free_list_.push_back(node);
   }
 }
 
@@ -603,4 +615,25 @@
   state_.msc_timestamp = new_state.msc_timestamp;
 }
 
+LookaheadFilterInterpreter::QState*
+LookaheadFilterInterpreter::QStateList::at(int offset) {
+  // Traverse to the appropriate offset
+  if (offset < 0) {
+    // negative offset is from end to begin
+    auto count = size();
+    for (auto iter = --end(); count > 0; --count, --iter) {
+      if (++offset == 0)
+        return *iter;
+    }
+  } else {
+    // positive offset is from begin to end
+    for (auto elem : *this) {
+      if (offset-- == 0)
+        return elem;
+    }
+  }
+  // invalid offset returns NULL
+  return nullptr;
+}
+
 }  // namespace gestures
diff --git a/src/lookahead_filter_interpreter_unittest.cc b/src/lookahead_filter_interpreter_unittest.cc
index 788d785..1c84eb4 100644
--- a/src/lookahead_filter_interpreter_unittest.cc
+++ b/src/lookahead_filter_interpreter_unittest.cc
@@ -788,42 +788,42 @@
   wrapper.Reset(interpreter.get());
 
   stime_t timeout = NO_DEADLINE;
-  List<LookaheadFilterInterpreter::QState>* queue = &interpreter->queue_;
+  const auto& queue = interpreter->queue_;
 
   // Pushing the first event
   wrapper.SyncInterpret(&hs[0], &timeout);
-  EXPECT_EQ(queue->size(), 1);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 1);
+  EXPECT_EQ(queue.size(), 1);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 1);
 
   // Expecting Drumroll detected and ID reassigned 1 -> 2.
   wrapper.SyncInterpret(&hs[1], &timeout);
-  EXPECT_EQ(queue->size(), 2);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 2);
+  EXPECT_EQ(queue.size(), 2);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 2);
 
   // Expecting Drumroll detected and ID reassigned 1 -> 3.
   wrapper.SyncInterpret(&hs[2], &timeout);
-  EXPECT_EQ(queue->size(), 3);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 3);
+  EXPECT_EQ(queue.size(), 3);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 3);
 
   // Removing the touch.
   wrapper.SyncInterpret(&hs[3], &timeout);
-  EXPECT_EQ(queue->size(), 4);
+  EXPECT_EQ(queue.size(), 4);
 
   // New event comes, old events removed from the queue.
   // New finger tracking ID assigned 2 - > 4.
   wrapper.SyncInterpret(&hs[4], &timeout);
-  EXPECT_EQ(queue->size(), 2);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 4);
+  EXPECT_EQ(queue.size(), 2);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 4);
 
   // Expecting Drumroll detected and ID reassigned 2 -> 5.
   wrapper.SyncInterpret(&hs[5], &timeout);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 5);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 5);
 
   // Expecting Quick movement detected and ID correction 5 -> 4.
   wrapper.SyncInterpret(&hs[6], &timeout);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 4);
-  EXPECT_EQ(queue->Tail()->prev_->fs_[0].tracking_id, 4);
-  EXPECT_EQ(queue->Tail()->prev_->prev_->fs_[0].tracking_id, 4);
+  EXPECT_EQ(interpreter->queue_.at(-1)->fs_[0].tracking_id, 4);
+  EXPECT_EQ(interpreter->queue_.at(-2)->fs_[0].tracking_id, 4);
+  EXPECT_EQ(interpreter->queue_.at(-3)->fs_[0].tracking_id, 4);
 }
 
 struct QuickSwipeTestInputs {
@@ -1263,16 +1263,79 @@
   wrapper.Reset(interpreter.get());
 
   stime_t timeout = NO_DEADLINE;
-  List<LookaheadFilterInterpreter::QState>* queue = &interpreter->queue_;
+  const auto& queue = interpreter->queue_;
 
   wrapper.SyncInterpret(&hs[0], &timeout);
-  EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 20);
+  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 20);
 
   // Test if the fingers in queue have the same tracking ids from input.
   for (size_t i = 1; i < arraysize(hs); i++) {
     wrapper.SyncInterpret(&hs[i], &timeout);
-    EXPECT_EQ(queue->Tail()->fs_[0].tracking_id, 20);  // the same input id
-    EXPECT_EQ(queue->Tail()->fs_[1].tracking_id, 21);
+    EXPECT_EQ(queue.back()->fs_[0].tracking_id, 20);  // the same input id
+    EXPECT_EQ(queue.back()->fs_[1].tracking_id, 21);
   }
 }
+
+TEST(LookaheadFilterInterpreterTest, QStateListTest) {
+  LookaheadFilterInterpreterTestInterpreter* base_interpreter = NULL;
+  std::unique_ptr<LookaheadFilterInterpreter> interpreter;
+
+  HardwareProperties hwprops = {
+    0, 0, 100, 100,  // left, top, right, bottom
+    1,  // x res (pixels/mm)
+    1,  // y res (pixels/mm)
+    25, 25,  // scrn DPI X, Y
+    -1,  // orientation minimum
+    2,   // orientation maximum
+    2, 5,  // max fingers, max_touch
+    1, 1, 0,  // t5r2, semi, button pad
+    0, 0,  // has wheel, vertical wheel is high resolution
+    0,  // haptic pad
+  };
+  TestInterpreterWrapper wrapper(interpreter.get(), &hwprops);
+
+  base_interpreter = new LookaheadFilterInterpreterTestInterpreter;
+  interpreter.reset(new LookaheadFilterInterpreter(
+      NULL, base_interpreter, NULL));
+  wrapper.Reset(interpreter.get());
+
+  auto& queue = interpreter->queue_;
+  auto& free_list = interpreter->free_list_;
+
+  // Release all of the QStates
+  while (!queue.empty()) {
+    free_list.push_back(queue.front());
+    queue.pop_front();
+  }
+  EXPECT_EQ(queue.size(), 0);
+  EXPECT_EQ(free_list.size(), 16);
+
+  EXPECT_EQ(queue.at(-1), nullptr);
+  EXPECT_EQ(queue.at(queue.size()), nullptr);
+
+  // fill up the QStates
+  while (!free_list.empty()) {
+    queue.push_front(free_list.back());
+    free_list.pop_back();
+  }
+  EXPECT_EQ(queue.size(), 16);
+  EXPECT_EQ(free_list.size(), 0);
+
+  EXPECT_NE(queue.at(-1), nullptr);
+  EXPECT_EQ(queue.at(-1), queue.at(queue.size() - 1));
+
+  EXPECT_EQ(queue.at(queue.size()), nullptr);
+
+  for (int i = 0; i < 16; ++i) {
+    for (int j = 0; j < 16; ++j) {
+      if (i == j) {
+        EXPECT_EQ(queue.at(i), queue.at(j));
+      } else {
+        EXPECT_NE(queue.at(i), queue.at(j));
+      }
+    }
+  }
+
+  LookaheadFilterInterpreter::QState qs;
+}
 }  // namespace gestures
diff --git a/src/metrics_filter_interpreter.cc b/src/metrics_filter_interpreter.cc
index e608f23..de6ca33 100644
--- a/src/metrics_filter_interpreter.cc
+++ b/src/metrics_filter_interpreter.cc
@@ -142,7 +142,7 @@
   RemoveMissingIdsFromMap(&histories_, hwstate, &removed);
   for (FingerHistoryMap::const_iterator it =
        removed.begin(); it != removed.end(); ++it) {
-    it->second->DeleteAll();
+    it->second->clear();
     history_mm_.Free(it->second);
 }
 
@@ -171,14 +171,15 @@
 
 bool MetricsFilterInterpreter::DetectNoisyGround(
     const FingerHistory* history) {
-  MState* current = history->Tail();
+  auto iter = history->end();
+  MState* current = *(--iter);
   size_t n_samples = history->size();
   // Noise pattern takes 3 samples
   if (n_samples < 3)
     return false;
 
-  MState* past_1 = current->prev_;
-  MState* past_2 = past_1->prev_;
+  MState* past_1 = *(--iter);
+  MState* past_2 = *(--iter);
   // Noise pattern needs to happen in a short period of time
   if(current->timestamp - past_2->timestamp >
       noisy_ground_time_threshold_.val_) {
diff --git a/src/trend_classifying_filter_interpreter.cc b/src/trend_classifying_filter_interpreter.cc
index 45699a9..d6ddd21 100644
--- a/src/trend_classifying_filter_interpreter.cc
+++ b/src/trend_classifying_filter_interpreter.cc
@@ -78,7 +78,7 @@
     history->DeleteFront();
 
   // Push the new finger state to the back of buffer
-  KState* previous_end = history->Tail();
+  KState* previous_end = history->back();
   KState* current = history->PushNewEltBack();
   if (!current) {
     Err("KState buffer out of space");
@@ -94,10 +94,10 @@
   // variance along the way. Complexity is O(|buffer|) per finger.
   int tie_n2[KState::n_axes_] = { 0, 0, 0, 0, 0, 0 };
   int tie_n3[KState::n_axes_] = { 0, 0, 0, 0, 0, 0 };
-  for (KState* it = history->Begin(); it != history->Tail(); it = it->next_)
+  for (auto it = history->begin(); it != history->end(); ++it)
     for (size_t i = 0; i < KState::n_axes_; i++)
-      if(it != history->Begin() || !KState::IsDelta(i)) {
-        UpdateKTValuePair(&it->axes_[i], &current->axes_[i],
+      if (it != history->begin() || !KState::IsDelta(i)) {
+        UpdateKTValuePair(&(*it)->axes_[i], &current->axes_[i],
             &tie_n2[i], &tie_n3[i]);
       }
   size_t n_samples = history->size();
@@ -136,7 +136,7 @@
   RemoveMissingIdsFromMap(&histories_, hwstate, &removed);
   for (FingerHistoryMap::const_iterator it =
        removed.begin(); it != removed.end(); ++it) {
-    it->second->DeleteAll();
+    it->second->clear();
     history_mm_.Free(it->second);
   }
 
@@ -159,7 +159,7 @@
 
     // Check if the score demonstrates statistical significance
     AddNewStateToBuffer(hp, fs[i]);
-    KState* current = hp->Tail();
+    KState* current = hp->back();
     size_t n_samples = hp->size();
     for (size_t idx = 0; idx < KState::n_axes_; idx++)
       if (second_order_enable_.val_ || !KState::IsDelta(idx)) {