blob: d11ffccd0474bfb1245e11c8279f664191b0e1c9 [file] [log] [blame]
[email protected]ba79eca2012-01-06 21:03:561// 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.
4
5#ifndef NET_BASE_PRIORITY_QUEUE_H_
6#define NET_BASE_PRIORITY_QUEUE_H_
7#pragma once
8
9#include <list>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/logging.h"
14#include "base/threading/non_thread_safe.h"
15#include "net/base/net_export.h"
16
17#if !defined(NDEBUG)
18#include "base/hash_tables.h"
19#endif
20
21namespace net {
22
23// A simple priority queue. The order of values is by priority and then FIFO.
24// Unlike the std::priority_queue, this implementation allows erasing elements
25// from the queue, and all operations are O(p) time for p priority levels.
26// The queue is agnostic to priority ordering (whether 0 precedes 1).
27// If the highest priority is 0, FirstMin() returns the first in order.
28//
29// In debug-mode, the internal queues store (id, value) pairs where id is used
30// to validate Pointers.
31//
32template<typename T>
33class PriorityQueue : public base::NonThreadSafe {
34 private:
35 // This section is up-front for Pointer only.
36#if !defined(NDEBUG)
[email protected]043324f42012-06-02 00:18:5337 typedef std::list<std::pair<unsigned, T> > List;
[email protected]ba79eca2012-01-06 21:03:5638#else
39 typedef std::list<T> List;
40#endif
41
42 public:
43 typedef uint32 Priority;
44
45 // A pointer to a value stored in the queue. The pointer becomes invalid
46 // when the queue is destroyed or cleared, or the value is erased.
47 class Pointer {
48 public:
49 // Constructs a null pointer.
[email protected]b3601bc22012-02-21 21:23:2050 Pointer() : priority_(kNullPriority) {
51#if !defined(NDEBUG)
[email protected]043324f42012-06-02 00:18:5352 id_ = static_cast<unsigned>(-1);
[email protected]b3601bc22012-02-21 21:23:2053#endif
54 }
[email protected]ba79eca2012-01-06 21:03:5655
[email protected]043324f42012-06-02 00:18:5356 Pointer(const Pointer& p) : priority_(p.priority_), iterator_(p.iterator_) {
57#if !defined(NDEBUG)
58 id_ = p.id_;
59#endif
60 }
61
62 Pointer& operator=(const Pointer& p) {
63 // Self-assignment is benign.
64 priority_ = p.priority_;
65 iterator_ = p.iterator_;
66#if !defined(NDEBUG)
67 id_ = p.id_;
68#endif
69 return *this;
70 }
71
[email protected]ba79eca2012-01-06 21:03:5672 bool is_null() const { return priority_ == kNullPriority; }
73
74 Priority priority() const { return priority_; }
75
76#if !defined(NDEBUG)
77 const T& value() const { return iterator_->second; }
78#else
79 const T& value() const { return *iterator_; }
80#endif
81
82 // Comparing to Pointer from a different PriorityQueue is undefined.
83 bool Equals(const Pointer& other) const {
84 return (priority_ == other.priority_) && (iterator_ == other.iterator_);
85 }
86
[email protected]b3601bc22012-02-21 21:23:2087 void Reset() {
88 *this = Pointer();
89 }
90
[email protected]ba79eca2012-01-06 21:03:5691 private:
92 friend class PriorityQueue;
93
94 // Note that we need iterator not const_iterator to pass to List::erase.
95 // When C++0x comes, this could be changed to const_iterator and const could
96 // be added to First, Last, and OldestLowest.
97 typedef typename PriorityQueue::List::iterator ListIterator;
98
99 static const Priority kNullPriority = static_cast<Priority>(-1);
100
101 Pointer(Priority priority, const ListIterator& iterator)
102 : priority_(priority), iterator_(iterator) {
103#if !defined(NDEBUG)
104 id_ = iterator_->first;
105#endif
106 }
107
108 Priority priority_;
109 ListIterator iterator_;
110
111#if !defined(NDEBUG)
112 // Used by the queue to check if a Pointer is valid.
[email protected]043324f42012-06-02 00:18:53113 unsigned id_;
[email protected]ba79eca2012-01-06 21:03:56114#endif
115 };
116
117 // Creates a new queue for |num_priorities|.
118 explicit PriorityQueue(Priority num_priorities)
119 : lists_(num_priorities), size_(0) {
120#if !defined(NDEBUG)
121 next_id_ = 0;
122#endif
123 }
124
125 // Adds |value| with |priority| to the queue. Returns a pointer to the
126 // created element.
127 Pointer Insert(const T& value, Priority priority) {
128 DCHECK(CalledOnValidThread());
129 DCHECK_LT(priority, lists_.size());
130 ++size_;
131 List& list = lists_[priority];
132#if !defined(NDEBUG)
[email protected]043324f42012-06-02 00:18:53133 unsigned id = next_id_;
[email protected]ba79eca2012-01-06 21:03:56134 valid_ids_.insert(id);
135 ++next_id_;
136 return Pointer(priority, list.insert(list.end(),
137 std::make_pair(id, value)));
138#else
139 return Pointer(priority, list.insert(list.end(), value));
140#endif
141 }
142
143 // Removes the value pointed by |pointer| from the queue. All pointers to this
144 // value including |pointer| become invalid.
145 void Erase(const Pointer& pointer) {
146 DCHECK(CalledOnValidThread());
147 DCHECK_LT(pointer.priority_, lists_.size());
148 DCHECK_GT(size_, 0u);
149
150#if !defined(NDEBUG)
151 DCHECK_EQ(1u, valid_ids_.erase(pointer.id_));
152 DCHECK_EQ(pointer.iterator_->first, pointer.id_);
153#endif
154
155 --size_;
156 lists_[pointer.priority_].erase(pointer.iterator_);
157 }
158
159 // Returns a pointer to the first value of minimum priority or a null-pointer
160 // if empty.
161 Pointer FirstMin() {
162 DCHECK(CalledOnValidThread());
163 for (size_t i = 0; i < lists_.size(); ++i) {
164 if (!lists_[i].empty())
165 return Pointer(i, lists_[i].begin());
166 }
167 return Pointer();
168 }
169
170 // Returns a pointer to the last value of minimum priority or a null-pointer
171 // if empty.
172 Pointer LastMin() {
173 DCHECK(CalledOnValidThread());
174 for (size_t i = 0; i < lists_.size(); ++i) {
175 if (!lists_[i].empty())
176 return Pointer(i, --lists_[i].end());
177 }
178 return Pointer();
179 }
180
181 // Returns a pointer to the first value of maximum priority or a null-pointer
182 // if empty.
183 Pointer FirstMax() {
184 DCHECK(CalledOnValidThread());
185 for (size_t i = lists_.size(); i > 0; --i) {
186 size_t index = i - 1;
187 if (!lists_[index].empty())
188 return Pointer(index, lists_[index].begin());
189 }
190 return Pointer();
191 }
192
193 // Returns a pointer to the last value of maximum priority or a null-pointer
194 // if empty.
195 Pointer LastMax() {
196 DCHECK(CalledOnValidThread());
197 for (size_t i = lists_.size(); i > 0; --i) {
198 size_t index = i - 1;
199 if (!lists_[index].empty())
200 return Pointer(index, --lists_[index].end());
201 }
202 return Pointer();
203 }
204
205 // Empties the queue. All pointers become invalid.
206 void Clear() {
207 DCHECK(CalledOnValidThread());
208 for (size_t i = 0; i < lists_.size(); ++i) {
209 lists_[i].clear();
210 }
211#if !defined(NDEBUG)
212 valid_ids_.clear();
213#endif
214 size_ = 0u;
215 }
216
217 // Returns number of queued values.
218 size_t size() const {
219 DCHECK(CalledOnValidThread());
220 return size_;
221 }
222
223 private:
224 typedef std::vector<List> ListVector;
225
226#if !defined(NDEBUG)
[email protected]043324f42012-06-02 00:18:53227 unsigned next_id_;
228 base::hash_set<unsigned> valid_ids_;
[email protected]ba79eca2012-01-06 21:03:56229#endif
230
231 ListVector lists_;
232 size_t size_;
[email protected]043324f42012-06-02 00:18:53233
234 DISALLOW_COPY_AND_ASSIGN(PriorityQueue);
[email protected]ba79eca2012-01-06 21:03:56235};
236
237} // namespace net
238
239#endif // NET_BASE_PRIORITY_QUEUE_H_