Snap for 10103804 from 781b8df8fa3b02c22baf0b9e80c164c7e84e84a5 to mainline-tzdata5-release

Change-Id: I48363bd338bc2daf28cbd32ee9f96a8546f4d471
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/METADATA.android b/METADATA.android
index 00233ca..f12b10f 100644
--- a/METADATA.android
+++ b/METADATA.android
@@ -6,7 +6,7 @@
     type: GIT
     value: "https://chromium.googlesource.com/chromiumos/platform/gestures/"
   }
-  version: "3059225019e295de1138574a16c0102c6845fefb"
-  last_upgrade_date { year: 2023 month: 02 day: 27  }
+  version: "b6ae21cf67acbc76254be3677264b0ea472fce09"
+  last_upgrade_date { year: 2023 month: 04 day: 05  }
   license_type: NOTICE
 }
diff --git a/Makefile b/Makefile
index c6165e9..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 \
@@ -112,7 +111,7 @@
 
 CXXFLAGS+=\
 	-g \
-	-std=gnu++11 \
+	-std=gnu++17 \
 	-fno-exceptions \
 	-fno-strict-aliasing \
 	-fPIC \
diff --git a/include/gestures.h b/include/gestures.h
index e4f7cc2..f3005a0 100644
--- a/include/gestures.h
+++ b/include/gestures.h
@@ -55,7 +55,8 @@
   float right;
   // The maximum Y coordinate that the device can report.
   float bottom;
-  // The resolutions of the X and Y axes, in units per mm.
+  // The resolutions of the X and Y axes, in units per mm. Set to 0 if the
+  // resolution is unknown.
   float res_x;
   float res_y;
 
@@ -105,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,
@@ -167,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
@@ -228,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 d5d94c4..0000000
--- a/include/list.h
+++ /dev/null
@@ -1,138 +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 "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 {
- 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(); }
-
-  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);
-    return elt;
-  }
-
-  Elt* PushNewEltFront() {
-    AssertWithReturnValue(memory_manager_, NULL);
-    Elt* elt = NewElt();
-    AssertWithReturnValue(elt, NULL);
-    PushFront(elt);
-    return elt;
-  }
-
-  void DeleteFront() {
-    AssertWithReturn(memory_manager_);
-    memory_manager_->Free(PopFront());
-  }
-
-  void DeleteBack() {
-    AssertWithReturn(memory_manager_);
-    memory_manager_->Free(PopBack());
-  }
-
-  virtual void DeleteAll() {
-    while (!Empty())
-      DeleteFront();
-  }
- private:
-  MemoryManager<Elt>* memory_manager_;
-};
-
-
-}  // namespace gestures
-
-#endif  // GESTURES_LIST_H__
diff --git a/include/lookahead_filter_interpreter.h b/include/lookahead_filter_interpreter.h
index 33dcc9b..2658daa 100644
--- a/include/lookahead_filter_interpreter.h
+++ b/include/lookahead_filter_interpreter.h
@@ -11,9 +11,9 @@
 #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"
+#include "include/util.h"
 
 #ifndef GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_
 #define GESTURES_LOOKAHEAD_FILTER_INTERPRETER_H_
@@ -33,6 +33,7 @@
   FRIEND_TEST(LookaheadFilterInterpreterTest, SimpleTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest);
   FRIEND_TEST(LookaheadFilterInterpreterTest, VariableDelayTest);
+
  public:
   LookaheadFilterInterpreter(PropRegistry* prop_reg, Interpreter* next,
                              Tracer* tracer);
@@ -62,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();
@@ -109,7 +107,6 @@
   stime_t ExtraVariableDelay() const;
 
   List<QState> queue_;
-  List<QState> free_list_;
 
   // 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/prop_registry.h b/include/prop_registry.h
index 836b98b..4545a33 100644
--- a/include/prop_registry.h
+++ b/include/prop_registry.h
@@ -46,9 +46,8 @@
 
 class Property {
  public:
-  Property(PropRegistry* parent, const char* name,
-           PropertyDelegate* delegate)
-      : gprop_(NULL), parent_(parent), delegate_(delegate), name_(name) {}
+  Property(PropRegistry* parent, const char* name)
+      : parent_(parent), name_(name) {}
 
   virtual ~Property() {
     if (parent_)
@@ -59,18 +58,9 @@
   virtual void CreatePropImpl() = 0;
   void DestroyProp();
 
-  // b/253585974
-  // delegate used to get passed as a constructor parameter but that
-  // led to a chance that the delegate was 'this' and setting the
-  // delegate to 'this' in the initializer list allowed the property
-  // creation to use 'this' before it was initialized.  This could
-  // lead to unexpected behavior and if you were lucky to a crash.
-  //
-  // Now the delegate is always NULL on initilization of the property
-  // instance and after the delegate and property are completely
-  // created the user should set the delegate in the constructor
-  // body. This will allow access to this in a safe manner.
-  void SetDelegate(PropertyDelegate* delegate);
+  void SetDelegate(PropertyDelegate* delegate) {
+    delegate_ = delegate;
+  }
 
   const char* name() { return name_; }
   // Returns a newly allocated Value object
@@ -91,9 +81,9 @@
   virtual void HandleGesturesPropWritten() = 0;
 
  protected:
-  GesturesProp* gprop_;
+  GesturesProp* gprop_ = NULL;
   PropRegistry* parent_;
-  PropertyDelegate* delegate_;
+  PropertyDelegate* delegate_ = NULL;
 
  private:
   const char* name_;
@@ -101,9 +91,8 @@
 
 class BoolProperty : public Property {
  public:
-  BoolProperty(PropRegistry* reg, const char* name, GesturesPropBool val,
-               PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), val_(val) {
+  BoolProperty(PropRegistry* reg, const char* name, GesturesPropBool val)
+      : Property(reg, name), val_(val) {
     if (parent_)
       parent_->Register(this);
   }
@@ -118,8 +107,8 @@
 class BoolArrayProperty : public Property {
  public:
   BoolArrayProperty(PropRegistry* reg, const char* name, GesturesPropBool* vals,
-                    size_t count, PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), vals_(vals), count_(count) {
+                    size_t count)
+      : Property(reg, name), vals_(vals), count_(count) {
     if (parent_)
       parent_->Register(this);
   }
@@ -134,9 +123,8 @@
 
 class DoubleProperty : public Property {
  public:
-  DoubleProperty(PropRegistry* reg, const char* name, double val,
-                 PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), val_(val) {
+  DoubleProperty(PropRegistry* reg, const char* name, double val)
+      : Property(reg, name), val_(val) {
     if (parent_)
       parent_->Register(this);
   }
@@ -151,8 +139,8 @@
 class DoubleArrayProperty : public Property {
  public:
   DoubleArrayProperty(PropRegistry* reg, const char* name, double* vals,
-                      size_t count, PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), vals_(vals), count_(count) {
+                      size_t count)
+      : Property(reg, name), vals_(vals), count_(count) {
     if (parent_)
       parent_->Register(this);
   }
@@ -167,9 +155,8 @@
 
 class IntProperty : public Property {
  public:
-  IntProperty(PropRegistry* reg, const char* name, int val,
-              PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), val_(val) {
+  IntProperty(PropRegistry* reg, const char* name, int val)
+      : Property(reg, name), val_(val) {
     if (parent_)
       parent_->Register(this);
   }
@@ -183,9 +170,9 @@
 
 class IntArrayProperty : public Property {
  public:
-  IntArrayProperty(PropRegistry* reg, const char* name, int* vals, size_t count,
-                   PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), vals_(vals), count_(count) {
+  IntArrayProperty(PropRegistry* reg, const char* name, int* vals,
+                   size_t count)
+      : Property(reg, name), vals_(vals), count_(count) {
     if (parent_)
       parent_->Register(this);
   }
@@ -200,9 +187,8 @@
 
 class StringProperty : public Property {
  public:
-  StringProperty(PropRegistry* reg, const char* name, const char* val,
-                 PropertyDelegate* delegate = NULL)
-      : Property(reg, name, delegate), val_(val) {
+  StringProperty(PropRegistry* reg, const char* name, const char* val)
+      : Property(reg, name), val_(val) {
     if (parent_)
       parent_->Register(this);
   }
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/iir_filter_interpreter.cc b/src/iir_filter_interpreter.cc
index 0558ef6..042e0f5 100644
--- a/src/iir_filter_interpreter.cc
+++ b/src/iir_filter_interpreter.cc
@@ -41,6 +41,7 @@
       a2_(prop_reg, "IIR a2", 0.412801598096189),
       iir_dist_thresh_(prop_reg, "IIR Distance Threshold", 10),
       adjust_iir_on_warp_(prop_reg, "Adjust IIR History On Warp", false) {
+  InitName();
   b0_.SetDelegate(this);
   b1_.SetDelegate(this);
   b2_.SetDelegate(this);
@@ -48,7 +49,6 @@
   a1_.SetDelegate(this);
   a2_.SetDelegate(this);
   iir_dist_thresh_.SetDelegate(this);
-  InitName();
 }
 
 void IirFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate,
diff --git a/src/immediate_interpreter.cc b/src/immediate_interpreter.cc
index 70369eb..7af423c 100644
--- a/src/immediate_interpreter.cc
+++ b/src/immediate_interpreter.cc
@@ -1095,7 +1095,7 @@
       keyboard_touched_timeval_high_(prop_reg, "Keyboard Touched Timeval High",
                                      0),
       keyboard_touched_timeval_low_(prop_reg, "Keyboard Touched Timeval Low",
-                                    0, this),
+                                    0),
       keyboard_palm_prevent_timeout_(prop_reg, "Keyboard Palm Prevent Timeout",
                                      0.5),
       motion_tap_prevent_timeout_(prop_reg, "Motion Tap Prevent Timeout",
@@ -1136,6 +1136,7 @@
       quick_acceleration_factor_(prop_reg, "Quick Acceleration Factor", 0.0) {
   InitName();
   requires_metrics_ = true;
+  keyboard_touched_timeval_low_.SetDelegate(this);
 }
 
 void ImmediateInterpreter::SyncInterpretImpl(HardwareState* hwstate,
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/logging_filter_interpreter.cc b/src/logging_filter_interpreter.cc
index d504607..2c43238 100644
--- a/src/logging_filter_interpreter.cc
+++ b/src/logging_filter_interpreter.cc
@@ -17,15 +17,19 @@
                                                    Interpreter* next,
                                                    Tracer* tracer)
     : FilterInterpreter(prop_reg, next, tracer, true),
-      event_logging_enable_(prop_reg, "Event Logging Enable", false, this),
-      logging_notify_(prop_reg, "Logging Notify", 0, this),
-      logging_reset_(prop_reg, "Logging Reset", 0, this),
+      event_logging_enable_(prop_reg, "Event Logging Enable", false),
+      logging_notify_(prop_reg, "Logging Notify", 0),
+      logging_reset_(prop_reg, "Logging Reset", 0),
       log_location_(prop_reg, "Log Path",
                     "/var/log/xorg/touchpad_activity_log.txt"),
       integrated_touchpad_(prop_reg, "Integrated Touchpad", false) {
   InitName();
   if (prop_reg && log_.get())
     prop_reg->set_activity_log(log_.get());
+  event_logging_enable_.SetDelegate(this);
+  BoolWasWritten(&event_logging_enable_);
+  logging_notify_.SetDelegate(this);
+  logging_reset_.SetDelegate(this);
 }
 
 void LoggingFilterInterpreter::IntWasWritten(IntProperty* prop) {
diff --git a/src/lookahead_filter_interpreter.cc b/src/lookahead_filter_interpreter.cc
index f7abaf5..fea2c47 100644
--- a/src/lookahead_filter_interpreter.cc
+++ b/src/lookahead_filter_interpreter.cc
@@ -45,41 +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 (QState* it = queue_.Begin(); it != queue_.End(); it = it->next_)
-      Err("Due: %f%s", it->due_, it->completed_ ? " (c)" : "");
-    return;
-  }
-  QState* node = free_list_.PopFront();
-  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_.Tail()->output_ids_;
-  // At this point, if ExtraVariableDelay() > 0, queue_.Tail()->due_ may have
-  // ExtraVariableDelay() applied, but node->due_ does not, yet.
-  if (!queue_.Empty() &&
-      (queue_.Tail()->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;
-    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;
+      queue_.pop_front();
+    } while (queue_.size() > 1);
     interpreter_due_ = -1.0;
     last_interpreted_time_ = -1.0;
   }
-  queue_.PushBack(node);
   AssignTrackingIds();
   AttemptInterpolation();
   UpdateInterpreterDue(interpreter_due_ < 0.0 ?
@@ -88,10 +79,10 @@
   HandleTimerImpl(hwstate->timestamp, timeout);
 
   // Copy finger flags for upstream filters.
-  QState* q_node = queue_.Head();
-  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;
    }
   }
 }
@@ -143,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_.Tail();
-      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;
   }
 
-  QState* tail = queue_.Tail();
-  HardwareState* hs = &tail->state_;
-  QState* prev_qs = queue_.size() < 2 ? NULL : tail->prev_;
+  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 : 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);
+  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;
@@ -186,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) {
@@ -239,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;
         }
       }
@@ -269,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
@@ -298,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;
@@ -316,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();
   }
 }
 
@@ -356,11 +347,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,33 +388,26 @@
 void LookaheadFilterInterpreter::AttemptInterpolation() {
   if (queue_.size() < 2)
     return;
-  QState* new_node = queue_.Tail();
-  QState* prev = new_node->prev_;
-  if (new_node->state_.timestamp - prev->state_.timestamp <
-      split_min_period_.val_)
+  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_))
-    return;
-  QState* node = free_list_.PopFront();
-  if (!node) {
-    Err("out of nodes?");
-    return;
   }
-  node->state_.fingers = node->fs_.get();
-  node->completed_ = false;
-  Interpolate(prev->state_, new_node->state_, &node->state_);
+  if (!prev.state_.SameFingersAs(new_node.state_))
+    return;
+  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_.PushBack(node);
-    return;
+  // Make sure time seems monotonically increasing w/ this new event
+  if (node.state_.timestamp > last_interpreted_time_) {
+    queue_.insert(--queue_.end(), std::move(node));
   }
-
-  queue_.InsertBefore(new_node, node);
 }
 
 void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now,
@@ -440,12 +425,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& elem : queue_) {
+        if (!elem.completed_) {
+          node = &elem;
+          break;
+        }
+      }
       if (node->completed_ || node->due_ > now)
         break;
       next_timeout = NO_DEADLINE;
@@ -471,8 +460,9 @@
       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_) {
+        queue_.pop_front();
+      }
 
       // Mark current node completed. This should be the only completed
       // node in the queue.
@@ -489,7 +479,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 +506,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 +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 (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,13 +547,7 @@
     MetricsProperties* mprops,
     GestureConsumer* consumer) {
   FilterInterpreter::Initialize(hwprops, NULL, mprops, consumer);
-  const size_t kMaxQNodes = 16;
-  queue_.DeleteAll();
-  free_list_.DeleteAll();
-  for (size_t i = 0; i < kMaxQNodes; ++i) {
-    QState* node = new QState(hwprops_->max_finger_cnt);
-    free_list_.PushBack(node);
-  }
+  queue_.clear();
 }
 
 stime_t LookaheadFilterInterpreter::ExtraVariableDelay() const {
@@ -571,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();
 }
diff --git a/src/lookahead_filter_interpreter_unittest.cc b/src/lookahead_filter_interpreter_unittest.cc
index 788d785..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);
@@ -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,17 @@
   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);
   }
 }
+
 }  // namespace gestures
diff --git a/src/metrics_filter_interpreter.cc b/src/metrics_filter_interpreter.cc
index e608f23..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,67 +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->DeleteAll();
-    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) {
-  MState* current = history->Tail();
-  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 = current->prev_;
-  MState* past_2 = past_1->prev_;
+  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/mouse_interpreter.cc b/src/mouse_interpreter.cc
index b26de8f..f3055b3 100644
--- a/src/mouse_interpreter.cc
+++ b/src/mouse_interpreter.cc
@@ -29,8 +29,7 @@
           scroll_accel_curve_, sizeof(scroll_accel_curve_) / sizeof(double)),
       scroll_max_allowed_input_speed_(prop_reg,
                                       "Mouse Scroll Max Input Speed",
-                                      177.0,
-                                      this),
+                                      177.0),
       force_scroll_wheel_emulation_(prop_reg,
                                      "Force Scroll Wheel Emulation",
                                      false),
@@ -53,6 +52,7 @@
   scroll_accel_curve_[2] = 2.5737e-02;
   scroll_accel_curve_[3] = 8.0428e-05;
   scroll_accel_curve_[4] = -9.1149e-07;
+  scroll_max_allowed_input_speed_.SetDelegate(this);
 }
 
 void MouseInterpreter::SyncInterpretImpl(HardwareState* hwstate,
diff --git a/src/prop_registry.cc b/src/prop_registry.cc
index 58e3a1a..2d9d454 100644
--- a/src/prop_registry.cc
+++ b/src/prop_registry.cc
@@ -70,18 +70,6 @@
   gprop_ = NULL;
 }
 
-void Property::SetDelegate(PropertyDelegate* delegate) {
-  bool delegate_was_late_set = !delegate_ && delegate;
-  delegate_ = delegate;
-  // In the normal path of creation of a property with a parent, the
-  // delegate is set late and the CreatePropImpl will not call the
-  // WasWritten method.  So catch the transition from NULL to not
-  // NULL in this condition and make sure to call the initial
-  // WasWritten to mimick the original code.
-  if (delegate_was_late_set && parent_ && parent_->PropProvider())
-    HandleGesturesPropWritten();
-}
-
 void BoolProperty::CreatePropImpl() {
   GesturesPropBool orig_val = val_;
   gprop_ = parent_->PropProvider()->create_bool_fn(
diff --git a/src/prop_registry_unittest.cc b/src/prop_registry_unittest.cc
index 23ba9d8..503a552 100644
--- a/src/prop_registry_unittest.cc
+++ b/src/prop_registry_unittest.cc
@@ -48,7 +48,8 @@
   PropRegistryTestDelegate delegate;
 
   int expected_call_cnt = 0;
-  BoolProperty bp1(&reg, "hi", false, &delegate);
+  BoolProperty bp1(&reg, "hi", false);
+  bp1.SetDelegate(&delegate);
   EXPECT_TRUE(strstr(ValueForProperty(bp1).c_str(), "false"));
   bp1.HandleGesturesPropWritten();
   EXPECT_EQ(++expected_call_cnt, delegate.call_cnt_);
@@ -58,7 +59,8 @@
   bp2.HandleGesturesPropWritten();
   EXPECT_EQ(expected_call_cnt, delegate.call_cnt_);
 
-  DoubleProperty dp1(&reg, "hi", 2721.0, &delegate);
+  DoubleProperty dp1(&reg, "hi", 2721.0);
+  dp1.SetDelegate(&delegate);
   EXPECT_TRUE(strstr(ValueForProperty(dp1).c_str(), "2721"));
   dp1.HandleGesturesPropWritten();
   EXPECT_EQ(++expected_call_cnt, delegate.call_cnt_);
@@ -68,7 +70,8 @@
   dp2.HandleGesturesPropWritten();
   EXPECT_EQ(expected_call_cnt, delegate.call_cnt_);
 
-  IntProperty ip1(&reg, "hi", 567, &delegate);
+  IntProperty ip1(&reg, "hi", 567);
+  ip1.SetDelegate(&delegate);
   EXPECT_TRUE(strstr(ValueForProperty(ip1).c_str(), "567"));
   ip1.HandleGesturesPropWritten();
   EXPECT_EQ(++expected_call_cnt, delegate.call_cnt_);
@@ -78,7 +81,8 @@
   ip2.HandleGesturesPropWritten();
   EXPECT_EQ(expected_call_cnt, delegate.call_cnt_);
 
-  StringProperty stp1(&reg, "hi", "foo", &delegate);
+  StringProperty stp1(&reg, "hi", "foo");
+  stp1.SetDelegate(&delegate);
   EXPECT_TRUE(strstr(ValueForProperty(stp1).c_str(), "foo"));
   stp1.HandleGesturesPropWritten();
   EXPECT_EQ(++expected_call_cnt, delegate.call_cnt_);
@@ -194,29 +198,31 @@
 
   PropRegistry reg;
   PropRegistryTestDelegate delegate;
-  BoolProperty my_bool(&reg, "MyBool", 0, &delegate);
-  DoubleProperty my_double(&reg, "MyDouble", 0.0, &delegate);
-  IntProperty my_int(&reg, "MyInt", 0, &delegate);
-  IntProperty my_int_no_change(&reg, "MyIntNoChange", 1, &delegate);
-  StringProperty my_string(&reg, "MyString", "mine", &delegate);
+  BoolProperty my_bool(&reg, "MyBool", 0);
+  my_bool.SetDelegate(&delegate);
+  DoubleProperty my_double(&reg, "MyDouble", 0.0);
+  my_double.SetDelegate(&delegate);
+  IntProperty my_int(&reg, "MyInt", 0);
+  my_int.SetDelegate(&delegate);
+  IntProperty my_int_no_change(&reg, "MyIntNoChange", 1);
+  my_int_no_change.SetDelegate(&delegate);
+  StringProperty my_string(&reg, "MyString", "mine");
+  my_string.SetDelegate(&delegate);
 
   EXPECT_EQ(0, delegate.call_cnt_);
   reg.SetPropProvider(&mock_gestures_props_provider, NULL);
   EXPECT_EQ(4, delegate.call_cnt_);
-
-  BoolProperty my_bool2(&reg, "MyBool2", 1);
-  EXPECT_EQ(4, delegate.call_cnt_);
-  my_bool2.SetDelegate(&delegate);
-  EXPECT_EQ(5, delegate.call_cnt_);
 }
 
 TEST(PropRegistryTest, DoublePromoteIntTest) {
   PropRegistry reg;
   PropRegistryTestDelegate delegate;
 
-  DoubleProperty my_double(&reg, "MyDouble", 1234.5, &delegate);
+  DoubleProperty my_double(&reg, "MyDouble", 1234.5);
+  my_double.SetDelegate(&delegate);
   EXPECT_TRUE(strstr(ValueForProperty(my_double).c_str(), "1234.5"));
-  IntProperty my_int(&reg, "MyInt", 321, &delegate);
+  IntProperty my_int(&reg, "MyInt", 321);
+  my_int.SetDelegate(&delegate);
   Json::Value my_int_val = my_int.NewValue();
   EXPECT_TRUE(my_double.SetValue(my_int_val));
   EXPECT_TRUE(strstr(ValueForProperty(my_double).c_str(), "321"));
@@ -229,15 +235,18 @@
 
   GesturesPropBool vals[] = { false, true };
   BoolArrayProperty my_bool_array_w_delegate(
-    &reg, "MyBoolArray", vals, 2, &delegate);
+    &reg, "MyBoolArray", vals, 2);
+  my_bool_array_w_delegate.SetDelegate(&delegate);
   EXPECT_EQ(0, delegate.call_cnt_);
   my_bool_array_w_delegate.HandleGesturesPropWritten();
   EXPECT_EQ(1, delegate.call_cnt_);
   delegate.BoolArrayWasWritten(&my_bool_array_w_delegate);
   EXPECT_EQ(2, delegate.call_cnt_);
 
-  IntProperty ip1(&reg, "hi", 567, &delegate);
-  StringProperty stp1(&reg, "hi", "foo", &delegate);
+  IntProperty ip1(&reg, "hi", 567);
+  ip1.SetDelegate(&delegate);
+  StringProperty stp1(&reg, "hi", "foo");
+  stp1.SetDelegate(&delegate);
   Json::Value my_bool_array_val = my_bool_array_w_delegate.NewValue();
   Json::Value my_int_val = ip1.NewValue();
   Json::Value my_str_val = stp1.NewValue();
@@ -261,15 +270,18 @@
 
   double vals[] = { 0.0, 1.0 };
   DoubleArrayProperty my_double_array_w_delegate(
-    &reg, "MyDoubleArray", vals, 2, &delegate);
+    &reg, "MyDoubleArray", vals, 2);
+  my_double_array_w_delegate.SetDelegate(&delegate);
   EXPECT_EQ(0, delegate.call_cnt_);
   my_double_array_w_delegate.HandleGesturesPropWritten();
   EXPECT_EQ(1, delegate.call_cnt_);
   delegate.DoubleArrayWasWritten(&my_double_array_w_delegate);
   EXPECT_EQ(2, delegate.call_cnt_);
 
-  IntProperty ip1(&reg, "hi", 567, &delegate);
-  StringProperty stp1(&reg, "hi", "foo", &delegate);
+  IntProperty ip1(&reg, "hi", 567);
+  ip1.SetDelegate(&delegate);
+  StringProperty stp1(&reg, "hi", "foo");
+  stp1.SetDelegate(&delegate);
   Json::Value my_double_array_val = my_double_array_w_delegate.NewValue();
   Json::Value my_int_val = ip1.NewValue();
   Json::Value my_str_val = stp1.NewValue();
@@ -293,15 +305,18 @@
 
   int vals[] = { 0, 1 };
   IntArrayProperty my_int_array_w_delegate(
-    &reg, "MyIntArray", vals, 2, &delegate);
+    &reg, "MyIntArray", vals, 2);
+  my_int_array_w_delegate.SetDelegate(&delegate);
   EXPECT_EQ(0, delegate.call_cnt_);
   my_int_array_w_delegate.HandleGesturesPropWritten();
   EXPECT_EQ(1, delegate.call_cnt_);
   delegate.IntArrayWasWritten(&my_int_array_w_delegate);
   EXPECT_EQ(2, delegate.call_cnt_);
 
-  IntProperty ip1(&reg, "hi", 567, &delegate);
-  StringProperty stp1(&reg, "hi", "foo", &delegate);
+  IntProperty ip1(&reg, "hi", 567);
+  ip1.SetDelegate(&delegate);
+  StringProperty stp1(&reg, "hi", "foo");
+  stp1.SetDelegate(&delegate);
   Json::Value my_int_array_val = my_int_array_w_delegate.NewValue();
   Json::Value my_int_val = ip1.NewValue();
   Json::Value my_str_val = stp1.NewValue();
diff --git a/src/scaling_filter_interpreter.cc b/src/scaling_filter_interpreter.cc
index 1094455..2d2aad9 100644
--- a/src/scaling_filter_interpreter.cc
+++ b/src/scaling_filter_interpreter.cc
@@ -318,8 +318,13 @@
                                           Metrics* metrics,
                                           MetricsProperties* mprops,
                                           GestureConsumer* consumer) {
-  tp_x_scale_ = 1.0 / hwprops->res_x;
-  tp_y_scale_ = 1.0 / hwprops->res_y;
+  // If the touchpad doesn't specify its resolution in one or both axes, use a
+  // reasonable default instead.
+  float res_x = hwprops->res_x != 0 ? hwprops->res_x : 32;
+  float res_y = hwprops->res_y != 0 ? hwprops->res_y : 32;
+
+  tp_x_scale_ = 1.0 / res_x;
+  tp_y_scale_ = 1.0 / res_y;
   tp_x_translate_ = -1.0 * (hwprops->left * tp_x_scale_);
   tp_y_translate_ = -1.0 * (hwprops->top * tp_y_scale_);
 
diff --git a/src/scaling_filter_interpreter_unittest.cc b/src/scaling_filter_interpreter_unittest.cc
index d701c7f..93f8e79 100644
--- a/src/scaling_filter_interpreter_unittest.cc
+++ b/src/scaling_filter_interpreter_unittest.cc
@@ -68,7 +68,7 @@
       EXPECT_FLOAT_EQ(expected_pressures_.front(),
                       hwstate->fingers[0].pressure);
       expected_pressures_.pop_front();
-    } else {
+    } else if (!expected_finger_cnt_.empty() && !expected_touch_cnt_.empty()) {
       // Test if the low pressure event is dropped
       EXPECT_EQ(expected_finger_cnt_.front(), hwstate->finger_cnt);
       expected_finger_cnt_.pop_front();
@@ -272,6 +272,47 @@
   out = wrapper.SyncInterpret(&hs2[2], NULL);
 }
 
+TEST(ScalingFilterInterpreterTest, ResolutionFallback) {
+  ScalingFilterInterpreterTestInterpreter* base_interpreter =
+      new ScalingFilterInterpreterTestInterpreter;
+  ScalingFilterInterpreter interpreter(NULL, base_interpreter, NULL,
+                                       GESTURES_DEVCLASS_TOUCHPAD);
+  HardwareProperties initial_hwprops = {
+    0, 0, 2000, 1000,  // left, top, right, bottom
+    0, 0,  // X/Y resolutions (pixels/mm)
+    0, 0,  // screen DPI X, Y (deprecated)
+    -1,  // orientation minimum
+    2,   // orientation maximum
+    2, 5,  // max fingers, max_touch
+    0, 0, 0,  // t5r2, semi, button pad
+    0, 0,  // has wheel, vertical wheel is high resolution
+    0,  // haptic pad
+  };
+  HardwareProperties expected_hwprops = {
+    0, 0, 2000 / 32.0, 1000 / 32.0,  // left, top, right, bottom
+    1, 1,  // X/Y resolutions (pixels/mm)
+    25.4, 25.4, // x DPI, y DPI
+    -M_PI_4,  // orientation minimum (1 tick above X-axis)
+    M_PI_2,   // orientation maximum
+    2, 5, 0, 0, 0,  // max_fingers, max_touch, t5r2, semi_mt, is button pad
+    0, 0,  // has wheel, vertical wheel is high resolution
+    0,  // is haptic pad
+  };
+  base_interpreter->expected_hwprops_ = expected_hwprops;
+
+  TestInterpreterWrapper wrapper(&interpreter, &initial_hwprops);
+  EXPECT_TRUE(base_interpreter->initialize_called_);
+
+  FingerState fs = { 1, 0, 0, 0, 1, 0, 1000, 500, 1, 0 };
+  HardwareState hs = make_hwstate(10000, 0, 1, 1, &fs);
+
+  base_interpreter->expected_coordinates_.push_back(
+      std::vector<pair<float, float>>(1, make_pair(
+          static_cast<float>(1000 / 32.0), static_cast<float>(500 / 32.0))));
+
+  wrapper.SyncInterpret(&hs, NULL);
+}
+
 static void RunTouchMajorAndMinorTest(
     ScalingFilterInterpreterTestInterpreter* base_interpreter,
     ScalingFilterInterpreter* interpreter,
diff --git a/src/trend_classifying_filter_interpreter.cc b/src/trend_classifying_filter_interpreter.cc
index 45699a9..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->Tail();
-  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 (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();
+  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->DeleteAll();
-    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->Tail();
-    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/local_coverage_rate.sh b/tools/local_coverage_rate.sh
index 710d91c..d1f9fff 100755
--- a/tools/local_coverage_rate.sh
+++ b/tools/local_coverage_rate.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+# 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.
 
diff --git a/tools/regression_test.sh b/tools/regression_test.sh
index db7535b..f97118a 100755
--- a/tools/regression_test.sh
+++ b/tools/regression_test.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/tools/replay_log b/tools/replay_log
index bfdca70..76ddbbd 100755
--- a/tools/replay_log
+++ b/tools/replay_log
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
diff --git a/tools/tplog.py b/tools/tplog.py
index b2a685f..7df13f8 100755
--- a/tools/tplog.py
+++ b/tools/tplog.py
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 #
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Copyright 2012 The ChromiumOS Authors
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -8,9 +8,9 @@
 
 
 import getopt
+import json
 import logging
 import os
-import simplejson as json
 import sys
 
 from operator import ge, lt