Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(802)

Side by Side Diff: tests/standalone/priority_queue_stress_test.dart

Issue 689713003: Context objects don't have a compile-type. Return dynamic-type in this case. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_type_propagator.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library priority_queue;
6
7 import 'dart:collection';
8 import 'dart:math';
9
10 /**
11 * A priority used for the priority queue. Subclasses only need to implement
12 * the compareTo function.
13 */
14 abstract class Priority implements Comparable {
15 /**
16 * Return < 0 if other is bigger, >0 if other is smaller, 0 if they are equal.
17 */
18 int compareTo(Priority other);
19 bool operator<(Priority other) => compareTo(other) < 0;
20 bool operator>(Priority other) => compareTo(other) > 0;
21 bool operator==(Priority other) => compareTo(other) == 0;
22 }
23
24 /**
25 * Priority based on integers.
26 */
27 class IntPriority extends Priority {
28 int priority;
29 IntPriority(int this.priority);
30
31 int compareTo(IntPriority other) {
32 return priority - other.priority;
33 }
34 String toString() => "$priority";
35 }
36
37 /**
38 * An element of a priority queue. The type is used restriction based
39 * querying of the queues.
40 */
41 abstract class TypedElement<V> {
42 bool typeEquals(var other);
43 }
44
45 class StringTypedElement<V> extends TypedElement{
46 String type;
47 V value;
48 StringTypedElement(String this.type, V this.value);
49 bool typeEquals(String otherType) => otherType == type;
50 String toString() => "<Type: $type, Value: $value>";
51 }
52
53
54 /**
55 * A priority node in a priority queue. A priority node contains all of the
56 * values for a given priority in a given queue. It is part of a linked
57 * list of nodes, with prev and next pointers.
58 */
59 class PriorityNode<N extends TypedElement, T extends Priority> {
60 T priority;
61 Queue<N> values;
62 PriorityNode prev;
63 PriorityNode next;
64 PriorityNode(N initialNode, T this.priority)
65 : values = new Queue<N>() {
66 add(initialNode);
67 }
68
69 void add(N n) => values.add(n);
70
71 bool remove(N n) => values.remove(n);
72
73 N removeFirst() => values.removeFirst();
74
75 bool get isEmpty => values.isEmpty;
76
77 N get first => values.first;
78
79 String toString() => "Priority: $priority $values";
80 }
81
82 /**
83 * A priority queue with a FIFO property for nodes with same priority.
84 * The queue guarantees that nodes are returned in the same order they
85 * are added for a given priority.
86 * For type safety this queue is guarded by the elements being subclasses of
87 * TypedElement - this is not strictly neccesary since we never actually
88 * use the value or type of the nodes.
89 */
90 class PriorityQueue<N extends TypedElement, P extends Priority> {
91 PriorityNode<N, P> head;
92 int length = 0;
93
94 void add(N value, P priority) {
95 length++;
96 if (head == null) {
97 head = new PriorityNode<N, P>(value, priority);
98 return;
99 }
100 assert(head.next == null);
101 var node = head;
102 while (node.prev != null && node.priority > priority) {
103 node = node.prev;
104 }
105 if (node.priority == priority) {
106 node.add(value);
107 } else if (node.priority < priority) {
108 var newNode = new PriorityNode<N, P>(value, priority);
109 newNode.next = node.next;
110 if (node.next != null) node.next.prev = newNode;
111 newNode.prev = node;
112 node.next = newNode;
113 if (node == head) head = newNode;
114 } else {
115 var newNode = new PriorityNode<N, P>(value, priority);
116 node.prev = newNode;
117 newNode.next = node;
118 }
119 }
120
121 N get first => head.first;
122
123 Priority get firstPriority => head.priority;
124
125 bool get isEmpty => head == null;
126
127 N removeFirst() {
128 if (isEmpty) throw "Can't get element from empty queue";
129 var value = head.removeFirst();
130 if (head.isEmpty) {
131 if (head.prev != null) {
132 head.prev.next = null;
133 }
134 head = head.prev;
135 }
136 length--;
137 assert(head == null || head.next == null);
138 return value;
139 }
140
141 String toString() {
142 if (head == null) return "Empty priority queue";
143 var node = head;
144 var buffer = new StringBuffer();
145 while (node.prev != null) {
146 buffer.writeln(node);
147 node = node.prev;
148 }
149 buffer.writeln(node);
150 return buffer.toString();
151 }
152 }
153
154 /**
155 * Implements a specialized priority queue that efficiently allows getting
156 * the highest priorized node that adheres to a set of restrictions.
157 * Most notably it allows to get the highest priority node where the node's
158 * type is not in an exclude list.
159 * In addition, the queue has a number of properties:
160 * The queue has fifo semantics for nodes with the same priority and type,
161 * i.e., if nodes a and b are added to the queue with priority x and type z
162 * then a is returned first iff a was added before b
163 * For different types with the same priority no guarantees are given, but
164 * the returned values try to be fair by returning from the biggest list of
165 * tasks in case of priority clash. (This could be fixed by adding timestamps
166 * to every node, that is _only_ used when collisions occur, not for
167 * insertions)
168 */
169 class RestrictViewPriorityQueue<N extends TypedElement, P extends Priority> {
170 // We can't use the basic dart priority queue since it does not guarantee
171 // FIFO for items with the same order. This is currently not uptimized for
172 // different N, if many different N is expected here we should have a
173 // priority queue instead of a list.
174 List<PriorityQueue<N, P>> restrictedQueues = new List<PriorityQueue<N, P>>();
175 PriorityQueue<N, P> mainQueue = new PriorityQueue<N, P>();
176
177 void add(N value, P priority) {
178 for (var queue in restrictedQueues) {
179 if (queue.first.value == value) {
180 queue.add(value, priority);
181 }
182 }
183 mainQueue.add(value, priority);
184 }
185
186 bool get isEmpty => restrictedQueues.length + mainQueue.length == 0;
187
188 int get length => restrictedQueues.fold(0, (v, e) => v + element.length) +
189 mainQueue.length;
190
191 PriorityQueue getRestricted(List<N> restrictions) {
192 var current = null;
193 // Find highest restricted priority.
194 for (var queue in restrictedQueues) {
195 if (!restrictions.any((e) => queue.head.first.typeEquals(e))) {
196 if (current == null || queue.firstPriority > current.firstPriority) {
197 current = queue;
198 } else if (current.firstPriority == queue.firstPriority) {
199 current = queue.length > current.length ? queue : current;
200 }
201 }
202 }
203 return current;
204 }
205
206 N get first {
207 if (isEmpty) throw "Trying to remove node from empty queue";
208 var candidate = getRestricted([]);
209 if (candidate != null &&
210 (mainQueue.isEmpty ||
211 mainQueue.first.priority < candidate.first.priority)) {
212 return candidate.first;
213 }
214 return mainQueue.isEmpty ? null : mainQueue.first;
215 }
216
217 /**
218 * Returns the node that under the given set of restrictions.
219 * If the queue is empty this function throws.
220 * If the queue is not empty, but no node exists that adheres to the
221 * restrictions we return null.
222 */
223 N removeFirst({List restrictions: const []}) {
224 if (isEmpty) throw "Trying to remove node from empty queue";
225 var candidate = getRestricted(restrictions);
226
227 if (candidate != null &&
228 (mainQueue.isEmpty ||
229 mainQueue.firstPriority < candidate.firstPriority)) {
230 var value = candidate.removeFirst();
231 if (candidate.isEmpty) restrictedQueues.remove(candidate);
232 return value;
233 }
234 while (!mainQueue.isEmpty) {
235 var currentPriority = mainQueue.firstPriority;
236 var current = mainQueue.removeFirst();
237 if (!restrictions.any((e) => current.typeEquals(e))) {
238 return current;
239 } else {
240 var restrictedQueue = restrictedQueues
241 .firstWhere((e) => current.typeEquals(e.first.type),
242 orElse: () => null);
243 if (restrictedQueue == null) {
244 restrictedQueue = new PriorityQueue<N, P>();
245 restrictedQueues.add(restrictedQueue);
246 }
247 restrictedQueue.add(current, currentPriority);
248 }
249 }
250 }
251
252 String toString() {
253 if (isEmpty) return "Empty queue";
254 var buffer = new StringBuffer();
255 if (!restrictedQueues.isEmpty) {
256 buffer.writeln("Restricted queues");
257 for (var queue in restrictedQueues) {
258 buffer.writeln("$queue");
259 }
260 }
261 buffer.writeln("Main queue:");
262 buffer.writeln("$mainQueue");
263 return buffer.toString();
264 }
265 }
266
267 /// TEMPORARY TESTING AND PERFORMANCE
268 void main([args]) {
269 stress(new RestrictViewPriorityQueue<StringTypedElement, IntPriority>());
270 }
271
272 void stress(queue) {
273 final int SIZE = 50000;
274 Random random = new Random(29);
275
276 var priorities = [1, 2, 3, 16, 32, 42, 56, 57, 59, 90];
277 var values = [new StringTypedElement('safari', 'foo'),
278 new StringTypedElement('ie', 'bar'),
279 new StringTypedElement('ff', 'foobar'),
280 new StringTypedElement('dartium', 'barfoo'),
281 new StringTypedElement('chrome', 'hest'),
282 new StringTypedElement('drt', 'fisk')];
283
284 var restricted = ['safari', 'chrome'];
285
286
287 void addRandom() {
288 queue.add(values[random.nextInt(values.length)],
289 new IntPriority(priorities[random.nextInt(priorities.length)]));
290 }
291
292 var stopwatch = new Stopwatch()..start();
293 while(queue.length < SIZE) {
294 addRandom();
295 }
296
297 stopwatch.stop();
298 print("Adding took: ${stopwatch.elapsedMilliseconds}");
299 print("Queue length: ${queue.length}");
300
301 stopwatch = new Stopwatch()..start();
302 while(queue.length > 0) {
303 queue.removeFirst();
304 }
305 stopwatch.stop();
306 print("Remowing took: ${stopwatch.elapsedMilliseconds}");
307 print("Queue length: ${queue.length}");
308
309
310 print("Restricted add/remove");
311 while(queue.length < SIZE) {
312 addRandom();
313 }
314
315 for (int i = 0; i < SIZE; i++) {
316 if (random.nextDouble() < 0.5) {
317 queue.removeFirst(restrictions: restricted);
318 } else {
319 queue.removeFirst();
320 }
321 addRandom();
322 }
323 }
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_type_propagator.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698