| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // This file is porting from |
| // https://github.com/trinodb/trino/blob/master/core/trino-main/src/main/java/io/trino/execution/resourcegroups/IndexedPriorityQueue.java |
| // to cpp and modified by Doris |
| |
| #pragma once |
| |
| #pragma once |
| |
| #include <functional> |
| #include <iostream> |
| #include <map> |
| #include <optional> |
| #include <set> |
| |
| /** |
| * A priority queue with constant time contains(E) and log time remove(E) |
| * Ties are broken by insertion order. |
| * LOW_TO_HIGH is the priority order from low to high, |
| * HIGH_TO_LOW is the priority order from high to low. |
| * Those with the same priority are arranged in order of insertion. |
| */ |
| |
| namespace doris { |
| |
| template <typename T> |
| struct IndexedPriorityQueueEntry { |
| T value; |
| long priority; |
| long generation; |
| |
| IndexedPriorityQueueEntry(T val, long prio, long gen) |
| : value(std::move(val)), priority(prio), generation(gen) {} |
| }; |
| |
| enum class IndexedPriorityQueuePriorityOrdering { LOW_TO_HIGH, HIGH_TO_LOW }; |
| |
| template <typename T, IndexedPriorityQueuePriorityOrdering priority_ordering> |
| struct IndexedPriorityQueueComparator { |
| bool operator()(const IndexedPriorityQueueEntry<T>& lhs, |
| const IndexedPriorityQueueEntry<T>& rhs) const { |
| if constexpr (priority_ordering == IndexedPriorityQueuePriorityOrdering::LOW_TO_HIGH) { |
| if (lhs.priority != rhs.priority) { |
| return lhs.priority < rhs.priority; |
| } |
| return lhs.generation < rhs.generation; |
| } else { |
| if (lhs.priority != rhs.priority) { |
| return lhs.priority > rhs.priority; |
| } |
| return lhs.generation < rhs.generation; |
| } |
| } |
| }; |
| |
| template <typename T, IndexedPriorityQueuePriorityOrdering priority_ordering = |
| IndexedPriorityQueuePriorityOrdering::HIGH_TO_LOW> |
| class IndexedPriorityQueue { |
| public: |
| struct Prioritized { |
| T value; |
| long priority; |
| }; |
| |
| IndexedPriorityQueue() = default; |
| |
| bool add_or_update(T element, long priority) { |
| auto it = _index.find(element); |
| if (it != _index.end()) { |
| if (it->second.priority == priority) { |
| return false; |
| } |
| _queue.erase(it->second); |
| } |
| IndexedPriorityQueueEntry<T> entry {std::move(element), priority, generation++}; |
| _queue.insert(std::move(entry)); |
| _index.insert({entry.value, std::move(entry)}); |
| return true; |
| } |
| |
| bool contains(const T& element) const { return _index.find(element) != _index.end(); } |
| |
| bool remove(const T& element) { |
| auto it = _index.find(element); |
| if (it != _index.end()) { |
| _queue.erase(it->second); |
| _index.erase(it); |
| return true; |
| } |
| return false; |
| } |
| |
| std::optional<T> poll() { |
| if (_queue.empty()) { |
| return std::nullopt; |
| } |
| T value = _queue.begin()->value; |
| _index.erase(value); |
| _queue.erase(_queue.begin()); |
| return value; |
| } |
| |
| std::optional<Prioritized> peek() const { |
| if (_queue.empty()) { |
| return std::nullopt; |
| } |
| const IndexedPriorityQueueEntry<T>& entry = *_queue.begin(); |
| return Prioritized {entry.value, entry.priority}; |
| } |
| |
| int size() const { return _queue.size(); } |
| |
| bool is_empty() const { return _queue.empty(); } |
| |
| class Iterator { |
| public: |
| using iterator_category = std::forward_iterator_tag; |
| using value_type = T; |
| using difference_type = std::ptrdiff_t; |
| using pointer = T*; |
| using reference = T&; |
| |
| Iterator() : _iter() {} |
| explicit Iterator( |
| typename std::set< |
| IndexedPriorityQueueEntry<T>, |
| IndexedPriorityQueueComparator<T, priority_ordering>>::const_iterator iter) |
| : _iter(iter) {} |
| |
| const T& operator*() const { return _iter->value; } |
| |
| const T* operator->() const { return &(_iter->value); } |
| |
| Iterator& operator++() { |
| ++_iter; |
| return *this; |
| } |
| |
| Iterator operator++(int) { |
| Iterator tmp = *this; |
| ++(*this); |
| return tmp; |
| } |
| |
| bool operator==(const Iterator& other) const { return _iter == other._iter; } |
| |
| bool operator!=(const Iterator& other) const { return !(*this == other); } |
| |
| private: |
| typename std::set<IndexedPriorityQueueEntry<T>, |
| IndexedPriorityQueueComparator<T, priority_ordering>>::const_iterator |
| _iter; |
| }; |
| |
| Iterator begin() const { return Iterator(_queue.begin()); } |
| |
| Iterator end() const { return Iterator(_queue.end()); } |
| |
| private: |
| std::map<T, IndexedPriorityQueueEntry<T>> _index; |
| std::set<IndexedPriorityQueueEntry<T>, IndexedPriorityQueueComparator<T, priority_ordering>> |
| _queue; |
| |
| long generation = 0; |
| }; |
| |
| } // namespace doris |