From f3e456ed250cb32c34e43d414f1f05887c355534 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 23 Jul 2023 19:54:36 +0200 Subject: [PATCH] Store event types internally as an enum. We were using ~15% of our CPU time comparing strings now, which was a bit too much. --- events.cpp | 191 ++++++++++++++++++++++++++++++++++++++++--------- events.h | 34 ++++++++- mainwindow.cpp | 2 +- 3 files changed, 190 insertions(+), 37 deletions(-) diff --git a/events.cpp b/events.cpp index 0fe5b3d..cc7a909 100644 --- a/events.cpp +++ b/events.cpp @@ -10,6 +10,129 @@ using namespace std; string format_timestamp(uint64_t pos); +static string event_type_to_string(EventType type) +{ + switch (type) { + case EventType::CATCH: + return "catch"; + case EventType::DEFENSE: + return "defense"; + case EventType::DEFENSIVE_SOFT_MINUS: + return "defensive_soft_minus"; + case EventType::DEFENSIVE_SOFT_PLUS: + return "defensive_soft_plus"; + case EventType::FORMATION_DEFENSE: + return "formation_defense"; + case EventType::FORMATION_OFFENSE: + return "formation_offense"; + case EventType::DROP: + return "drop"; + case EventType::GOAL: + return "goal"; + case EventType::IN: + return "in"; + case EventType::INTERCEPTION: + return "interception"; + case EventType::OFFENSIVE_SOFT_MINUS: + return "offensive_soft_minus"; + case EventType::OFFENSIVE_SOFT_PLUS: + return "offensive_soft_plus"; + case EventType::OUT: + return "out"; + case EventType::PULL: + return "pull"; + case EventType::PULL_LANDED: + return "pull_landed"; + case EventType::PULL_OOB: + return "pull_oob"; + case EventType::RESTART: + return "restart"; + case EventType::SET_DEFENSE: + return "set_defense"; + case EventType::SET_OFFENSE: + return "set_offense"; + case EventType::STALLOUT: + return "stallout"; + case EventType::STOPPAGE: + return "stoppage"; + case EventType::THEIR_GOAL: + return "their_goal"; + case EventType::THEIR_PULL: + return "their_pull"; + case EventType::THEIR_THROWAWAY: + return "their_throwaway"; + case EventType::THROWAWAY: + return "throwaway"; + case EventType::UNKNOWN: + return "unknown"; + case EventType::WAS_D: + return "was_d"; + } + abort(); +} + +static EventType string_to_event_type(const string &type) +{ + if (type == "catch") { + return EventType::CATCH; + } else if (type == "defense") { + return EventType::DEFENSE; + } else if (type == "defensive_soft_minus") { + return EventType::DEFENSIVE_SOFT_MINUS; + } else if (type == "defensive_soft_plus") { + return EventType::DEFENSIVE_SOFT_PLUS; + } else if (type == "formation_defense") { + return EventType::FORMATION_DEFENSE; + } else if (type == "formation_offense") { + return EventType::FORMATION_OFFENSE; + } else if (type == "drop") { + return EventType::DROP; + } else if (type == "goal") { + return EventType::GOAL; + } else if (type == "in") { + return EventType::IN; + } else if (type == "interception") { + return EventType::INTERCEPTION; + } else if (type == "offensive_soft_minus") { + return EventType::OFFENSIVE_SOFT_MINUS; + } else if (type == "offensive_soft_plus") { + return EventType::OFFENSIVE_SOFT_PLUS; + } else if (type == "out") { + return EventType::OUT; + } else if (type == "pull") { + return EventType::PULL; + } else if (type == "pull_landed") { + return EventType::PULL_LANDED; + } else if (type == "pull_oob") { + return EventType::PULL_OOB; + } else if (type == "restart") { + return EventType::RESTART; + } else if (type == "set_defense") { + return EventType::SET_DEFENSE; + } else if (type == "set_offense") { + return EventType::SET_OFFENSE; + } else if (type == "stallout") { + return EventType::STALLOUT; + } else if (type == "stoppage") { + return EventType::STOPPAGE; + } else if (type == "their_goal") { + return EventType::THEIR_GOAL; + } else if (type == "their_pull") { + return EventType::THEIR_PULL; + } else if (type == "their_throwaway") { + return EventType::THEIR_THROWAWAY; + } else if (type == "throwaway") { + return EventType::THROWAWAY; + } else if (type == "unknown") { + return EventType::UNKNOWN; + } else if (type == "was_d") { + return EventType::WAS_D; + } else { + fprintf(stderr, "Unknown event type “%s”\n", type.c_str()); + exit(1); + } +} + EventsModel::EventsModel(sqlite3 *db, int match_id) : db(db), match_id(match_id) { load_data(); @@ -52,14 +175,14 @@ QVariant EventsModel::data(const QModelIndex &index, int role) const auto f_it = formations.find(*formation_id); const Formation &f = f_it->second; return QString::fromUtf8(f.name); - } else if (e.type == "formation_offense" || e.type == "formation_defense") { + } else if (e.type == EventType::FORMATION_OFFENSE || e.type == EventType::FORMATION_DEFENSE) { return "(None/unknown)"; } else { return QVariant(); } } else if (index.column() == 2) { - string type = e.type; - type[0] = toupper(e.type[0]); + string type = event_type_to_string(e.type); + type[0] = toupper(type[0]); for (char &ch : type) { if (ch == '_') { ch = ' '; @@ -168,7 +291,7 @@ void EventsModel::load_data() if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) { // Non-NULL. e.formation_id = sqlite3_column_int(stmt, 3); } - e.type = (const char *)sqlite3_column_text(stmt, 4); + e.type = string_to_event_type((const char *)sqlite3_column_text(stmt, 4)); events.push_back(std::move(e)); } else if (ret == SQLITE_DONE) { break; @@ -195,7 +318,7 @@ unsigned EventsModel::insert_event(uint64_t t, optional player_id, optional e.t = t; e.player_id = player_id; e.formation_id = formation_id; - e.type = type; + e.type = string_to_event_type(type); events.insert(events.begin() + pos, e); endInsertRows(); @@ -271,7 +394,7 @@ void EventsModel::delete_event(unsigned pos) void EventsModel::set_event_type(unsigned pos, const string &type) { - events[pos].type = type; + events[pos].type = string_to_event_type(type); emit dataChanged(createIndex(pos, 0), createIndex(pos, 2)); sqlite3_stmt *stmt; @@ -361,73 +484,73 @@ EventsModel::Status EventsModel::get_status_at(uint64_t t) break; } - if (e.type == "goal" || e.type == "their_goal") { + if (e.type == EventType::GOAL || e.type == EventType::THEIR_GOAL) { s.pull_state = Status::SHOULD_PULL; - } else if (e.type == "in" || e.type == "out" || e.type == "stoppage" || e.type == "restart" || e.type == "unknown" || e.type == "set_defense" || e.type == "set_offense") { + } else if (e.type == EventType::IN || e.type == EventType::OUT || e.type == EventType::STOPPAGE || e.type == EventType::RESTART || e.type == EventType::UNKNOWN || e.type == EventType::SET_DEFENSE || e.type == EventType::SET_OFFENSE) { // No effect on pull status. - } else if (e.type == "pull") { + } else if (e.type == EventType::PULL) { s.pull_state = Status::PULL_IN_AIR; } else { s.pull_state = Status::NOT_PULLING; // Includes pull_landed and pull_oob. } - if (e.type == "set_offense") { + if (e.type == EventType::SET_OFFENSE) { set_offense(); - } else if (e.type == "set_defense") { + } else if (e.type == EventType::SET_DEFENSE) { set_defense(); } - if (e.type == "goal") { + if (e.type == EventType::GOAL) { ++s.our_score; set_defense(); num_touches = 0; } - if (e.type == "their_goal") { + if (e.type == EventType::THEIR_GOAL) { ++s.their_score; set_offense(); num_touches = 0; } - if (e.type == "catch") { + if (e.type == EventType::CATCH) { if (num_touches == 0) { // Pick up. last_gained_possession = e.t; time_spent_in_stoppage = 0; } ++num_touches; } - if (e.type == "interception") { + if (e.type == EventType::INTERCEPTION) { num_touches = 1; set_offense(); last_gained_possession = e.t; time_spent_in_stoppage = 0; } - if (e.type == "defense" || e.type == "their_throwaway") { + if (e.type == EventType::DEFENSE || e.type == EventType::THEIR_THROWAWAY) { set_offense(); num_touches = 0; time_spent_in_stoppage = 0; } - if (e.type == "drop" || e.type == "was_d" || e.type == "throwaway" || e.type == "stallout") { + if (e.type == EventType::DROP || e.type == EventType::WAS_D || e.type == EventType::THROWAWAY || e.type == EventType::STALLOUT) { set_defense(); num_touches = 0; } - if (e.type == "stoppage") { + if (e.type == EventType::STOPPAGE) { s.stoppage = true; last_stoppage = e.t; } - if (e.type == "restart") { + if (e.type == EventType::RESTART) { s.stoppage = false; if (last_stoppage != 0) { time_spent_in_stoppage += (e.t - last_stoppage); last_stoppage = 0; } } - if (e.type == "formation_offense") { + if (e.type == EventType::FORMATION_OFFENSE) { if (e.formation_id) { s.offensive_formation = *e.formation_id; } else { s.offensive_formation = 0; } } - if (e.type == "formation_defense") { + if (e.type == EventType::FORMATION_DEFENSE) { if (e.formation_id) { s.defensive_formation = *e.formation_id; } else { @@ -452,10 +575,10 @@ set EventsModel::get_team_at(uint64_t t) if (e.t > t) { break; } - if (e.type == "in") { + if (e.type == EventType::IN) { team.insert(*e.player_id); } - if (e.type == "out") { + if (e.type == EventType::OUT) { team.erase(*e.player_id); } } @@ -473,7 +596,7 @@ void EventsModel::set_team_at(uint64_t t, const set &new_team) if (e.t > t) { break; } - if (e.type == "goal" || e.type == "their_goal" || e.type == "stoppage" || e.type == "set_offense" || e.type == "set_defense") { + if (e.type == EventType::GOAL || e.type == EventType::THEIR_GOAL || e.type == EventType::STOPPAGE || e.type == EventType::SET_OFFENSE || e.type == EventType::SET_DEFENSE) { backdate_point = e.t + 1; } if (e.player_id.has_value() && !new_team.count(*e.player_id)) { @@ -486,7 +609,7 @@ void EventsModel::set_team_at(uint64_t t, const set &new_team) if (events[i].t > backdate_point) { break; } - if (events[i].t == backdate_point && (events[i].type == "in" || events[i].type == "out")) { + if (events[i].t == backdate_point && (events[i].type == EventType::IN || events[i].type == EventType::OUT)) { delete_event(i); } else { ++i; @@ -518,17 +641,17 @@ void EventsModel::set_formation_at(uint64_t t, bool offense, unsigned formation) if (e.t > t) { break; } - if (e.type == "goal" || e.type == "their_goal" || - e.type == "in" || e.type == "out" || - e.type == "stoppage" || - e.type == "set_defense" || e.type == "set_offense" || - e.type == "throwaway" || e.type == "their_throwaway" || - e.type == "drop" || e.type == "was_d" || e.type == "defense" || e.type == "interception" || e.type == "stallout" || - e.type == "pull" || e.type == "pull_landed" || e.type == "pull_oob" || e.type == "their_pull" || - e.type == "formation_offense" || e.type == "formation_defense") { + if (e.type == EventType::GOAL || e.type == EventType::THEIR_GOAL || + e.type == EventType::IN || e.type == EventType::OUT || + e.type == EventType::STOPPAGE || + e.type == EventType::SET_DEFENSE || e.type == EventType::SET_OFFENSE || + e.type == EventType::THROWAWAY || e.type == EventType::THEIR_THROWAWAY || + e.type == EventType::DROP || e.type == EventType::WAS_D || e.type == EventType::DEFENSE || e.type == EventType::INTERCEPTION || e.type == EventType::STALLOUT || + e.type == EventType::PULL || e.type == EventType::PULL_LANDED || e.type == EventType::PULL_OOB || e.type == EventType::THEIR_PULL || + e.type == EventType::FORMATION_OFFENSE || e.type == EventType::FORMATION_DEFENSE) { backdate_point = e.t + 1; } - if (e.type == "formation_offense" || e.type == "formation_defense") { + if (e.type == EventType::FORMATION_OFFENSE || e.type == EventType::FORMATION_DEFENSE) { backdate_point = 0; } } diff --git a/events.h b/events.h index df5fcb6..f522734 100644 --- a/events.h +++ b/events.h @@ -9,6 +9,36 @@ #include #include +enum class EventType { + CATCH, + DEFENSE, + DEFENSIVE_SOFT_MINUS, + DEFENSIVE_SOFT_PLUS, + FORMATION_DEFENSE, + FORMATION_OFFENSE, + DROP, + GOAL, + IN, + INTERCEPTION, + OFFENSIVE_SOFT_MINUS, + OFFENSIVE_SOFT_PLUS, + OUT, + PULL, + PULL_LANDED, + PULL_OOB, + RESTART, + SET_DEFENSE, + SET_OFFENSE, + STALLOUT, + STOPPAGE, + THEIR_GOAL, + THEIR_PULL, + THEIR_THROWAWAY, + THROWAWAY, + UNKNOWN, + WAS_D, +}; + class EventsModel : public QAbstractTableModel { public: @@ -27,7 +57,7 @@ public: unsigned insert_event(uint64_t t, std::optional player_id, std::optional formation_id, const std::string &type = "unknown"); // Returns the row. void delete_event(unsigned row); - std::string get_event_type(unsigned row) { return events[row].type; } + EventType get_event_type(unsigned row) { return events[row].type; } void set_event_type(unsigned row, const std::string &type); void set_event_formation(unsigned row, int formation_id); uint64_t get_time(unsigned row) { return events[row].t; } @@ -78,7 +108,7 @@ private: uint64_t t; std::optional player_id; std::optional formation_id; - std::string type; + EventType type; }; std::vector events; diff --git a/mainwindow.cpp b/mainwindow.cpp index 05c5d71..0ff813b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -352,7 +352,7 @@ void MainWindow::insert_or_change_formation(bool offense) QItemSelectionModel *select = ui->event_view->selectionModel(); if (select->hasSelection()) { int row = select->selectedRows().front().row(); // Should only be one, due to our selection behavior. - string expected_type = offense ? "formation_offense" : "formation_defense"; + EventType expected_type = offense ? EventType::FORMATION_OFFENSE : EventType::FORMATION_DEFENSE; if (events->get_event_type(row) == expected_type) { events->set_event_formation(row, formation_id); update_ui_from_time(ui->video->get_position()); -- 2.39.2