1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef NET_BASE_PRIORITY_QUEUE_H_
6 #define NET_BASE_PRIORITY_QUEUE_H_
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/threading/non_thread_safe.h"
14 #include "net/base/net_export.h"
17 #include "base/containers/hash_tables.h"
22 // A simple priority queue. The order of values is by priority and then FIFO.
23 // Unlike the std::priority_queue, this implementation allows erasing elements
24 // from the queue, and all operations are O(p) time for p priority levels.
25 // The queue is agnostic to priority ordering (whether 0 precedes 1).
26 // If the highest priority is 0, FirstMin() returns the first in order.
28 // In debug-mode, the internal queues store (id, value) pairs where id is used
29 // to validate Pointers.
32 class PriorityQueue : public base::NonThreadSafe {
34 // This section is up-front for Pointer only.
36 typedef std::list<std::pair<unsigned, T> > List;
38 typedef std::list<T> List;
42 typedef uint32 Priority;
44 // A pointer to a value stored in the queue. The pointer becomes invalid
45 // when the queue is destroyed or cleared, or the value is erased.
48 // Constructs a null pointer.
49 Pointer() : priority_(kNullPriority) {
51 id_ = static_cast<unsigned>(-1);
55 Pointer(const Pointer& p) : priority_(p.priority_), iterator_(p.iterator_) {
61 Pointer& operator=(const Pointer& p) {
62 // Self-assignment is benign.
63 priority_ = p.priority_;
64 iterator_ = p.iterator_;
71 bool is_null() const { return priority_ == kNullPriority; }
73 Priority priority() const { return priority_; }
76 const T& value() const { return iterator_->second; }
78 const T& value() const { return *iterator_; }
81 // Comparing to Pointer from a different PriorityQueue is undefined.
82 bool Equals(const Pointer& other) const {
83 return (priority_ == other.priority_) && (iterator_ == other.iterator_);
91 friend class PriorityQueue;
93 // Note that we need iterator and not const_iterator to pass to
94 // List::erase. When C++11 is turned on for Chromium, this could
95 // be changed to const_iterator and the const_casts in the rest of
96 // the file can be removed.
97 typedef typename PriorityQueue::List::iterator ListIterator;
99 static const Priority kNullPriority = static_cast<Priority>(-1);
101 // It is guaranteed that Pointer will treat |iterator| as a
103 Pointer(Priority priority, const ListIterator& iterator)
104 : priority_(priority), iterator_(iterator) {
106 id_ = iterator_->first;
111 ListIterator iterator_;
114 // Used by the queue to check if a Pointer is valid.
119 // Creates a new queue for |num_priorities|.
120 explicit PriorityQueue(Priority num_priorities)
121 : lists_(num_priorities), size_(0) {
127 // Adds |value| with |priority| to the queue. Returns a pointer to the
129 Pointer Insert(const T& value, Priority priority) {
130 DCHECK(CalledOnValidThread());
131 DCHECK_LT(priority, lists_.size());
133 List& list = lists_[priority];
135 unsigned id = next_id_;
136 valid_ids_.insert(id);
138 return Pointer(priority, list.insert(list.end(),
139 std::make_pair(id, value)));
141 return Pointer(priority, list.insert(list.end(), value));
145 // Adds |value| with |priority| to the queue. Returns a pointer to the
147 Pointer InsertAtFront(const T& value, Priority priority) {
148 DCHECK(CalledOnValidThread());
149 DCHECK_LT(priority, lists_.size());
151 List& list = lists_[priority];
153 unsigned id = next_id_;
154 valid_ids_.insert(id);
156 return Pointer(priority, list.insert(list.begin(),
157 std::make_pair(id, value)));
159 return Pointer(priority, list.insert(list.begin(), value));
163 // Removes the value pointed by |pointer| from the queue. All pointers to this
164 // value including |pointer| become invalid.
165 void Erase(const Pointer& pointer) {
166 DCHECK(CalledOnValidThread());
167 DCHECK_LT(pointer.priority_, lists_.size());
168 DCHECK_GT(size_, 0u);
171 DCHECK_EQ(1u, valid_ids_.erase(pointer.id_));
172 DCHECK_EQ(pointer.iterator_->first, pointer.id_);
176 lists_[pointer.priority_].erase(pointer.iterator_);
179 // Returns a pointer to the first value of minimum priority or a null-pointer
181 Pointer FirstMin() const {
182 DCHECK(CalledOnValidThread());
183 for (size_t i = 0; i < lists_.size(); ++i) {
184 List* list = const_cast<List*>(&lists_[i]);
186 return Pointer(i, list->begin());
191 // Returns a pointer to the last value of minimum priority or a null-pointer
193 Pointer LastMin() const {
194 DCHECK(CalledOnValidThread());
195 for (size_t i = 0; i < lists_.size(); ++i) {
196 List* list = const_cast<List*>(&lists_[i]);
198 return Pointer(i, --list->end());
203 // Returns a pointer to the first value of maximum priority or a null-pointer
205 Pointer FirstMax() const {
206 DCHECK(CalledOnValidThread());
207 for (size_t i = lists_.size(); i > 0; --i) {
208 size_t index = i - 1;
209 List* list = const_cast<List*>(&lists_[index]);
211 return Pointer(index, list->begin());
216 // Returns a pointer to the last value of maximum priority or a null-pointer
218 Pointer LastMax() const {
219 DCHECK(CalledOnValidThread());
220 for (size_t i = lists_.size(); i > 0; --i) {
221 size_t index = i - 1;
222 List* list = const_cast<List*>(&lists_[index]);
224 return Pointer(index, --list->end());
229 // Given an ordering of the values in this queue by decreasing
230 // priority and then FIFO, returns a pointer to the value following
231 // the value of the given pointer (which must be non-NULL).
233 // (One could also implement GetNextTowardsFirstMin() [decreasing
234 // priority, then reverse FIFO] as well as
235 // GetNextTowards{First,Last}Max() [increasing priority, then
236 // {,reverse} FIFO].)
237 Pointer GetNextTowardsLastMin(const Pointer& pointer) const {
238 DCHECK(CalledOnValidThread());
239 DCHECK(!pointer.is_null());
240 DCHECK_LT(pointer.priority_, lists_.size());
242 typename Pointer::ListIterator it = pointer.iterator_;
243 Priority priority = pointer.priority_;
244 DCHECK(it != lists_[priority].end());
246 while (it == lists_[priority].end()) {
250 it = const_cast<List*>(&lists_[priority])->begin();
252 return Pointer(priority, it);
255 // Empties the queue. All pointers become invalid.
257 DCHECK(CalledOnValidThread());
258 for (size_t i = 0; i < lists_.size(); ++i) {
267 // Returns the number of priorities the queue supports.
268 size_t num_priorities() const {
269 DCHECK(CalledOnValidThread());
270 return lists_.size();
274 DCHECK(CalledOnValidThread());
278 // Returns number of queued values.
279 size_t size() const {
280 DCHECK(CalledOnValidThread());
285 typedef std::vector<List> ListVector;
289 base::hash_set<unsigned> valid_ids_;
295 DISALLOW_COPY_AND_ASSIGN(PriorityQueue);
300 #endif // NET_BASE_PRIORITY_QUEUE_H_