diff options
author | Harry Cutts <hcutts@google.com> | 2023-04-05 20:51:03 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-04-05 20:51:03 +0000 |
commit | 781b8df8fa3b02c22baf0b9e80c164c7e84e84a5 (patch) | |
tree | 5cc65c6a06e2fa8e7e7b178485355ea72ef89627 | |
parent | a2cb809cb1d81ffb2ad30a952319f41800c5c7b5 (diff) | |
parent | bcae70e9f7042837ba05c8c9c3b5ed6eff25f302 (diff) | |
download | libchrome-gestures-aml_sdk_341110080.tar.gz |
Merge list refactor from upstream am: f29fcceda1 am: f78de2018b am: b9d4211737 am: bcae70e9f7aml_wif_341711020aml_wif_341610000aml_wif_341510000aml_wif_341410080aml_wif_341310010aml_wif_341110010aml_wif_341011010aml_wif_340913010aml_uwb_341710010aml_uwb_341513070aml_uwb_341511050aml_uwb_341310300aml_uwb_341310030aml_uwb_341111010aml_uwb_341011000aml_tet_341712060aml_tet_341610020aml_tet_341511010aml_tet_341411060aml_tet_341310230aml_tet_341112070aml_tet_341010040aml_tet_340913030aml_swc_341711000aml_swc_341619000aml_swc_341513600aml_swc_341312300aml_swc_341312020aml_swc_341111000aml_swc_341011020aml_swc_340922010aml_sta_341710000aml_sta_341615000aml_sta_341511040aml_sta_341410000aml_sta_341311010aml_sta_341114000aml_sta_341111000aml_sta_341010020aml_sta_340912000aml_sta_340911000aml_sdk_341710000aml_sdk_341510000aml_sdk_341410000aml_sdk_341110080aml_sdk_341110000aml_sdk_341010000aml_sdk_340912010aml_sch_341510000aml_res_341510000aml_res_341410010aml_res_341311030aml_res_341110000aml_res_340912000aml_per_341711000aml_per_341614000aml_per_341510010aml_per_341410020aml_per_341311000aml_per_341110020aml_per_341110010aml_per_341011100aml_per_341011020aml_per_340916010aml_odp_341717000aml_odp_341610000aml_neu_341510000aml_neu_341010080aml_neu_341010000aml_net_341710020aml_net_341610030aml_net_341510050aml_net_341510000aml_net_341411030aml_net_341311010aml_net_341310020aml_net_341111030aml_net_341014000aml_net_340913000aml_mpr_341713020aml_mpr_341614010aml_mpr_341511070aml_mpr_341411070aml_mpr_341313030aml_mpr_341111030aml_mpr_341111020aml_mpr_341015090aml_mpr_341015030aml_mpr_340919000aml_med_341711000aml_med_341619000aml_med_341513600aml_med_341312300aml_med_341312020aml_med_341111000aml_med_341011000aml_med_340922010aml_ips_341611000aml_ips_341510000aml_ips_340914280aml_ips_340914200aml_ips_340914000aml_ext_341716000aml_ext_341620040aml_ext_341518010aml_ext_341414010aml_ext_341317010aml_ext_341131030aml_ext_341027030aml_doc_341713000aml_doc_341610010aml_doc_341510050aml_doc_341312010aml_doc_341112000aml_doc_341012000aml_doc_340916000aml_con_341614000aml_con_341511080aml_con_341410300aml_con_341310090aml_con_341110000aml_cbr_341710000aml_cbr_341610000aml_cbr_341510010aml_cbr_341410010aml_cbr_341311010aml_cbr_341110000aml_cbr_341011000aml_cbr_340914000aml_ase_341510000aml_ase_341410000aml_ase_341310010aml_ase_341113000aml_ase_340913000aml_art_341711000aml_art_341615020aml_art_341514450aml_art_341514410aml_art_341411300aml_art_341311100aml_art_341110110aml_art_341110060aml_art_341010050aml_art_340915060aml_ads_341720000aml_ads_341615050aml_ads_341517040aml_ads_341413000aml_ads_341316030aml_ads_341131050aml_ads_341027030aml_ads_340915050aml_adb_341520010aml_adb_341517070aml_adb_340912530aml_adb_340912350aml_adb_340912200aml_adb_340912000android14-mainline-wifi-releaseandroid14-mainline-uwb-releaseandroid14-mainline-tethering-releaseandroid14-mainline-sdkext-releaseandroid14-mainline-resolv-releaseandroid14-mainline-permission-releaseandroid14-mainline-os-statsd-releaseandroid14-mainline-networking-releaseandroid14-mainline-mediaprovider-releaseandroid14-mainline-media-swcodec-releaseandroid14-mainline-media-releaseandroid14-mainline-extservices-releaseandroid14-mainline-conscrypt-releaseandroid14-mainline-cellbroadcast-releaseandroid14-mainline-art-releaseandroid14-mainline-appsearch-releaseandroid14-mainline-adservices-releaseandroid14-mainline-adbd-release
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>
-rw-r--r-- | METADATA.android | 4 | ||||
-rw-r--r-- | include/gestures.h | 35 | ||||
-rw-r--r-- | include/list.h | 70 | ||||
-rw-r--r-- | include/lookahead_filter_interpreter.h | 16 | ||||
-rw-r--r-- | include/memory_manager.h | 79 | ||||
-rw-r--r-- | include/metrics_filter_interpreter.h | 32 | ||||
-rw-r--r-- | include/trend_classifying_filter_interpreter.h | 19 | ||||
-rw-r--r-- | include/util.h | 48 | ||||
-rw-r--r-- | src/lookahead_filter_interpreter.cc | 185 | ||||
-rw-r--r-- | src/lookahead_filter_interpreter_unittest.cc | 98 | ||||
-rw-r--r-- | src/metrics_filter_interpreter.cc | 74 | ||||
-rw-r--r-- | src/trend_classifying_filter_interpreter.cc | 64 | ||||
-rw-r--r-- | src/util_unittest.cc | 47 | ||||
-rwxr-xr-x | tools/tplog.py | 2 |
14 files changed, 248 insertions, 525 deletions
diff --git a/METADATA.android b/METADATA.android index 4aee07c..f12b10f 100644 --- a/METADATA.android +++ b/METADATA.android @@ -6,7 +6,7 @@ third_party { 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 @@ struct HardwareProperties { #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 @@ struct HardwareProperties { #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 @@ struct HardwareState { 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 @@ class LookaheadFilterInterpreter : public FilterInterpreter { 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 @@ class LookaheadFilterInterpreter : public FilterInterpreter { 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 @@ class LookaheadFilterInterpreter : public FilterInterpreter { 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 @@ class MetricsFilterInterpreter : public FilterInterpreter { 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 @@ class MetricsFilterInterpreter : public FilterInterpreter { 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 @@ class MetricsFilterInterpreter : public FilterInterpreter { // 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ bool MapContainsKey(const Map& the_map, const Key& the_key) { } // 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 @@ inline bool SetContainsValue(const Set& the_set, 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 @@ namespace { 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 @@ LookaheadFilterInterpreter::LookaheadFilterInterpreter( 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 @@ void LookaheadFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate, 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { // 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { 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 @@ void LookaheadFilterInterpreter::AssignTrackingIds() { 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 @@ void LookaheadFilterInterpreter::TapDownOccurringGesture(stime_t now) { 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 @@ short LookaheadFilterInterpreter::NextTrackingId() { 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; - - 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); + node.due_ = node.state_.timestamp + delay; + + // 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 @@ void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now, 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 @@ void LookaheadFilterInterpreter::HandleTimerImpl(stime_t now, 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::HandleTimerImpl(stime_t now, } 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 @@ void LookaheadFilterInterpreter::ConsumeGesture(const Gesture& gesture) { } // 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 @@ void LookaheadFilterInterpreter::UpdateInterpreterDue( // 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 @@ void LookaheadFilterInterpreter::Initialize( 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 @@ stime_t LookaheadFilterInterpreter::ExtraVariableDelay() const { } 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 @@ void LookaheadFilterInterpreter::QState::set_state( 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 @@ TEST(LookaheadFilterInterpreterTest, SimpleTest) { 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 @@ TEST(LookaheadFilterInterpreterTest, SpuriousCallbackTest) { 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 @@ TEST(LookaheadFilterInterpreterTest, InterpolationOverdueTest) { 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 @@ TEST(LookaheadFilterInterpreterTest, QuickMoveTest) { // 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 @@ TEST(LookaheadFilterInterpreterTest, QuickMoveTest) { // 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 @@ TEST(LookaheadFilterInterpreterTest, SemiMtNoTrackingIdAssignmentTest) { 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 @@ MetricsFilterInterpreter::MetricsFilterInterpreter( 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 @@ MetricsFilterInterpreter::MetricsFilterInterpreter( } 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 @@ void MetricsFilterInterpreter::SyncInterpretImpl(HardwareState* hwstate, 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::ReportMouseStatistics() { 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 @@ namespace gestures { 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::InterpretTestResult( } 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"); - return; - } - current->Init(fs); - if (history->size() == 1) + auto& current = history.emplace_back(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], ¤t->axes_[i], + if (it != history.begin() || !KState::IsDelta(i)) { + UpdateKTValuePair(&it->axes_[i], ¤t.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 @@ TrendClassifyingFilterInterpreter::RunKTTest(const KState::KAxis* current, 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(¤t->axes_[idx], + TrendType result = RunKTTest(¤t.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 @@ TEST(UtilTest, DistSqTest) { 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 |