From 41fe990530c546b4cac7e000b40481f87fb33305 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 19 Oct 2020 19:36:10 +0200 Subject: shared_ptr -> unique_ptr and naked pointers --- src/QuickMedia.cpp | 107 +++++++++++++++++++------------------------------ src/plugins/Matrix.cpp | 72 ++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 98 deletions(-) (limited to 'src') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 659e59c..a32febb 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -2961,21 +2961,10 @@ namespace QuickMedia { // This is needed to get initial data, with joined rooms etc. TODO: Remove this once its cached // and allow asynchronous update of rooms bool synced = false; - - struct RoomBodyData { - std::shared_ptr body_item; - bool last_message_read; - time_t last_read_message_timestamp; - }; - - std::unordered_map, RoomBodyData> body_items_by_room; - std::shared_ptr current_room; - RoomBodyData *current_room_body_data = nullptr; - + RoomData *current_room = nullptr; bool is_window_focused = window.hasFocus(); - // TODO: Always keep the mentioned rooms at the top, and then the ones with unread messages below? - auto process_new_room_messages = [this, &tabs, &body_items_by_room, ¤t_room, &is_window_focused](RoomSyncMessages &room_sync_messages, bool is_first_sync) mutable { + auto process_new_room_messages = [this, &tabs, ¤t_room, &is_window_focused](RoomSyncMessages &room_sync_messages, bool is_first_sync) mutable { size_t room_swap_index = 0; for(auto &[room, messages] : room_sync_messages) { if(messages.empty()) @@ -2985,6 +2974,7 @@ namespace QuickMedia { for(auto &message : messages) { if(message->mentions_me) { was_mentioned = true; + room->has_unread_mention = true; //message->mentions_me = false; // TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user if(!is_window_focused || room != current_room) @@ -2992,9 +2982,8 @@ namespace QuickMedia { } } - auto room_body_item_it = body_items_by_room.find(room); - if(room_body_item_it == body_items_by_room.end()) - continue; + BodyItem *room_body_item = static_cast(room->userdata); + assert(room_body_item); // TODO: this wont always work because we dont display all types of messages from server, such as "joined", "left", "kicked", "banned", "changed avatar", "changed display name", etc. bool unread_messages = false; @@ -3006,19 +2995,20 @@ namespace QuickMedia { std::string room_desc = "Unread: " + matrix->message_get_author_displayname(messages.back().get()) + ": " + extract_first_line(messages.back()->body, 150); if(was_mentioned) room_desc += "\n** You were mentioned **"; // TODO: Better notification? - room_body_item_it->second.body_item->set_description(std::move(room_desc)); - room_body_item_it->second.body_item->set_title_color(sf::Color(255, 100, 100)); - room_body_item_it->second.last_message_read = false; + room_body_item->set_description(std::move(room_desc)); + room_body_item->set_title_color(sf::Color(255, 100, 100)); + room->last_message_read = false; // Swap room with the top one // TODO: Optimize with hash map instead of linear search? or cache the index - int room_body_index = tabs[ROOMS_TAB_INDEX].body->get_index_by_body_item(room_body_item_it->second.body_item.get()); + int room_body_index = tabs[ROOMS_TAB_INDEX].body->get_index_by_body_item(room_body_item); if(room_body_index != -1) { std::swap(tabs[ROOMS_TAB_INDEX].body->items[room_body_index], tabs[ROOMS_TAB_INDEX].body->items[room_swap_index]); ++room_swap_index; } } else if(is_first_sync) { - room_body_item_it->second.body_item->set_description(matrix->message_get_author_displayname(messages.back().get()) + ": " + extract_first_line(messages.back()->body, 150)); + room_body_item->set_description(matrix->message_get_author_displayname(messages.back().get()) + ": " + extract_first_line(messages.back()->body, 150)); + room->has_unread_mention = false; } } }; @@ -3058,14 +3048,6 @@ namespace QuickMedia { bool redraw = true; - auto get_room_by_ptr = [&body_items_by_room](RoomData *room_ptr) -> std::shared_ptr { - for(auto &[room, body_data] : body_items_by_room) { - if(room.get() == room_ptr) - return room; - } - return nullptr; - }; - // TODO: Optimize with hash map? auto find_body_item_by_event_id = [](std::shared_ptr *body_items, size_t num_body_items, const std::string &event_id) -> std::shared_ptr { for(size_t i = 0; i < num_body_items; ++i) { @@ -3077,7 +3059,7 @@ namespace QuickMedia { }; // TODO: What if these never end up referencing events? clean up automatically after a while? - std::unordered_map, Messages> unreferenced_event_by_room; + std::unordered_map unreferenced_event_by_room; auto set_body_as_deleted = [](Message *message, BodyItem *body_item) { body_item->embedded_item = nullptr; @@ -3137,9 +3119,9 @@ namespace QuickMedia { }; room_search_bar.onTextSubmitCallback = - [this, &tabs, &selected_tab, ¤t_room, ¤t_room_body_data, &room_name_text, - &get_room_by_ptr, &body_items_by_room, &modify_related_messages_in_current_room, - &room_avatar_thumbnail_data, &read_marker_timeout_ms, &redraw] + [this, &tabs, &selected_tab, ¤t_room, &room_name_text, + &modify_related_messages_in_current_room, &room_avatar_thumbnail_data, + &read_marker_timeout_ms, &redraw] (const std::string&) { BodyItem *selected_item = tabs[ROOMS_TAB_INDEX].body->get_selected(); @@ -3148,7 +3130,7 @@ namespace QuickMedia { tabs[ROOMS_TAB_INDEX].body->clear_cache(); - current_room = get_room_by_ptr((RoomData*)selected_item->userdata); + current_room = (RoomData*)selected_item->userdata; assert(current_room); selected_tab = MESSAGES_TAB_INDEX; tabs[MESSAGES_TAB_INDEX].body->clear_items(); @@ -3163,12 +3145,8 @@ namespace QuickMedia { show_notification("QuickMedia", err_msg, Urgency::CRITICAL); } - auto room_body_item_it = body_items_by_room.find(current_room); - if(room_body_item_it != body_items_by_room.end()) { - current_room_body_data = &room_body_item_it->second; - room_name_text.setString(current_room_body_data->body_item->get_title()); - room_avatar_thumbnail_data = std::make_shared(); - } + room_name_text.setString(static_cast(current_room->userdata)->get_title()); + room_avatar_thumbnail_data = std::make_shared(); read_marker_timeout_ms = 0; redraw = true; @@ -3255,11 +3233,11 @@ namespace QuickMedia { std::future previous_messages_future; bool fetching_previous_messages_running = false; - std::shared_ptr previous_messages_future_room; + RoomData *previous_messages_future_room = nullptr; std::future> fetch_reply_message_future; bool fetching_reply_message_running = false; - std::shared_ptr fetch_reply_future_room; + RoomData *fetch_reply_future_room = nullptr; BodyItem *fetch_reply_body_item = nullptr; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. @@ -3287,7 +3265,7 @@ namespace QuickMedia { body_item->embedded_item_status = EmbeddedItemStatus::LOADING; // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive? fetch_reply_message_future = std::async(std::launch::async, [this, &fetch_reply_future_room, message_event_id]() { - return matrix->get_message_by_id(fetch_reply_future_room.get(), message_event_id); + return matrix->get_message_by_id(fetch_reply_future_room, message_event_id); }); }; @@ -3318,7 +3296,7 @@ namespace QuickMedia { float tab_vertical_offset = 0.0f; - auto typing_async_func = [this](bool new_state, std::shared_ptr room) { + auto typing_async_func = [this](bool new_state, RoomData *room) { if(new_state) { matrix->on_start_typing(room); } else { @@ -3381,7 +3359,7 @@ namespace QuickMedia { } }; - auto add_new_rooms = [&tabs, &body_items_by_room, ¤t_room, ¤t_room_body_data, &room_name_text, &room_search_bar](Rooms &rooms) { + auto add_new_rooms = [&tabs, ¤t_room, &room_name_text, &room_search_bar](Rooms &rooms) { if(rooms.empty()) return; @@ -3395,23 +3373,19 @@ namespace QuickMedia { auto body_item = BodyItem::create(std::move(room_name)); body_item->thumbnail_url = room->avatar_url; - body_item->userdata = room.get(); // Note: this has to be valid as long as the room list is valid! + body_item->userdata = room; // Note: this has to be valid as long as the room list is valid! body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; body_item->thumbnail_size = sf::Vector2i(32, 32); tabs[ROOMS_TAB_INDEX].body->filter_search_fuzzy_item(search_filter_text, body_item.get()); tabs[ROOMS_TAB_INDEX].body->items.push_back(body_item); - body_items_by_room[room] = { body_item, true, 0 }; + room->userdata = body_item.get(); } if(current_room) return; current_room = rooms[0]; - auto room_body_item_it = body_items_by_room.find(current_room); - if(room_body_item_it != body_items_by_room.end()) { - current_room_body_data = &room_body_item_it->second; - room_name_text.setString(current_room_body_data->body_item->get_title()); - } + room_name_text.setString(static_cast(current_room->userdata)->get_title()); }; float tab_shade_height = 0.0f; @@ -3738,8 +3712,8 @@ namespace QuickMedia { ++it; } - if(current_room_body_data && room_avatar_thumbnail_data->loading_state == LoadingState::NOT_LOADED) - async_image_loader.load_thumbnail(current_room_body_data->body_item->thumbnail_url, false, sf::Vector2i(32, 32), use_tor, room_avatar_thumbnail_data); + if(current_room && current_room->userdata && room_avatar_thumbnail_data->loading_state == LoadingState::NOT_LOADED) + async_image_loader.load_thumbnail(static_cast(current_room->userdata)->thumbnail_url, false, sf::Vector2i(32, 32), use_tor, room_avatar_thumbnail_data); if(room_avatar_thumbnail_data->loading_state == LoadingState::FINISHED_LOADING && room_avatar_thumbnail_data->image->getSize().x > 0 && room_avatar_thumbnail_data->image->getSize().y > 0) { if(!room_avatar_thumbnail_data->texture.loadFromImage(*room_avatar_thumbnail_data->image)) @@ -3987,20 +3961,23 @@ namespace QuickMedia { tabs[MESSAGES_TAB_INDEX].body->draw_item(window, currently_operating_on_item.get(), body_item_pos, body_item_size); } - if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room_body_data) { + if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room && current_room->userdata) { if(tabs[selected_tab].body->is_last_item_fully_visible()) { - if(!current_room_body_data->last_message_read) { - std::string room_desc = current_room_body_data->body_item->get_description(); + if(!current_room->last_message_read) { + BodyItem *current_room_body_item = static_cast(current_room->userdata); + std::string room_desc = current_room_body_item->get_description(); if(strncmp(room_desc.c_str(), "Unread: ", 8) == 0) room_desc = room_desc.substr(8); if(room_desc.size() >= 25 && strncmp(room_desc.c_str() + room_desc.size() - 25, "\n** You were mentioned **", 25) == 0) room_desc = room_desc.substr(0, room_desc.size() - 25); - current_room_body_data->body_item->set_description(std::move(room_desc)); + current_room_body_item->set_description(std::move(room_desc)); // TODO: Show a line like nheko instead for unread messages, or something else - current_room_body_data->body_item->set_title_color(sf::Color::White); - current_room_body_data->last_message_read = true; + current_room_body_item->set_title_color(sf::Color::White); + current_room->last_message_read = true; + // TODO: Maybe set this instead when the mention is visible on the screen? + current_room->has_unread_mention = false; } - } else if(!current_room_body_data->last_message_read) { + } else if(!current_room->last_message_read) { window.draw(more_messages_below_rect); } } @@ -4014,15 +3991,15 @@ namespace QuickMedia { if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) { BodyItem *last_visible_item = tabs[selected_tab].body->get_last_fully_visible_item(); - if(is_window_focused && chat_state != ChatState::URL_SELECTION && current_room_body_data && last_visible_item && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { + if(is_window_focused && chat_state != ChatState::URL_SELECTION && current_room && last_visible_item && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) { Message *message = (Message*)last_visible_item->userdata; // TODO: What if two messages have the same timestamp? - if(message->timestamp > current_room_body_data->last_read_message_timestamp) { + if(message->timestamp > current_room->last_read_message_timestamp) { read_marker_timeout_ms = read_marker_timeout_ms_default; - current_room_body_data->last_read_message_timestamp = message->timestamp; + current_room->last_read_message_timestamp = message->timestamp; // TODO: What if the message is no longer valid? setting_read_marker = true; - std::shared_ptr room = current_room; + RoomData *room = current_room; set_read_marker_future = std::async(std::launch::async, [this, room, message]() mutable { if(matrix->set_read_marker(room, message) != PluginResult::OK) { fprintf(stderr, "Warning: failed to set read marker to %s\n", message->event_id.c_str()); diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index bfdd496..35f5302 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -139,19 +139,23 @@ namespace QuickMedia { void Matrix::get_room_join_updates(Rooms &new_rooms) { std::lock_guard lock(room_data_mutex); - new_rooms.insert(new_rooms.end(), rooms.begin() + room_list_read_index, rooms.end()); size_t num_new_rooms = rooms.size() - room_list_read_index; + size_t new_rooms_prev_size = new_rooms.size(); + new_rooms.resize(new_rooms_prev_size + num_new_rooms); + for(size_t i = new_rooms_prev_size; i < new_rooms.size(); ++i) { + new_rooms[i] = rooms[room_list_read_index + i].get(); + } room_list_read_index += num_new_rooms; } - PluginResult Matrix::get_all_synced_room_messages(std::shared_ptr room, Messages &messages) { + PluginResult Matrix::get_all_synced_room_messages(RoomData *room, Messages &messages) { room->acquire_room_lock(); messages = room->get_messages_thread_unsafe(); room->release_room_lock(); return PluginResult::OK; } - PluginResult Matrix::get_previous_room_messages(std::shared_ptr room, Messages &messages) { + PluginResult Matrix::get_previous_room_messages(RoomData *room, Messages &messages) { room->acquire_room_lock(); size_t num_messages_before = room->get_messages_thread_unsafe().size(); room->release_room_lock(); @@ -189,18 +193,19 @@ namespace QuickMedia { std::string room_id_str = room_id.GetString(); - auto room = get_room_by_id(room_id_str); + RoomData *room = get_room_by_id(room_id_str); if(!room) { - room = std::make_shared(); - room->id = room_id_str; - add_room(room); + auto new_room = std::make_unique(); + new_room->id = room_id_str; + room = new_room.get(); + add_room(std::move(new_room)); } const rapidjson::Value &state_json = GetMember(it.value, "state"); if(state_json.IsObject()) { const rapidjson::Value &events_json = GetMember(state_json, "events"); - events_add_user_info(events_json, room.get()); - events_set_room_name(events_json, room.get()); + events_add_user_info(events_json, room); + events_set_room_name(events_json, room); } const rapidjson::Value &timeline_json = GetMember(it.value, "timeline"); @@ -222,15 +227,15 @@ namespace QuickMedia { } const rapidjson::Value &events_json = GetMember(timeline_json, "events"); - events_add_user_info(events_json, room.get()); + events_add_user_info(events_json, room); events_add_messages(events_json, room, MessageDirection::AFTER, &room_messages, has_unread_notifications); - events_set_room_name(events_json, room.get()); + events_set_room_name(events_json, room); } const rapidjson::Value &ephemeral_json = GetMember(it.value, "ephemeral"); if(ephemeral_json.IsObject()) { const rapidjson::Value &events_json = GetMember(ephemeral_json, "events"); - events_add_user_read_markers(events_json, room.get()); + events_add_user_read_markers(events_json, room); } } @@ -443,7 +448,7 @@ namespace QuickMedia { return false; } - void Matrix::events_add_messages(const rapidjson::Value &events_json, std::shared_ptr &room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications) { + void Matrix::events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications) { if(!events_json.IsArray()) return; @@ -451,7 +456,7 @@ namespace QuickMedia { auto me = get_me(room_data); for(const rapidjson::Value &event_item_json : events_json.GetArray()) { - std::shared_ptr new_message = parse_message_event(event_item_json, room_data.get()); + std::shared_ptr new_message = parse_message_event(event_item_json, room_data); if(!new_message) continue; @@ -731,7 +736,7 @@ namespace QuickMedia { } } - PluginResult Matrix::get_previous_room_messages(std::shared_ptr &room_data) { + PluginResult Matrix::get_previous_room_messages(RoomData *room_data) { std::string from = room_data->prev_batch; if(from.empty()) { fprintf(stderr, "Info: missing previous batch for room: %s, using /sync next batch\n", room_data->id.c_str()); @@ -766,8 +771,8 @@ namespace QuickMedia { return PluginResult::ERR; const rapidjson::Value &state_json = GetMember(json_root, "state"); - events_add_user_info(state_json, room_data.get()); - events_set_room_name(state_json, room_data.get()); + events_add_user_info(state_json, room_data); + events_set_room_name(state_json, room_data); const rapidjson::Value &chunk_json = GetMember(json_root, "chunk"); events_add_messages(chunk_json, room_data, MessageDirection::BEFORE, nullptr, false); @@ -818,7 +823,7 @@ namespace QuickMedia { return "m.file"; } - PluginResult Matrix::post_message(std::shared_ptr room, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info) { + PluginResult Matrix::post_message(RoomData *room, const std::string &body, const std::optional &file_info, const std::optional &thumbnail_info) { char random_characters[18]; if(!generate_random_characters(random_characters, sizeof(random_characters))) return PluginResult::ERR; @@ -990,11 +995,11 @@ namespace QuickMedia { } // TODO: Support greentext - PluginResult Matrix::post_reply(std::shared_ptr room, const std::string &body, void *relates_to) { + PluginResult Matrix::post_reply(RoomData *room, const std::string &body, void *relates_to) { // TODO: Store shared_ptr instead of raw pointer... Message *relates_to_message_raw = (Message*)relates_to; std::shared_ptr relates_to_message_shared = room->get_message_by_id(relates_to_message_raw->event_id); - std::shared_ptr relates_to_message_original = get_edited_message_original_message(room.get(), relates_to_message_shared); + std::shared_ptr relates_to_message_original = get_edited_message_original_message(room, relates_to_message_shared); if(!relates_to_message_original) { fprintf(stderr, "Failed to get the original message for message with event id: %s\n", relates_to_message_raw->event_id.c_str()); return PluginResult::ERR; @@ -1051,10 +1056,10 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult Matrix::post_edit(std::shared_ptr room, const std::string &body, void *relates_to) { + PluginResult Matrix::post_edit(RoomData *room, const std::string &body, void *relates_to) { Message *relates_to_message_raw = (Message*)relates_to; std::shared_ptr relates_to_message_shared = room->get_message_by_id(relates_to_message_raw->event_id); - std::shared_ptr relates_to_message_original = get_edited_message_original_message(room.get(), relates_to_message_shared); + std::shared_ptr relates_to_message_original = get_edited_message_original_message(room, relates_to_message_shared); if(!relates_to_message_original) { fprintf(stderr, "Failed to get the original message for message with event id: %s\n", relates_to_message_raw->event_id.c_str()); return PluginResult::ERR; @@ -1205,7 +1210,7 @@ namespace QuickMedia { return filename; } - PluginResult Matrix::post_file(std::shared_ptr room, const std::string &filepath, std::string &err_msg) { + PluginResult Matrix::post_file(RoomData *room, const std::string &filepath, std::string &err_msg) { UploadInfo file_info; UploadInfo thumbnail_info; PluginResult upload_file_result = upload_file(room, filepath, file_info, thumbnail_info, err_msg); @@ -1221,7 +1226,7 @@ namespace QuickMedia { return post_message(room, filename, file_info_opt, thumbnail_info_opt); } - PluginResult Matrix::upload_file(std::shared_ptr room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg) { + PluginResult Matrix::upload_file(RoomData *room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg) { FileAnalyzer file_analyzer; if(!file_analyzer.load_file(filepath.c_str())) { err_msg = "Failed to load " + filepath; @@ -1400,6 +1405,7 @@ namespace QuickMedia { // Make sure all fields are reset here! rooms.clear(); + room_list_read_index = 0; room_data_by_id.clear(); user_id.clear(); username.clear(); @@ -1411,7 +1417,7 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult Matrix::delete_message(std::shared_ptr room, void *message, std::string &err_msg){ + PluginResult Matrix::delete_message(RoomData *room, void *message, std::string &err_msg){ char random_characters[18]; if(!generate_random_characters(random_characters, sizeof(random_characters))) return PluginResult::ERR; @@ -1517,7 +1523,7 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult Matrix::on_start_typing(std::shared_ptr room) { + PluginResult Matrix::on_start_typing(RoomData *room) { rapidjson::Document request_data(rapidjson::kObjectType); request_data.AddMember("typing", true, request_data.GetAllocator()); request_data.AddMember("timeout", 30000, request_data.GetAllocator()); // 30 sec timeout @@ -1540,7 +1546,7 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult Matrix::on_stop_typing(std::shared_ptr room) { + PluginResult Matrix::on_stop_typing(RoomData *room) { rapidjson::Document request_data(rapidjson::kObjectType); request_data.AddMember("typing", false, request_data.GetAllocator()); @@ -1562,7 +1568,7 @@ namespace QuickMedia { return PluginResult::OK; } - PluginResult Matrix::set_read_marker(std::shared_ptr room, const Message *message) { + PluginResult Matrix::set_read_marker(RoomData *room, const Message *message) { rapidjson::Document request_data(rapidjson::kObjectType); request_data.AddMember("m.fully_read", rapidjson::StringRef(message->event_id.c_str()), request_data.GetAllocator()); request_data.AddMember("m.read", rapidjson::StringRef(message->event_id.c_str()), request_data.GetAllocator()); @@ -1628,22 +1634,22 @@ namespace QuickMedia { return PluginResult::OK; } - std::shared_ptr Matrix::get_me(std::shared_ptr room) { + std::shared_ptr Matrix::get_me(RoomData *room) { return room->get_user_by_id(user_id); } - std::shared_ptr Matrix::get_room_by_id(const std::string &id) { + RoomData* Matrix::get_room_by_id(const std::string &id) { std::lock_guard lock(room_data_mutex); auto room_it = room_data_by_id.find(id); if(room_it == room_data_by_id.end()) return nullptr; - return rooms[room_it->second]; + return rooms[room_it->second].get(); } - void Matrix::add_room(std::shared_ptr room) { + void Matrix::add_room(std::unique_ptr room) { std::lock_guard lock(room_data_mutex); room_data_by_id.insert(std::make_pair(room->id, rooms.size())); - rooms.push_back(room); + rooms.push_back(std::move(room)); } DownloadResult Matrix::download_json(rapidjson::Document &result, const std::string &url, std::vector additional_args, bool use_browser_useragent, std::string *err_msg) const { -- cgit v1.2.3