#ifndef NET_BASE_PRIORITY_QUEUE_H_
#define NET_BASE_PRIORITY_QUEUE_H_
#include <stddef.h>
#include <stdint.h>
#include <list>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/threading/thread_checker.h"
#if !defined(NDEBUG)
#include <unordered_set>
#endif
namespace net {
template <typename T>
class PriorityQueue {
private:
#if !defined(NDEBUG)
typedef std::list<std::pair<unsigned, T> > List;
#else
typedef std::list<T> List;
#endif
public:
typedef uint32_t Priority;
class Pointer {
public:
Pointer() : priority_(kNullPriority) {
#if !defined(NDEBUG)
id_ = static_cast<unsigned>(-1);
#endif
iterator_ = dummy_empty_list_.end();
}
Pointer(const Pointer& p)
: priority_(p.priority_),
iterator_(p.iterator_) {
#if !defined(NDEBUG)
id_ = p.id_;
#endif
}
Pointer& operator=(const Pointer& p) {
priority_ = p.priority_;
iterator_ = p.iterator_;
#if !defined(NDEBUG)
id_ = p.id_;
#endif
return *this;
}
bool is_null() const { return priority_ == kNullPriority; }
Priority priority() const { return priority_; }
#if !defined(NDEBUG)
const T& value() const { return iterator_->second; }
#else
const T& value() const { return *iterator_; }
#endif
bool Equals(const Pointer& other) const {
return (priority_ == other.priority_) && (iterator_ == other.iterator_);
}
void Reset() {
*this = Pointer();
}
private:
friend class PriorityQueue;
typedef typename PriorityQueue::List::iterator ListIterator;
static const Priority kNullPriority = static_cast<Priority>(-1);
Pointer(Priority priority, const ListIterator& iterator)
: priority_(priority), iterator_(iterator) {
#if !defined(NDEBUG)
id_ = iterator_->first;
#endif
}
Priority priority_;
ListIterator iterator_;
List dummy_empty_list_;
#if !defined(NDEBUG)
unsigned id_;
#endif
};
explicit PriorityQueue(Priority num_priorities) : lists_(num_priorities) {
#if !defined(NDEBUG)
next_id_ = 0;
#endif
}
PriorityQueue(const PriorityQueue&) = delete;
PriorityQueue& operator=(const PriorityQueue&) = delete;
~PriorityQueue() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); }
Pointer Insert(T value, Priority priority) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_LT(priority, lists_.size());
++size_;
List& list = lists_[priority];
#if !defined(NDEBUG)
unsigned id = next_id_;
valid_ids_.insert(id);
++next_id_;
list.emplace_back(std::make_pair(id, std::move(value)));
#else
list.emplace_back(std::move(value));
#endif
return Pointer(priority, std::prev(list.end()));
}
Pointer InsertAtFront(T value, Priority priority) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_LT(priority, lists_.size());
++size_;
List& list = lists_[priority];
#if !defined(NDEBUG)
unsigned id = next_id_;
valid_ids_.insert(id);
++next_id_;
list.emplace_front(std::make_pair(id, std::move(value)));
#else
list.emplace_front(std::move(value));
#endif
return Pointer(priority, list.begin());
}
T Erase(const Pointer& pointer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_LT(pointer.priority_, lists_.size());
DCHECK_GT(size_, 0u);
#if !defined(NDEBUG)
DCHECK_EQ(1u, valid_ids_.erase(pointer.id_));
DCHECK_EQ(pointer.iterator_->first, pointer.id_);
T erased = std::move(pointer.iterator_->second);
#else
T erased = std::move(*pointer.iterator_);
#endif
--size_;
lists_[pointer.priority_].erase(pointer.iterator_);
return erased;
}
Pointer FirstMin() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (size_t i = 0; i < lists_.size(); ++i) {
List* list = const_cast<List*>(&lists_[i]);
if (!list->empty())
return Pointer(i, list->begin());
}
return Pointer();
}
Pointer LastMin() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (size_t i = 0; i < lists_.size(); ++i) {
List* list = const_cast<List*>(&lists_[i]);
if (!list->empty())
return Pointer(i, --list->end());
}
return Pointer();
}
Pointer FirstMax() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (size_t i = lists_.size(); i > 0; --i) {
size_t index = i - 1;
List* list = const_cast<List*>(&lists_[index]);
if (!list->empty())
return Pointer(index, list->begin());
}
return Pointer();
}
Pointer LastMax() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (size_t i = lists_.size(); i > 0; --i) {
size_t index = i - 1;
List* list = const_cast<List*>(&lists_[index]);
if (!list->empty())
return Pointer(index, --list->end());
}
return Pointer();
}
Pointer GetNextTowardsLastMin(const Pointer& pointer) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!pointer.is_null());
DCHECK_LT(pointer.priority_, lists_.size());
typename Pointer::ListIterator it = pointer.iterator_;
Priority priority = pointer.priority_;
DCHECK(it != lists_[priority].end());
++it;
while (it == lists_[priority].end()) {
if (priority == 0u) {
DCHECK(pointer.Equals(LastMin()));
return Pointer();
}
--priority;
it = const_cast<List*>(&lists_[priority])->begin();
}
return Pointer(priority, it);
}
Pointer GetPreviousTowardsFirstMax(const Pointer& pointer) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!pointer.is_null());
DCHECK_LT(pointer.priority_, lists_.size());
typename Pointer::ListIterator it = pointer.iterator_;
Priority priority = pointer.priority_;
DCHECK(it != lists_[priority].end());
while (it == lists_[priority].begin()) {
if (priority == num_priorities() - 1) {
DCHECK(pointer.Equals(FirstMax()));
return Pointer();
}
++priority;
it = const_cast<List*>(&lists_[priority])->end();
}
return Pointer(priority, std::prev(it));
}
bool IsCloserToFirstMaxThan(const Pointer& lhs, const Pointer& rhs) {
if (lhs.Equals(rhs))
return false;
if (lhs.priority_ == rhs.priority_) {
for (auto it = lhs.iterator_; it != lists_[lhs.priority_].end(); ++it) {
if (it == rhs.iterator_)
return true;
}
return false;
}
return lhs.priority_ > rhs.priority_;
}
bool IsCloserToLastMinThan(const Pointer& lhs, const Pointer& rhs) {
return !lhs.Equals(rhs) && !IsCloserToFirstMaxThan(lhs, rhs);
}
Pointer FindIf(const base::RepeatingCallback<bool(T)>& pred) {
for (auto pointer = FirstMax(); !pointer.is_null();
pointer = GetNextTowardsLastMin(pointer)) {
if (pred.Run(pointer.value()))
return pointer;
}
return Pointer();
}
void Clear() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (size_t i = 0; i < lists_.size(); ++i) {
lists_[i].clear();
}
#if !defined(NDEBUG)
valid_ids_.clear();
#endif
size_ = 0u;
}
size_t num_priorities() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return lists_.size();
}
bool empty() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return size_ == 0;
}
size_t size() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return size_;
}
private:
typedef std::vector<List> ListVector;
#if !defined(NDEBUG)
unsigned next_id_;
std::unordered_set<unsigned> valid_ids_;
#endif
ListVector lists_;
size_t size_ = 0;
THREAD_CHECKER(thread_checker_);
};
}
#endif