#pragma once #include #include #include #include #include #include #include // NOLINT namespace data { /// Thread safe queue with unique keys updating priority and value template > class safe_priority_queue_map { private: static bool cmpByWeight(const std::pair &a, const std::pair &b) { return a.second < b.second; } std::vector> heap; robin_hood::unordered_map map; TracyLockableN(std::mutex, mutex, "PriorityQueueMap"); std::condition_variable_any cv; public: std::pair, std::unique_lock> inserter() { return std::make_pair([&](const K& key, const V& val, const W& weight) { heap.emplace_back(key, weight); std::push_heap(heap.begin(), heap.end(), cmpByWeight); map.insert_or_assign(key, val); }, std::unique_lock(mutex)); } void push(const K& key, const V& val, const W& weight) { std::unique_lock lock(mutex); heap.emplace_back(key, weight); std::push_heap(heap.begin(), heap.end(), cmpByWeight); map.insert_or_assign(key, val); cv.notify_one(); } bool pop(std::pair& out) { std::unique_lock lock(mutex); if (heap.empty()) return false; std::pop_heap(heap.begin(), heap.end(), cmpByWeight); const auto priority = heap.back(); heap.pop_back(); const auto it = map.find(priority.first); if(it == map.end()) return false; out = std::make_pair(it->first, it->second); map.erase(it); return true; } bool empty() { std::unique_lock lock(mutex); return heap.empty(); } size_t size() { std::unique_lock lock(mutex); return map.size(); } void notify_all() { cv.notify_all(); } void notify_one() { cv.notify_one(); } void wait() { std::unique_lock lock(mutex); if (heap.empty()) cv.wait(lock); } }; /// Thread safe queue with unique keys updating priority template class safe_priority_queue { private: static bool cmpByWeight(const std::pair &a, const std::pair &b) { return a.second < b.second; } std::vector> heap; robin_hood::unordered_flat_set set; TracyLockableN(std::mutex, mutex, "PriorityQueue"); std::condition_variable_any cv; public: std::pair, std::unique_lock> inserter() { return std::make_pair([&](const K& key, const W& weight) { heap.emplace_back(key, weight); std::push_heap(heap.begin(), heap.end(), cmpByWeight); set.insert(key); }, std::unique_lock(mutex)); } void push(const K& key, const W& weight) { std::unique_lock lock(mutex); heap.emplace_back(key, weight); std::push_heap(heap.begin(), heap.end(), cmpByWeight); set.insert(key); cv.notify_one(); } bool pop(K& out) { std::unique_lock lock(mutex); if (heap.empty()) return false; std::pop_heap(heap.begin(), heap.end(), cmpByWeight); const auto priority = heap.back(); heap.pop_back(); const auto it = set.find(priority.first); if(it == set.end()) return false; out = *it; set.erase(it); return true; } bool empty() { std::unique_lock lock(mutex); return heap.empty(); } size_t size() { std::unique_lock lock(mutex); return set.size(); } void notify_all() { cv.notify_all(); } void notify_one() { cv.notify_one(); } void wait() { std::unique_lock lock(mutex); if (heap.empty()) cv.wait(lock); } }; }