Merge list refactor from upstream am: f29fcceda1 am: f78de2018b am: b9d4211737 am: bcae70e9f7

Original change: https://android-review.googlesource.com/c/platform/external/libchrome-gestures/+/2523978

Change-Id: I13151b97e709c749bcb3bcc2e8af29dbd0085c72
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/METADATA.android b/METADATA.android
index 4aee07c..f12b10f 100644
--- a/METADATA.android
+++ b/METADATA.android
@@ -6,7 +6,7 @@
     type: GIT
     value: "https://chromium.googlesource.com/chromiumos/platform/gestures/"
   }
-  version: "2a80cba49fb09f6f2632b61f21ea7dc62acd82d7"
-  last_upgrade_date { year: 2023 month: 03 day: 10  }
+  version: "b6ae21cf67acbc76254be3677264b0ea472fce09"
+  last_upgrade_date { year: 2023 month: 04 day: 05  }
   license_type: NOTICE
 }
diff --git a/include/gestures.h b/include/gestures.h
index f21d531..f3005a0 100644
--- a/include/gestures.h
+++ b/include/gestures.h
@@ -106,15 +106,6 @@
 #endif  // __cplusplus
 };
 
-// position is the (x,y) cartesian coord of the finger on the trackpad.
-// touch_major/minor are the large/small radii of the ellipse of the touching
-// finger. width_major/minor are also radii, but of the finger itself,
-// including a little bit that isn't touching. So, width* is generally a tad
-// larger than touch*.
-// tracking_id: If a finger is the same physical finger across two
-// consecutive frames, it must have the same tracking id; if it's a different
-// finger, it may (should) have a different tracking id.
-
 // Warp: If a finger has the 'warp' flag set for an axis, it means that while
 // the finger may have moved, it should not cause any motion in that direction.
 // This may occur is some situations where we thought a finger was in one place,
@@ -168,16 +159,27 @@
 #define GESTURES_FINGER_WARP_Y    (GESTURES_FINGER_WARP_Y_NON_MOVE | \
                                    GESTURES_FINGER_WARP_Y_MOVE)
 
-// Describes a single contact on a touch surface. Unless otherwise noted, the
-// fields have the same meaning as the equivalent ABS_MT_... axis in the Linux
-// evdev protocol.
+// Describes a single contact on a touch surface. Generally, the fields have the
+// same meaning as the equivalent ABS_MT_... axis in the Linux evdev protocol.
 struct FingerState {
+  // The large and small radii of the ellipse of the finger touching the pad.
   float touch_major, touch_minor;
+
+  // The large and small radii of the ellipse of the finger, including parts
+  // that are hovering over the pad but not quite touching. Devices normally
+  // don't report these values, in which case they should be left at 0.
   float width_major, width_minor;
   float pressure;
   float orientation;
+
   float position_x;
   float position_y;
+
+  // A number that identifies a single physical finger across consecutive
+  // frames. If a finger is the same physical finger across two consecutive
+  // frames, it must have the same tracking ID; if it's a different finger, it
+  // should have a different tracking ID. It should be ≥ 0 (see documentation
+  // comment for HardwareState::fingers).
   short tracking_id;
 
   // A bit field of flags that are used internally by the library. (See the
@@ -229,8 +231,13 @@
   unsigned short finger_cnt;
   // The number of fingers touching the pad, which may be more than finger_cnt.
   unsigned short touch_cnt;
-  // A pointer to finger_cnt FingerState structs representing the contacts
-  // currently being tracked.
+  // A pointer to an array of FingerState structs with finger_cnt entries,
+  // representing the contacts currently being tracked. The order in which
+  // FingerStates appear need not be stable between HardwareStates — only the
+  // tracking ID is used to track individual contacts over time. Accordingly,
+  // when a finger is lifted from the pad (and therefore its ABS_MT_TRACKING_ID
+  // becomes -1), the client should simply stop including it in this array,
+  // rather than including a final FingerState for it.
   struct FingerState* fingers;
 
   // Mouse axes, which have the same meanings as the Linux evdev axes of the
diff --git a/include/list.h b/include/list.h
deleted file mode 100644
index c822e7a..0000000
--- a/include/list.h
+++ /dev/null
@@ -1,70 +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.
-
-#ifndef GESTURES_LIST_H__
-#define GESTURES_LIST_H__
-
-#include <list>
-#include "include/logging.h"
-#include "include/memory_manager.h"
-
-namespace gestures {
-
-template<typename Elt>
-class MemoryManagedList : public std::list<Elt*> {
- public:
-  MemoryManagedList() { };
-  ~MemoryManagedList() { clear(); }
-
-  void Init(MemoryManager<Elt>* memory_manager) {
-    memory_manager_ = memory_manager;
-  }
-
-  Elt* PushNewEltBack() {
-    AssertWithReturnValue(memory_manager_, NULL);
-    Elt* elt = NewElt();
-    AssertWithReturnValue(elt, NULL);
-    this->push_back(elt);
-    return elt;
-  }
-
-  Elt* PushNewEltFront() {
-    AssertWithReturnValue(memory_manager_, NULL);
-    Elt* elt = NewElt();
-    AssertWithReturnValue(elt, NULL);
-    this->push_front(elt);
-    return elt;
-  }
-
-  void DeleteFront() {
-    AssertWithReturn(memory_manager_);
-    memory_manager_->Free(this->front());
-    this->pop_front();
-  }
-
-  void DeleteBack() {
-    AssertWithReturn(memory_manager_);
-    memory_manager_->Free(this->pop_back());
-  }
-
-  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;
-  }
-};
-
-
-}  // namespace gestures
-
-#endif  // GESTURES_LIST_H__
diff --git a/include/lookahead_filter_interpreter.h b/include/lookahead_filter_interpreter.h
index 31aefe4..2658daa 100644
--- a/include/lookahead_filter_interpreter.h
+++ b/include/lookahead_filter_interpreter.h
@@ -3,10 +3,8 @@
 // found in the LICENSE file.
 
 #include <algorithm>
-#include <list>
 #include <map>
 #include <memory>
-#include <vector>
 
 #include <gtest/gtest.h>  // For FRIEND_TEST
 
@@ -15,6 +13,7 @@
 #include "include/gestures.h"
 #include "include/prop_registry.h"
 #include "include/tracer.h"
+#include "include/util.h"
 
 #ifndef GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_
 #define GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_
@@ -34,7 +33,6 @@
   FRIEND_TEST(LookaheadFilterInterpreterTest, SimpleTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, VariableDelayTest);
-  FRIEND_TEST(LookaheadFilterInterpreterTest, QStateListTest);
 
  public:
   LookaheadFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
@@ -65,10 +63,7 @@
     std::map<short, short> output_ids_;  // input tracking ids -> output
 
     stime_t due_;
-    bool completed_;
-
-    QState* next_;
-    QState* prev_;
+    bool completed_ = false;
   };
 
   void LogVectors();
@@ -111,12 +106,7 @@
 
   stime_t ExtraVariableDelay() const;
 
-  class QStateList : public std::list<QState*> {
-  public:
-    QState* at(int offset);
-  } queue_;
-
-  std::vector<QState*> free_list_;
+  List<QState> queue_;
 
   // The last id assigned to a contact (part of drumroll suppression)
   short last_id_;
diff --git a/include/memory_manager.h b/include/memory_manager.h
deleted file mode 100644
index 26e096a..0000000
--- a/include/memory_manager.h
+++ /dev/null
@@ -1,79 +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.
-
-#ifndef GESTURES_MEMORY_MANAGER_H_
-#define GESTURES_MEMORY_MANAGER_H_
-
-#include <new>
-
-#include "include/logging.h"
-#include "include/macros.h"
-
-namespace gestures {
-
-// A simple memory manager class that pre-allocates a size of
-// buffer and garbage collects freed variables. It is not intended
-// to be used directly. User classes should inherit the
-// MemoryManaged wrapper class and use the provided Allocate/Free
-// interface instead (see below).
-
-template<typename T>
-class MemoryManager {
- public:
-  explicit MemoryManager(size_t size) : buf_(new T[size]),
-    free_slots_(new T *[size]), used_mark_(new bool[size]()),
-    max_size_(size), head_(size) {
-    for (size_t i = 0; i < max_size_; i++)
-      free_slots_[i] = buf_.get() + i;
-  }
-
-  size_t Size() const { return max_size_ - head_; }
-  size_t MaxSize() const { return max_size_; }
-
-  T* Allocate() {
-    if (!head_) {
-      Err("MemoryManager::Allocate: out of space");
-      return NULL;
-    }
-
-    T* ptr = free_slots_[--head_];
-    used_mark_[ptr - buf_.get()] = true;
-    return ptr;
-  }
-
-  bool Free(T* ptr) {
-    // Check for invalid pointer and double-free
-    if (ptr < buf_.get() || ptr >= buf_.get() + max_size_) {
-      Err("MemoryManager::Free: pointer out of bounds");
-      return false;
-    }
-    size_t offset_in_bytes = reinterpret_cast<size_t>(ptr) -
-        reinterpret_cast<size_t>(buf_.get());
-    if (offset_in_bytes % sizeof(T)) {
-      Err("MemoryManager::Free: unaligned pointer");
-      return false;
-    }
-    size_t offset = ptr - buf_.get();
-    if (!used_mark_[offset]) {
-      Err("MemoryManager::Free: double-free");
-      return false;
-    }
-
-    free_slots_[head_++] = ptr;
-    used_mark_[offset] = false;
-    return true;
-  }
-
- private:
-  std::unique_ptr<T[]> buf_;
-  std::unique_ptr<T*[]> free_slots_;
-  std::unique_ptr<bool[]> used_mark_;
-  size_t max_size_;
-  size_t head_;
-  DISALLOW_COPY_AND_ASSIGN(MemoryManager<T>);
-};
-
-}  // namespace gestures
-
-#endif  // MEMORY_MANAGER_H_
diff --git a/include/metrics_filter_interpreter.h b/include/metrics_filter_interpreter.h
index 60d5898..518a47a 100644
--- a/include/metrics_filter_interpreter.h
+++ b/include/metrics_filter_interpreter.h
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <map>
 #include <gtest/gtest.h>  // for FRIEND_TEST
+#include <map>
 
 #include "include/filter_interpreter.h"
 #include "include/finger_metrics.h"
 #include "include/gestures.h"
-#include "include/list.h"
-#include "include/memory_manager.h"
 #include "include/prop_registry.h"
 #include "include/tracer.h"
+#include "include/util.h"
 
 #ifndef GESTURES_METRICS_FILTER_INTERPRETER_H_
 #define GESTURES_METRICS_FILTER_INTERPRETER_H_
@@ -43,31 +42,22 @@
   template <class DataType, size_t kHistorySize>
   struct State {
     State() {}
-    State(const DataType& fs, const HardwareState& hwstate) {
-      Init(fs, hwstate);
-    }
-
-    void Init(const DataType& fs, const HardwareState& hwstate) {
-      timestamp = hwstate.timestamp;
-      data = fs;
-    }
+    State(const DataType& fs, const HardwareState& hwstate)
+      : timestamp(hwstate.timestamp), data(fs) {}
 
     static size_t MaxHistorySize() { return kHistorySize; }
 
     stime_t timestamp;
     DataType data;
-    State<DataType, kHistorySize>* next_;
-    State<DataType, kHistorySize>* prev_;
   };
 
   // struct for one finger's data of one frame.
   typedef State<FingerState, 3> MState;
-  typedef MemoryManagedList<MState> FingerHistory;
+  typedef List<MState> FingerHistory;
 
   // Push the new data into the buffer.
-  template <class StateType, class DataType>
-  void AddNewStateToBuffer(MemoryManagedList<StateType>* history,
-                           const DataType& data,
+  void AddNewStateToBuffer(FingerHistory& history,
+                           const FingerState& data,
                            const HardwareState& hwstate);
 
   // Update the class with new finger data, check if there is any interesting
@@ -75,7 +65,7 @@
   void UpdateFingerState(const HardwareState& hwstate);
 
   // Detect the noisy ground pattern and send GestureMetrics
-  bool DetectNoisyGround(const FingerHistory* history);
+  bool DetectNoisyGround(FingerHistory& history);
 
   // Update the class with new mouse movement data.
   void UpdateMouseMovementState(const HardwareState& hwstate);
@@ -83,12 +73,8 @@
   // Compute interested statistics for the mouse history, send GestureMetrics.
   void ReportMouseStatistics();
 
-  // memory managers to prevent malloc during interrupt calls
-  MemoryManager<MState> mstate_mm_;
-  MemoryManager<FingerHistory> history_mm_;
-
   // A map to store each finger's past data
-  typedef std::map<short, FingerHistory*> FingerHistoryMap;
+  typedef std::map<short, FingerHistory> FingerHistoryMap;
   FingerHistoryMap histories_;
 
   // Device class (e.g. touchpad, mouse).
diff --git a/include/trend_classifying_filter_interpreter.h b/include/trend_classifying_filter_interpreter.h
index b2e8436..92ae3d2 100644
--- a/include/trend_classifying_filter_interpreter.h
+++ b/include/trend_classifying_filter_interpreter.h
@@ -2,17 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <map>
-#include <set>
 #include <gtest/gtest.h>  // for FRIEND_TEST
+#include <map>
 
 #include "include/filter_interpreter.h"
 #include "include/finger_metrics.h"
 #include "include/gestures.h"
-#include "include/list.h"
-#include "include/memory_manager.h"
 #include "include/prop_registry.h"
 #include "include/tracer.h"
+#include "include/util.h"
 
 #ifndef GESTURES_TREND_CLASSIFYING_FILTER_INTERPRETER_H_
 #define GESTURES_TREND_CLASSIFYING_FILTER_INTERPRETER_H_
@@ -151,12 +149,9 @@
           GESTURES_FINGER_TREND_DEC_TOUCH_MAJOR };
       return flags[idx];
     }
-
-    KState* next_;
-    KState* prev_;
   };
 
-  typedef MemoryManagedList<KState> FingerHistory;
+  typedef List<KState> FingerHistory;
 
   // Trend types for internal use
   enum TrendType {
@@ -169,7 +164,7 @@
   void UpdateFingerState(const HardwareState& hwstate);
 
   // Push new finger data into the buffer and update values
-  void AddNewStateToBuffer(FingerHistory* history, const FingerState& fs);
+  void AddNewStateToBuffer(FingerHistory& history, const FingerState& fs);
 
   // Assess statistical significance with a classic two-tail hypothesis test
   TrendType RunKTTest(const KState::KAxis* current, const size_t n_samples);
@@ -220,13 +215,9 @@
                            const unsigned flag_decreasing,
                            unsigned* flags);
 
-  // memory managers to prevent malloc during interrupt calls
-  MemoryManager<KState> kstate_mm_;
-  MemoryManager<FingerHistory> history_mm_;
-
   // A map to store each finger's past coordinates and calculation
   // intermediates
-  typedef std::map<short, FingerHistory*> FingerHistoryMap;
+  typedef std::map<short, FingerHistory> FingerHistoryMap;
   FingerHistoryMap histories_;
 
   // Flag to turn on/off the trend classifying filter
diff --git a/include/util.h b/include/util.h
index 2e87a7b..f0c2a39 100644
--- a/include/util.h
+++ b/include/util.h
@@ -5,6 +5,7 @@
 #ifndef GESTURES_UTIL_H_
 #define GESTURES_UTIL_H_
 
+#include <list>
 #include <map>
 #include <set>
 
@@ -61,28 +62,16 @@
 }
 
 // Removes any ids from the map that are not finger ids in hs.
-// This implementation supports returning removed elements for
-// further processing.
-template<typename Data>
-void RemoveMissingIdsFromMap(std::map<short, Data>* the_map,
-                             const HardwareState& hs,
-                             std::map<short, Data>* removed) {
-  removed->clear();
-  for (typename std::map<short, Data>::const_iterator it =
-      the_map->begin(); it != the_map->end(); ++it)
-    if (!hs.GetFingerState((*it).first))
-      (*removed)[it->first] = it->second;
-  for (typename std::map<short, Data>::const_iterator it =
-      removed->begin(); it != removed->end(); ++it)
-    the_map->erase(it->first);
-}
-
-// Removes any ids from the map that are not finger ids in hs.
 template<typename Data>
 void RemoveMissingIdsFromMap(std::map<short, Data>* the_map,
                              const HardwareState& hs) {
   std::map<short, Data> removed;
-  RemoveMissingIdsFromMap(the_map, hs, &removed);
+  for (const auto& [key, value] : *the_map) {
+    if (!hs.GetFingerState(key))
+      removed[key] = value;
+  }
+  for (const auto& [key, value] : removed)
+    the_map->erase(key);
 }
 
 // Removes any ids from the set that are not finger ids in hs.
@@ -105,6 +94,29 @@
   return the_set.find(elt) != the_set.end();
 }
 
+template<typename Elem>
+class List : public std::list<Elem> {
+public:
+  Elem& at(int offset) {
+    // Traverse to the appropriate offset
+    if (offset < 0) {
+      // negative offset is from end to begin
+      for (auto iter = this->rbegin(); iter != this->rend(); ++iter) {
+        if (++offset == 0)
+          return *iter;
+      }
+    } else {
+      // positive offset is from begin to end
+      for (auto iter = this->begin(); iter != this->end(); ++iter) {
+        if (offset-- == 0)
+          return *iter;
+      }
+    }
+    // Invalid offset
+    abort();
+  }
+};
+
 }  // namespace gestures
 
 #endif  // GESTURES_UTIL_H_
diff --git a/src/lookahead_filter_interpreter.cc b/src/lookahead_filter_interpreter.cc
index f60b0f5..fea2c47 100644
--- a/src/lookahead_filter_interpreter.cc
+++ b/src/lookahead_filter_interpreter.cc
@@ -19,12 +19,9 @@
 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",
@@ -48,43 +45,32 @@
 
 void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate,
                                                        stime_t* timeout) {
-  // Push back into queue
-  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 (const auto& element : queue_)
-      Err("Due: %f%s", element->due_, element->completed_ ? " (c)" : "");
-    return;
-  }
-  QState* node = free_list_.back();
-  free_list_.pop_back();
-  node->set_state(*hwstate);
+  // Keep track of where the last node is in the current queue_
+  auto const queue_was_not_empty = !queue_.empty();
+  QState* old_back_node = queue_was_not_empty ? &queue_.back() : nullptr;
+  // Allocate and initialize a new node on the end of the queue_
+  auto& new_node = queue_.emplace_back(hwprops_->max_finger_cnt);
+  new_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())
-    node->output_ids_.clear();
-  else
-    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_.back()->due_ - node->due_ > ExtraVariableDelay())) {
+  new_node.due_ = hwstate->timestamp + delay;
+  if (queue_was_not_empty)
+    new_node.output_ids_ = old_back_node->output_ids_;
+  // At this point, if ExtraVariableDelay() > 0, old_back_node.due_ may have
+  // ExtraVariableDelay() applied, but new_node.due_ does not, yet.
+  if (queue_was_not_empty &&
+      (old_back_node->due_ - new_node.due_ > ExtraVariableDelay())) {
     Err("Clock changed backwards. Flushing queue.");
     stime_t next_timeout = NO_DEADLINE;
     auto q_node_iter = queue_.begin();
     do {
-      if (!(*q_node_iter)->completed_)
-        next_->SyncInterpret(&(*q_node_iter)->state_, &next_timeout);
+      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());
+    } while (queue_.size() > 1);
     interpreter_due_ = -1.0;
     last_interpreted_time_ = -1.0;
   }
-  queue_.push_back(node);
   AssignTrackingIds();
   AttemptInterpolation();
   UpdateInterpreterDue(interpreter_due_ < 0.0 ?
@@ -93,10 +79,10 @@
   HandleTimerImpl(hwstate->timestamp, timeout);
 
   // Copy finger flags for upstream filters.
-  QState* q_node = queue_.front();
-  if (q_node->state_.SameFingersAs(*hwstate)) {
+  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;
+      hwstate->fingers[i].flags = q_node.state_.fingers[i].flags;
    }
   }
 }
@@ -148,27 +134,27 @@
     // 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_.back();
-      HardwareState* hs = &tail->state_;
+      QState& tail = queue_.back();
+      HardwareState* hs = &tail.state_;
       for (size_t i = 0; i < hs->finger_cnt; i++) {
         FingerState* fs = &hs->fingers[i];
-        tail->output_ids_[fs->tracking_id] = NextTrackingId();
-        fs->tracking_id = tail->output_ids_[fs->tracking_id];
+        tail.output_ids_[fs->tracking_id] = NextTrackingId();
+        fs->tracking_id = tail.output_ids_[fs->tracking_id];
       }
       if (hs->finger_cnt > 0)
-        tail->due_ += ExtraVariableDelay();
+        tail.due_ += ExtraVariableDelay();
     }
     return;
   }
 
-  auto tail = queue_.at(-1);
-  HardwareState* hs = &tail->state_;
-  QState* prev_qs = queue_.size() < 2 ? NULL : queue_.at(-2);
+  auto& tail = queue_.at(-1);
+  HardwareState* hs = &tail.state_;
+  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 : queue_.at(-3);
+  QState* prev2_qs = queue_.size() < 3 ? NULL : &(queue_.at(-3));
   HardwareState* prev2_hs = prev2_qs ? &prev2_qs->state_ : NULL;
 
-  RemoveMissingIdsFromMap(&tail->output_ids_, *hs);
+  RemoveMissingIdsFromMap(&tail.output_ids_, *hs);
   float dt = prev_hs ? hs->timestamp - prev_hs->timestamp : 1.0;
   float prev_dt =
       prev_hs && prev2_hs ? prev_hs->timestamp - prev2_hs->timestamp : 1.0;
@@ -191,11 +177,11 @@
     FingerState* fs = &hs->fingers[i];
     const short old_id = fs->tracking_id;
     bool new_finger = false;
-    if (!MapContainsKey(tail->output_ids_, fs->tracking_id)) {
-      tail->output_ids_[fs->tracking_id] = NextTrackingId();
+    if (!MapContainsKey(tail.output_ids_, fs->tracking_id)) {
+      tail.output_ids_[fs->tracking_id] = NextTrackingId();
       new_finger_present = new_finger = true;
     }
-    fs->tracking_id = tail->output_ids_[fs->tracking_id];
+    fs->tracking_id = tail.output_ids_[fs->tracking_id];
     if (new_finger)
       continue;
     if (!prev_hs) {
@@ -244,8 +230,8 @@
         if (prev_qs->output_ids_[old_id] != prev2_qs->output_ids_[old_id]) {
           prev_qs->output_ids_[old_id] = prev2_qs->output_ids_[old_id];
           prev_fs->tracking_id = prev_qs->output_ids_[old_id];
-          tail->output_ids_[old_id] = prev2_qs->output_ids_[old_id];
-          fs->tracking_id = tail->output_ids_[old_id];
+          tail.output_ids_[old_id] = prev2_qs->output_ids_[old_id];
+          fs->tracking_id = tail.output_ids_[old_id];
           continue;
         }
       }
@@ -274,7 +260,7 @@
         continue;
       }
       separated_fingers.insert(old_id);
-      SeparateFinger(tail, fs, old_id);
+      SeparateFinger(&tail, fs, old_id);
       // Separating fingers shouldn't tap.
       fs->flags |= GESTURES_FINGER_NO_TAP;
       // Try to also flag the previous frame, if we didn't execute it yet
@@ -303,10 +289,10 @@
         Err("How is input ID missing from prev state? %d", input_id);
         continue;
       }
-      short new_bad_output_id = tail->output_ids_[input_id];
+      short new_bad_output_id = tail.output_ids_[input_id];
       short prev_output_id = prev_qs->output_ids_[input_id];
-      tail->output_ids_[input_id] = prev_output_id;
-      FingerState* fs = tail->state_.GetFingerState(new_bad_output_id);
+      tail.output_ids_[input_id] = prev_output_id;
+      FingerState* fs = tail.state_.GetFingerState(new_bad_output_id);
       if (!fs) {
         Err("Can't find finger state.");
         continue;
@@ -321,7 +307,7 @@
        LiftoffJumpStarting(*hs, *prev_hs, *prev2_hs))) {
     // Possibly add some extra delay to correct, incase this separation
     // shouldn't have occurred or if the finger may be lifting from the pad.
-    tail->due_ += ExtraVariableDelay();
+    tail.due_ += ExtraVariableDelay();
   }
 }
 
@@ -361,12 +347,12 @@
     return;
   if (queue_.size() < 2)
     return;  // Not enough data to know
-  HardwareState& hs = queue_.back()->state_;
-  if (queue_.back()->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.
   // Get the state_ of back->prev
-  HardwareState& prev_hs = queue_.at(-2)->state_;
+  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,
@@ -402,33 +388,25 @@
 void LookaheadFilterInterpreter::AttemptInterpolation() {
   if (queue_.size() < 2)
     return;
-  QState* new_node = queue_.at(-1);
-  QState* prev = queue_.at(-2);
-  if (new_node->state_.timestamp - prev->state_.timestamp <
+  QState& new_node = queue_.at(-1);
+  QState& prev = queue_.at(-2);
+  if (new_node.state_.timestamp - prev.state_.timestamp <
       split_min_period_.val_) {
     return;  // Nodes came in too quickly to need interpolation
   }
-  if (!prev->state_.SameFingersAs(new_node->state_))
+  if (!prev.state_.SameFingersAs(new_node.state_))
     return;
-  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_);
+  auto node = QState(hwprops_->max_finger_cnt);
+  node.state_.fingers = node.fs_.get();
+  node.completed_ = false;
+  Interpolate(prev.state_, new_node.state_, &node.state_);
 
   double delay = max(0.0, min<stime_t>(kMaxDelay, min_delay_.val_));
-  node->due_ = node->state_.timestamp + delay;
+  node.due_ = node.state_.timestamp + delay;
 
-  if (node->state_.timestamp <= last_interpreted_time_) {
-    // Time wouldn't seem monotonically increasing w/ this new event, so
-    // discard it.
-    free_list_.push_back(node);
-  } else {
-    queue_.insert(--queue_.end(), node);
+  // Make sure time seems monotonically increasing w/ this new event
+  if (node.state_.timestamp > last_interpreted_time_) {
+    queue_.insert(--queue_.end(), std::move(node));
   }
 }
 
@@ -450,10 +428,10 @@
       if (queue_.empty())
         break;
       // Get next uncompleted and overdue hwstate
-      auto node = queue_.back();
-      for (auto state : queue_) {
-        if (!state->completed_) {
-          node = state;
+      auto node = &queue_.back();
+      for (auto& elem : queue_) {
+        if (!elem.completed_) {
+          node = &elem;
           break;
         }
       }
@@ -482,8 +460,7 @@
       next_->SyncInterpret(&hs_copy, &next_timeout);
 
       // Clear previously completed nodes, but keep at least two nodes.
-      while (queue_.size() > 2 && queue_.front()->completed_) {
-        free_list_.push_back(queue_.front());
+      while (queue_.size() > 2 && queue_.front().completed_) {
         queue_.pop_front();
       }
 
@@ -502,7 +479,7 @@
 }
 
 void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) {
-  QState* node = queue_.front();
+  QState& node = queue_.front();
 
   float distance_sq = 0.0;
   // Slow movements should potentially be suppressed
@@ -530,8 +507,8 @@
   }
   // Speed is slow. Suppress if fingers have changed.
   for (auto iter = ++queue_.begin(); iter != queue_.end(); ++iter) {
-    if (!node->state_.SameFingersAs((*iter)->state_) ||
-        (node->state_.buttons_down != (*iter)->state_.buttons_down))
+    if (!node.state_.SameFingersAs((*iter).state_) ||
+        (node.state_.buttons_down != (*iter).state_.buttons_down))
       return; // suppress
   }
 
@@ -546,10 +523,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 (auto elem : queue_) {
-    if (elem->completed_)
+  for (auto& elem : queue_) {
+    if (elem.completed_)
       continue;
-    next_hwstate_timeout = elem->due_ - now;
+    next_hwstate_timeout = elem.due_ - now;
     break;
   }
 
@@ -571,11 +548,6 @@
     GestureConsumer* consumer) {
   FilterInterpreter::Initialize(hwprops, NULL, mprops, consumer);
   queue_.clear();
-  free_list_.clear();
-  for (size_t i = 0; i < kMaxQNodes; ++i) {
-    QState* node = new QState(hwprops_->max_finger_cnt);
-    free_list_.push_back(node);
-  }
 }
 
 stime_t LookaheadFilterInterpreter::ExtraVariableDelay() const {
@@ -583,13 +555,13 @@
 }
 
 LookaheadFilterInterpreter::QState::QState()
-    : max_fingers_(0), completed_(false), next_(NULL), prev_(NULL) {
+    : max_fingers_(0) {
   fs_.reset();
   state_.fingers = NULL;
 }
 
 LookaheadFilterInterpreter::QState::QState(unsigned short max_fingers)
-    : max_fingers_(max_fingers), completed_(false), next_(NULL), prev_(NULL) {
+    : max_fingers_(max_fingers) {
   fs_.reset(new FingerState[max_fingers]);
   state_.fingers = fs_.get();
 }
@@ -615,25 +587,4 @@
   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 1c84eb4..1345daf 100644
--- a/src/lookahead_filter_interpreter_unittest.cc
+++ b/src/lookahead_filter_interpreter_unittest.cc
@@ -175,7 +175,7 @@
       if (newtimeout < 0.0)
         EXPECT_DOUBLE_EQ(NO_DEADLINE, newtimeout);
       if (i == 5) {
-        EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
+        EXPECT_EQ(nullptr, out);
       } else {
         // Expect movement
         ASSERT_TRUE(out);
@@ -389,19 +389,19 @@
 
   stime_t timeout = NO_DEADLINE;
   Gesture* out = wrapper.SyncInterpret(&hs, &timeout);
-  EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
+  EXPECT_EQ(nullptr, out);
   EXPECT_FLOAT_EQ(interpreter->min_delay_.val_, timeout);
 
   out = wrapper.HandleTimer(hs.timestamp + interpreter->min_delay_.val_,
                                  &timeout);
-  EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
+  EXPECT_EQ(nullptr, out);
   EXPECT_FLOAT_EQ(1.0, timeout);
 
 
   out = wrapper.HandleTimer(hs.timestamp + interpreter->min_delay_.val_ +
                                  0.25,
                                  &timeout);
-  EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
+  EXPECT_EQ(nullptr, out);
   EXPECT_FLOAT_EQ(0.75, timeout);
 }
 
@@ -640,20 +640,20 @@
 
   stime_t timeout = NO_DEADLINE;
   Gesture* out = wrapper.SyncInterpret(&hs[0], &timeout);
-  EXPECT_EQ(reinterpret_cast<Gesture*>(NULL), out);
+  EXPECT_EQ(nullptr, out);
   EXPECT_FLOAT_EQ(timeout, interpreter->min_delay_.val_);
 
   stime_t now = hs[0].timestamp + timeout;
   timeout = NO_DEADLINE;
   out = wrapper.HandleTimer(now, &timeout);
-  ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
+  ASSERT_NE(nullptr, out);
   EXPECT_EQ(kGestureTypeMove, out->type);
   EXPECT_EQ(1, out->details.move.dy);
   EXPECT_DOUBLE_EQ(timeout, 0.700);
 
   timeout = NO_DEADLINE;
   out = wrapper.SyncInterpret(&hs[1], &timeout);
-  ASSERT_NE(reinterpret_cast<Gesture*>(NULL), out);
+  ASSERT_NE(nullptr, out);
   EXPECT_EQ(kGestureTypeMove, out->type);
   EXPECT_EQ(2, out->details.move.dy);
   EXPECT_GE(timeout, 0.0);
@@ -793,17 +793,17 @@
   // Pushing the first event
   wrapper.SyncInterpret(&hs[0], &timeout);
   EXPECT_EQ(queue.size(), 1);
-  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 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.back()->fs_[0].tracking_id, 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.back()->fs_[0].tracking_id, 3);
+  EXPECT_EQ(queue.back().fs_[0].tracking_id, 3);
 
   // Removing the touch.
   wrapper.SyncInterpret(&hs[3], &timeout);
@@ -813,17 +813,17 @@
   // New finger tracking ID assigned 2 - > 4.
   wrapper.SyncInterpret(&hs[4], &timeout);
   EXPECT_EQ(queue.size(), 2);
-  EXPECT_EQ(queue.back()->fs_[0].tracking_id, 4);
+  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.back()->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(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);
+  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 {
@@ -1266,76 +1266,14 @@
   const auto& queue = interpreter->queue_;
 
   wrapper.SyncInterpret(&hs[0], &timeout);
-  EXPECT_EQ(queue.back()->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.back()->fs_[0].tracking_id, 20);  // the same input id
-    EXPECT_EQ(queue.back()->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 de6ca33..a19b814 100644
--- a/src/metrics_filter_interpreter.cc
+++ b/src/metrics_filter_interpreter.cc
@@ -22,8 +22,6 @@
     Tracer* tracer,
     GestureInterpreterDeviceClass devclass)
     : FilterInterpreter(NULL, next, tracer, false),
-      mstate_mm_(kMaxFingers * MState::MaxHistorySize()),
-      history_mm_(kMaxFingers),
       devclass_(devclass),
       mouse_movement_session_index_(0),
       mouse_movement_current_session_length(0),
@@ -44,7 +42,7 @@
 }
 
 void MetricsFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate,
-                                                   stime_t* timeout) {
+                                                 stime_t* timeout) {
   if (devclass_ == GESTURES_DEVCLASS_TOUCHPAD) {
     // Right now, we only want to update finger states for built-in touchpads
     // because all the generated metrics gestures would be put under each
@@ -66,22 +64,16 @@
   next_->SyncInterpret(hwstate, timeout);
 }
 
-template <class StateType, class DataType>
 void MetricsFilterInterpreter::AddNewStateToBuffer(
-    MemoryManagedList<StateType>* history,
-    const DataType& data,
+    FingerHistory& history,
+    const FingerState& data,
     const HardwareState& hwstate) {
   // The history buffer is already full, pop one
-  if (history->size() == StateType::MaxHistorySize())
-    history->DeleteFront();
+  if (history.size() == MState::MaxHistorySize())
+    history.pop_front();
 
   // Push the new finger state to the back of buffer
-  StateType* current = history->PushNewEltBack();
-  if (!current) {
-    Err("MetricsFilterInterpreter buffer out of space");
-    return;
-  }
-  current->Init(data, hwstate);
+  (void)history.emplace_back(data, hwstate);
 }
 
 void MetricsFilterInterpreter::UpdateMouseMovementState(
@@ -138,68 +130,48 @@
 
 void MetricsFilterInterpreter::UpdateFingerState(
     const HardwareState& hwstate) {
-  FingerHistoryMap removed;
-  RemoveMissingIdsFromMap(&histories_, hwstate, &removed);
-  for (FingerHistoryMap::const_iterator it =
-       removed.begin(); it != removed.end(); ++it) {
-    it->second->clear();
-    history_mm_.Free(it->second);
-}
+  RemoveMissingIdsFromMap(&histories_, hwstate);
 
   FingerState *fs = hwstate.fingers;
   for (short i = 0; i < hwstate.finger_cnt; i++) {
-    FingerHistory* hp;
-
     // Update the map if the contact is new
     if (!MapContainsKey(histories_, fs[i].tracking_id)) {
-      hp = history_mm_.Allocate();
-      if (!hp) {
-        Err("FingerHistory out of space");
-        continue;
-      }
-      hp->Init(&mstate_mm_);
-      histories_[fs[i].tracking_id] = hp;
-    } else {
-      hp = histories_[fs[i].tracking_id];
+      histories_[fs[i].tracking_id] = FingerHistory{};
     }
+    auto& href = histories_[fs[i].tracking_id];
 
     // Check if the finger history contains interesting patterns
-    AddNewStateToBuffer(hp, fs[i], hwstate);
-    DetectNoisyGround(hp);
+    AddNewStateToBuffer(href, fs[i], hwstate);
+    DetectNoisyGround(href);
   }
 }
 
-bool MetricsFilterInterpreter::DetectNoisyGround(
-    const FingerHistory* history) {
-  auto iter = history->end();
-  MState* current = *(--iter);
-  size_t n_samples = history->size();
+bool MetricsFilterInterpreter::DetectNoisyGround(FingerHistory& history) {
   // Noise pattern takes 3 samples
-  if (n_samples < 3)
+  if (history.size() < 3)
     return false;
 
-  MState* past_1 = *(--iter);
-  MState* past_2 = *(--iter);
+  auto current = history.at(-1);
+  auto past_1 = history.at(-2);
+  auto past_2 = history.at(-3);
   // Noise pattern needs to happen in a short period of time
-  if(current->timestamp - past_2->timestamp >
-      noisy_ground_time_threshold_.val_) {
+  if (current.timestamp - past_2.timestamp > noisy_ground_time_threshold_.val_)
     return false;
-  }
 
   // vec[when][x,y]
   float vec[2][2];
-  vec[0][0] = current->data.position_x - past_1->data.position_x;
-  vec[0][1] = current->data.position_y - past_1->data.position_y;
-  vec[1][0] = past_1->data.position_x - past_2->data.position_x;
-  vec[1][1] = past_1->data.position_y - past_2->data.position_y;
+  vec[0][0] = current.data.position_x - past_1.data.position_x;
+  vec[0][1] = current.data.position_y - past_1.data.position_y;
+  vec[1][0] = past_1.data.position_x - past_2.data.position_x;
+  vec[1][1] = past_1.data.position_y - past_2.data.position_y;
   const float thr = noisy_ground_distance_threshold_.val_;
   // We dictate the noise pattern as two consecutive big moves in
   // opposite directions in either X or Y
   for (size_t i = 0; i < arraysize(vec[0]); i++)
     if ((vec[0][i] < -thr && vec[1][i] > thr) ||
         (vec[0][i] > thr && vec[1][i] < -thr)) {
-      ProduceGesture(Gesture(kGestureMetrics, past_2->timestamp,
-                     current->timestamp, kGestureMetricsTypeNoisyGround,
+      ProduceGesture(Gesture(kGestureMetrics, past_2.timestamp,
+                     current.timestamp, kGestureMetricsTypeNoisyGround,
                      vec[0][i], vec[1][i]));
       return true;
     }
diff --git a/src/trend_classifying_filter_interpreter.cc b/src/trend_classifying_filter_interpreter.cc
index d6ddd21..714cb68 100644
--- a/src/trend_classifying_filter_interpreter.cc
+++ b/src/trend_classifying_filter_interpreter.cc
@@ -30,8 +30,6 @@
 TrendClassifyingFilterInterpreter::TrendClassifyingFilterInterpreter(
     PropRegistry* prop_reg, Interpreter* next, Tracer* tracer)
     : FilterInterpreter(NULL, next, tracer, false),
-      kstate_mm_(kMaxFingers * kNumOfSamples),
-      history_mm_(kMaxFingers),
       trend_classifying_filter_enable_(
           prop_reg, "Trend Classifying Filter Enabled", true),
       second_order_enable_(
@@ -72,37 +70,32 @@
 }
 
 void TrendClassifyingFilterInterpreter::AddNewStateToBuffer(
-    FingerHistory* history, const FingerState& fs) {
+    FingerHistory& history, const FingerState& fs) {
   // The history buffer is already full, pop one
-  if (history->size() == static_cast<size_t>(num_of_samples_.val_))
-    history->DeleteFront();
+  if (history.size() == static_cast<size_t>(num_of_samples_.val_))
+    history.pop_front();
 
   // Push the new finger state to the back of buffer
-  KState* previous_end = history->back();
-  KState* current = history->PushNewEltBack();
-  if (!current) {
-    Err("KState buffer out of space");
+  auto& current = history.emplace_back(fs);
+  if (history.size() == 1)
     return;
-  }
-  current->Init(fs);
-  if (history->size() == 1)
-    return;
+  auto& previous_end = history.at(-2);
 
-  current->DxAxis()->val = current->XAxis()->val - previous_end->XAxis()->val;
-  current->DyAxis()->val = current->YAxis()->val - previous_end->YAxis()->val;
+  current.DxAxis()->val = current.XAxis()->val - previous_end.XAxis()->val;
+  current.DyAxis()->val = current.YAxis()->val - previous_end.YAxis()->val;
   // Update the nodes already in the buffer and compute the Kendall score/
   // 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 (auto it = history->begin(); it != history->end(); ++it)
+  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();
+  size_t n_samples = history.size();
   for (size_t i = 0; i < KState::n_axes_; i++) {
-    current->axes_[i].var = ComputeKTVariance(tie_n2[i], tie_n3[i],
+    current.axes_[i].var = ComputeKTVariance(tie_n2[i], tie_n3[i],
         KState::IsDelta(i) ? n_samples - 1 : n_samples);
   }
 }
@@ -132,38 +125,23 @@
 
 void TrendClassifyingFilterInterpreter::UpdateFingerState(
     const HardwareState& hwstate) {
-  FingerHistoryMap removed;
-  RemoveMissingIdsFromMap(&histories_, hwstate, &removed);
-  for (FingerHistoryMap::const_iterator it =
-       removed.begin(); it != removed.end(); ++it) {
-    it->second->clear();
-    history_mm_.Free(it->second);
-  }
+  RemoveMissingIdsFromMap(&histories_, hwstate);
 
-  FingerState *fs = hwstate.fingers;
+  FingerState* fs = hwstate.fingers;
   for (short i = 0; i < hwstate.finger_cnt; i++) {
-    FingerHistory* hp;
-
     // Update the map if the contact is new
     if (!MapContainsKey(histories_, fs[i].tracking_id)) {
-      hp = history_mm_.Allocate();
-      if (!hp) {
-        Err("FingerHistory out of space");
-        continue;
-      }
-      hp->Init(&kstate_mm_);
-      histories_[fs[i].tracking_id] = hp;
-    } else {
-      hp = histories_[fs[i].tracking_id];
+      histories_[fs[i].tracking_id] = FingerHistory{};
     }
+    auto& history = histories_[fs[i].tracking_id];
 
     // Check if the score demonstrates statistical significance
-    AddNewStateToBuffer(hp, fs[i]);
-    KState* current = hp->back();
-    size_t n_samples = hp->size();
+    AddNewStateToBuffer(history, fs[i]);
+    const auto& current = history.back();
+    const size_t n_samples = history.size();
     for (size_t idx = 0; idx < KState::n_axes_; idx++)
       if (second_order_enable_.val_ || !KState::IsDelta(idx)) {
-        TrendType result = RunKTTest(&current->axes_[idx],
+        TrendType result = RunKTTest(&current.axes_[idx],
             KState::IsDelta(idx) ? n_samples - 1 : n_samples);
         InterpretTestResult(result, KState::IncFlag(idx),
             KState::DecFlag(idx), &(fs[i].flags));
diff --git a/src/util_unittest.cc b/src/util_unittest.cc
index 5d0a435..f19fe1f 100644
--- a/src/util_unittest.cc
+++ b/src/util_unittest.cc
@@ -21,4 +21,51 @@
   EXPECT_FLOAT_EQ(DistSqXY(fs[0], 4, 6), 25);
 }
 
+TEST(UtilTest, ListAtTest) {
+  const int kMaxElements = 3;
+  struct element {
+    int x;
+  };
+
+  List<element> list;
+
+  for (auto i = 0; i < kMaxElements; ++i) {
+    auto& elem = list.emplace_back();
+    elem.x = i;
+  }
+  EXPECT_EQ(list.at(-1).x, list.at(list.size() - 1).x);
+
+  for (auto i = 0; i < kMaxElements; ++i) {
+    for (auto j = 0; j < kMaxElements; ++j) {
+      if (i == j) {
+        EXPECT_EQ(list.at(i).x, list.at(j).x);
+        EXPECT_EQ(&(list.at(i)), &(list.at(j)));
+      } else {
+        EXPECT_NE(list.at(i).x, list.at(j).x);
+        EXPECT_NE(&(list.at(i)), &(list.at(j)));
+      }
+    }
+  }
+}
+
+TEST(UtilTest, ListAtDeathForwardTest) {
+  List<int> list;
+  const int kMaxElements = 3;
+
+  for (auto i = 0; i < kMaxElements; ++i) {
+    list.emplace_back(i);
+  }
+  EXPECT_DEATH(list.at(kMaxElements+1), "");
+}
+
+TEST(UtilTest, ListAtDeathBackwardTest) {
+  List<int> list;
+  const int kMaxElements = 3;
+
+  for (auto i = 0; i < kMaxElements; ++i) {
+    list.emplace_back(i);
+  }
+  EXPECT_DEATH(list.at(-(kMaxElements+1)), "");
+}
+
 }  // namespace gestures
diff --git a/tools/tplog.py b/tools/tplog.py
index 3ede9b7..7df13f8 100755
--- a/tools/tplog.py
+++ b/tools/tplog.py
@@ -8,9 +8,9 @@
 
 
 import getopt
+import json
 import logging
 import os
-import simplejson as json
 import sys
 
 from operator import ge, lt