OLD | NEW |
| (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 // This code was auto-generated, is not intended to be edited, and is subject to | |
6 // significant change. Please see the README file for more information. | |
7 | |
8 library engine.utilities.collection; | |
9 | |
10 import "dart:math" as math; | |
11 import 'dart:collection'; | |
12 | |
13 import 'java_core.dart'; | |
14 import 'scanner.dart' show Token; | |
15 | |
16 /** | |
17 * The class `BooleanArray` defines methods for operating on integers as if they
were arrays | |
18 * of booleans. These arrays can be indexed by either integers or by enumeration
constants. | |
19 */ | |
20 class BooleanArray { | |
21 /** | |
22 * Return the value of the element at the given index. | |
23 * | |
24 * @param array the array being accessed | |
25 * @param index the index of the element being accessed | |
26 * @return the value of the element at the given index | |
27 * @throws IndexOutOfBoundsException if the index is not between zero (0) and
31, inclusive | |
28 */ | |
29 static bool get(int array, int index) { | |
30 _checkIndex(index); | |
31 return (array & (1 << index)) > 0; | |
32 } | |
33 | |
34 /** | |
35 * Return the value of the element at the given index. | |
36 * | |
37 * @param array the array being accessed | |
38 * @param index the index of the element being accessed | |
39 * @return the value of the element at the given index | |
40 * @throws IndexOutOfBoundsException if the index is not between zero (0) and
31, inclusive | |
41 */ | |
42 static bool getEnum(int array, Enum index) => get(array, index.ordinal); | |
43 | |
44 /** | |
45 * Set the value of the element at the given index to the given value. | |
46 * | |
47 * @param array the array being modified | |
48 * @param index the index of the element being set | |
49 * @param value the value to be assigned to the element | |
50 * @return the updated value of the array | |
51 * @throws IndexOutOfBoundsException if the index is not between zero (0) and
31, inclusive | |
52 */ | |
53 static int set(int array, int index, bool value) { | |
54 _checkIndex(index); | |
55 if (value) { | |
56 return array | (1 << index); | |
57 } else { | |
58 return array & ~(1 << index); | |
59 } | |
60 } | |
61 | |
62 /** | |
63 * Set the value of the element at the given index to the given value. | |
64 * | |
65 * @param array the array being modified | |
66 * @param index the index of the element being set | |
67 * @param value the value to be assigned to the element | |
68 * @return the updated value of the array | |
69 * @throws IndexOutOfBoundsException if the index is not between zero (0) and
31, inclusive | |
70 */ | |
71 static int setEnum(int array, Enum index, bool value) => | |
72 set(array, index.ordinal, value); | |
73 | |
74 /** | |
75 * Throw an exception if the index is not within the bounds allowed for an int
eger-encoded array | |
76 * of boolean values. | |
77 * | |
78 * @throws IndexOutOfBoundsException if the index is not between zero (0) and
31, inclusive | |
79 */ | |
80 static void _checkIndex(int index) { | |
81 if (index < 0 || index > 30) { | |
82 throw new RangeError("Index not between 0 and 30: $index"); | |
83 } | |
84 } | |
85 } | |
86 | |
87 /** | |
88 * Instances of the class `DirectedGraph` implement a directed graph in which th
e nodes are | |
89 * arbitrary (client provided) objects and edges are represented implicitly. The
graph will allow an | |
90 * edge from any node to any other node, including itself, but will not represen
t multiple edges | |
91 * between the same pair of nodes. | |
92 * | |
93 * @param N the type of the nodes in the graph | |
94 */ | |
95 class DirectedGraph<N> { | |
96 /** | |
97 * The table encoding the edges in the graph. An edge is represented by an ent
ry mapping the head | |
98 * to a set of tails. Nodes that are not the head of any edge are represented
by an entry mapping | |
99 * the node to an empty set of tails. | |
100 */ | |
101 HashMap<N, HashSet<N>> _edges = new HashMap<N, HashSet<N>>(); | |
102 | |
103 /** | |
104 * Return `true` if this graph is empty. | |
105 * | |
106 * @return `true` if this graph is empty | |
107 */ | |
108 bool get isEmpty => _edges.isEmpty; | |
109 | |
110 /** | |
111 * Return the number of nodes in this graph. | |
112 * | |
113 * @return the number of nodes in this graph | |
114 */ | |
115 int get nodeCount => _edges.length; | |
116 | |
117 /** | |
118 * Return a set of all nodes in the graph. | |
119 */ | |
120 Set<N> get nodes => _edges.keys.toSet(); | |
121 | |
122 /** | |
123 * Add an edge from the given head node to the given tail node. Both nodes wil
l be a part of the | |
124 * graph after this method is invoked, whether or not they were before. | |
125 * | |
126 * @param head the node at the head of the edge | |
127 * @param tail the node at the tail of the edge | |
128 */ | |
129 void addEdge(N head, N tail) { | |
130 // | |
131 // First, ensure that the tail is a node known to the graph. | |
132 // | |
133 if (_edges[tail] == null) { | |
134 _edges[tail] = new HashSet<N>(); | |
135 } | |
136 // | |
137 // Then create the edge. | |
138 // | |
139 HashSet<N> tails = _edges[head]; | |
140 if (tails == null) { | |
141 tails = new HashSet<N>(); | |
142 _edges[head] = tails; | |
143 } | |
144 tails.add(tail); | |
145 } | |
146 | |
147 /** | |
148 * Add the given node to the set of nodes in the graph. | |
149 * | |
150 * @param node the node to be added | |
151 */ | |
152 void addNode(N node) { | |
153 HashSet<N> tails = _edges[node]; | |
154 if (tails == null) { | |
155 _edges[node] = new HashSet<N>(); | |
156 } | |
157 } | |
158 | |
159 /** | |
160 * Run a topological sort of the graph. Since the graph may contain cycles, th
is results in a list | |
161 * of strongly connected components rather than a list of nodes. The nodes in
each strongly | |
162 * connected components only have edges that point to nodes in the same compon
ent or earlier | |
163 * components. | |
164 */ | |
165 List<List<N>> computeTopologicalSort() { | |
166 DirectedGraph_SccFinder<N> finder = new DirectedGraph_SccFinder<N>(this); | |
167 return finder.computeTopologicalSort(); | |
168 } | |
169 | |
170 /** | |
171 * Return true if the graph contains at least one path from `source` to `desti
nation`. | |
172 */ | |
173 bool containsPath(N source, N destination) { | |
174 HashSet<N> nodesVisited = new HashSet<N>(); | |
175 return _containsPathInternal(source, destination, nodesVisited); | |
176 } | |
177 | |
178 /** | |
179 * Return a list of nodes that form a cycle containing the given node. If the
node is not part of | |
180 * this graph, then a list containing only the node itself will be returned. | |
181 * | |
182 * @return a list of nodes that form a cycle containing the given node | |
183 */ | |
184 List<N> findCycleContaining(N node) { | |
185 if (node == null) { | |
186 throw new IllegalArgumentException(); | |
187 } | |
188 DirectedGraph_SccFinder<N> finder = new DirectedGraph_SccFinder<N>(this); | |
189 return finder.componentContaining(node); | |
190 } | |
191 | |
192 /** | |
193 * Return a set containing the tails of edges that have the given node as thei
r head. The set will | |
194 * be empty if there are no such edges or if the node is not part of the graph
. Clients must not | |
195 * modify the returned set. | |
196 * | |
197 * @param head the node at the head of all of the edges whose tails are to be
returned | |
198 * @return a set containing the tails of edges that have the given node as the
ir head | |
199 */ | |
200 Set<N> getTails(N head) { | |
201 HashSet<N> tails = _edges[head]; | |
202 if (tails == null) { | |
203 return new HashSet<N>(); | |
204 } | |
205 return tails; | |
206 } | |
207 | |
208 /** | |
209 * Remove all of the given nodes from this graph. As a consequence, any edges
for which those | |
210 * nodes were either a head or a tail will also be removed. | |
211 * | |
212 * @param nodes the nodes to be removed | |
213 */ | |
214 void removeAllNodes(List<N> nodes) { | |
215 for (N node in nodes) { | |
216 removeNode(node); | |
217 } | |
218 } | |
219 | |
220 /** | |
221 * Remove the edge from the given head node to the given tail node. If there w
as no such edge then | |
222 * the graph will be unmodified: the number of edges will be the same and the
set of nodes will be | |
223 * the same (neither node will either be added or removed). | |
224 * | |
225 * @param head the node at the head of the edge | |
226 * @param tail the node at the tail of the edge | |
227 * @return `true` if the graph was modified as a result of this operation | |
228 */ | |
229 void removeEdge(N head, N tail) { | |
230 HashSet<N> tails = _edges[head]; | |
231 if (tails != null) { | |
232 tails.remove(tail); | |
233 } | |
234 } | |
235 | |
236 /** | |
237 * Remove the given node from this graph. As a consequence, any edges for whic
h that node was | |
238 * either a head or a tail will also be removed. | |
239 * | |
240 * @param node the node to be removed | |
241 */ | |
242 void removeNode(N node) { | |
243 _edges.remove(node); | |
244 for (HashSet<N> tails in _edges.values) { | |
245 tails.remove(node); | |
246 } | |
247 } | |
248 | |
249 /** | |
250 * Find one node (referred to as a sink node) that has no outgoing edges (that
is, for which there | |
251 * are no edges that have that node as the head of the edge) and remove it fro
m this graph. Return | |
252 * the node that was removed, or `null` if there are no such nodes either beca
use the graph | |
253 * is empty or because every node in the graph has at least one outgoing edge.
As a consequence of | |
254 * removing the node from the graph any edges for which that node was a tail w
ill also be removed. | |
255 * | |
256 * @return the sink node that was removed | |
257 */ | |
258 N removeSink() { | |
259 N sink = _findSink(); | |
260 if (sink == null) { | |
261 return null; | |
262 } | |
263 removeNode(sink); | |
264 return sink; | |
265 } | |
266 | |
267 bool _containsPathInternal(N source, N destination, HashSet<N> nodesVisited) { | |
268 if (identical(source, destination)) { | |
269 return true; | |
270 } | |
271 HashSet<N> tails = _edges[source]; | |
272 if (tails != null) { | |
273 nodesVisited.add(source); | |
274 for (N tail in tails) { | |
275 if (!nodesVisited.contains(tail)) { | |
276 if (_containsPathInternal(tail, destination, nodesVisited)) { | |
277 return true; | |
278 } | |
279 } | |
280 } | |
281 } | |
282 return false; | |
283 } | |
284 | |
285 /** | |
286 * Return one node that has no outgoing edges (that is, for which there are no
edges that have | |
287 * that node as the head of the edge), or `null` if there are no such nodes. | |
288 * | |
289 * @return a sink node | |
290 */ | |
291 N _findSink() { | |
292 for (N key in _edges.keys) { | |
293 if (_edges[key].isEmpty) return key; | |
294 } | |
295 return null; | |
296 } | |
297 } | |
298 | |
299 /** | |
300 * Instances of the class `NodeInfo` are used by the [SccFinder] to maintain | |
301 * information about the nodes that have been examined. | |
302 * | |
303 * @param N the type of the nodes corresponding to the entries | |
304 */ | |
305 class DirectedGraph_NodeInfo<N> { | |
306 /** | |
307 * The depth of this node. | |
308 */ | |
309 int index = 0; | |
310 | |
311 /** | |
312 * The depth of the first node in a cycle. | |
313 */ | |
314 int lowlink = 0; | |
315 | |
316 /** | |
317 * A flag indicating whether the corresponding node is on the stack. Used to r
emove the need for | |
318 * searching a collection for the node each time the question needs to be aske
d. | |
319 */ | |
320 bool onStack = false; | |
321 | |
322 /** | |
323 * The component that contains the corresponding node. | |
324 */ | |
325 List<N> component; | |
326 | |
327 /** | |
328 * Initialize a newly created information holder to represent a node at the gi
ven depth. | |
329 * | |
330 * @param depth the depth of the node being represented | |
331 */ | |
332 DirectedGraph_NodeInfo(int depth) { | |
333 index = depth; | |
334 lowlink = depth; | |
335 onStack = false; | |
336 } | |
337 } | |
338 | |
339 /** | |
340 * Instances of the class `SccFinder` implement Tarjan's Algorithm for finding t
he strongly | |
341 * connected components in a graph. | |
342 */ | |
343 class DirectedGraph_SccFinder<N> { | |
344 /** | |
345 * The graph to work with. | |
346 */ | |
347 final DirectedGraph<N> _graph; | |
348 | |
349 /** | |
350 * The index used to uniquely identify the depth of nodes. | |
351 */ | |
352 int _index = 0; | |
353 | |
354 /** | |
355 * The stack of nodes that are being visited in order to identify components. | |
356 */ | |
357 List<N> _stack = new List<N>(); | |
358 | |
359 /** | |
360 * A table mapping nodes to information about the nodes that is used by this a
lgorithm. | |
361 */ | |
362 HashMap<N, DirectedGraph_NodeInfo<N>> _nodeMap = | |
363 new HashMap<N, DirectedGraph_NodeInfo<N>>(); | |
364 | |
365 /** | |
366 * A list of all strongly connected components found, in topological sort orde
r (each node in a | |
367 * strongly connected component only has edges that point to nodes in the same
component or | |
368 * earlier components). | |
369 */ | |
370 List<List<N>> _allComponents = new List<List<N>>(); | |
371 | |
372 /** | |
373 * Initialize a newly created finder. | |
374 */ | |
375 DirectedGraph_SccFinder(this._graph) : super(); | |
376 | |
377 /** | |
378 * Return a list containing the nodes that are part of the strongly connected
component that | |
379 * contains the given node. | |
380 * | |
381 * @param node the node used to identify the strongly connected component to b
e returned | |
382 * @return the nodes that are part of the strongly connected component that co
ntains the given | |
383 * node | |
384 */ | |
385 List<N> componentContaining(N node) => _strongConnect(node).component; | |
386 | |
387 /** | |
388 * Run Tarjan's algorithm and return the resulting list of strongly connected
components. The | |
389 * list is in topological sort order (each node in a strongly connected compon
ent only has edges | |
390 * that point to nodes in the same component or earlier components). | |
391 */ | |
392 List<List<N>> computeTopologicalSort() { | |
393 for (N node in _graph._edges.keys.toSet()) { | |
394 DirectedGraph_NodeInfo<N> nodeInfo = _nodeMap[node]; | |
395 if (nodeInfo == null) { | |
396 _strongConnect(node); | |
397 } | |
398 } | |
399 return _allComponents; | |
400 } | |
401 | |
402 /** | |
403 * Remove and return the top-most element from the stack. | |
404 * | |
405 * @return the element that was removed | |
406 */ | |
407 N _pop() { | |
408 N node = _stack.removeAt(_stack.length - 1); | |
409 _nodeMap[node].onStack = false; | |
410 return node; | |
411 } | |
412 | |
413 /** | |
414 * Add the given node to the stack. | |
415 * | |
416 * @param node the node to be added to the stack | |
417 */ | |
418 void _push(N node) { | |
419 _nodeMap[node].onStack = true; | |
420 _stack.add(node); | |
421 } | |
422 | |
423 /** | |
424 * Compute the strongly connected component that contains the given node as we
ll as any | |
425 * components containing nodes that are reachable from the given component. | |
426 * | |
427 * @param v the node from which the search will begin | |
428 * @return the information about the given node | |
429 */ | |
430 DirectedGraph_NodeInfo<N> _strongConnect(N v) { | |
431 // | |
432 // Set the depth index for v to the smallest unused index | |
433 // | |
434 DirectedGraph_NodeInfo<N> vInfo = new DirectedGraph_NodeInfo<N>(_index++); | |
435 _nodeMap[v] = vInfo; | |
436 _push(v); | |
437 // | |
438 // Consider successors of v | |
439 // | |
440 HashSet<N> tails = _graph._edges[v]; | |
441 if (tails != null) { | |
442 for (N w in tails) { | |
443 DirectedGraph_NodeInfo<N> wInfo = _nodeMap[w]; | |
444 if (wInfo == null) { | |
445 // Successor w has not yet been visited; recurse on it | |
446 wInfo = _strongConnect(w); | |
447 vInfo.lowlink = math.min(vInfo.lowlink, wInfo.lowlink); | |
448 } else if (wInfo.onStack) { | |
449 // Successor w is in stack S and hence in the current SCC | |
450 vInfo.lowlink = math.min(vInfo.lowlink, wInfo.index); | |
451 } | |
452 } | |
453 } | |
454 // | |
455 // If v is a root node, pop the stack and generate an SCC | |
456 // | |
457 if (vInfo.lowlink == vInfo.index) { | |
458 List<N> component = new List<N>(); | |
459 N w; | |
460 do { | |
461 w = _pop(); | |
462 component.add(w); | |
463 _nodeMap[w].component = component; | |
464 } while (!identical(w, v)); | |
465 _allComponents.add(component); | |
466 } | |
467 return vInfo; | |
468 } | |
469 } | |
470 | |
471 /** | |
472 * The class `ListUtilities` defines utility methods useful for working with [Li
st | |
473 ]. | |
474 */ | |
475 class ListUtilities { | |
476 /** | |
477 * Add all of the elements in the given array to the given list. | |
478 * | |
479 * @param list the list to which the elements are to be added | |
480 * @param elements the elements to be added to the list | |
481 */ | |
482 static void addAll(List list, List<Object> elements) { | |
483 int count = elements.length; | |
484 for (int i = 0; i < count; i++) { | |
485 list.add(elements[i]); | |
486 } | |
487 } | |
488 } | |
489 | |
490 /** | |
491 * The interface `MapIterator` defines the behavior of objects that iterate over
the entries | |
492 * in a map. | |
493 * | |
494 * This interface defines the concept of a current entry and provides methods to
access the key and | |
495 * value in the current entry. When an iterator is first created it will be posi
tioned before the | |
496 * first entry and there is no current entry until [moveNext] is invoked. When a
ll of the | |
497 * entries have been accessed there will also be no current entry. | |
498 * | |
499 * There is no guarantee made about the order in which the entries are accessibl
e. | |
500 */ | |
501 abstract class MapIterator<K, V> { | |
502 /** | |
503 * Return the key associated with the current element. | |
504 * | |
505 * @return the key associated with the current element | |
506 * @throws NoSuchElementException if there is no current element | |
507 */ | |
508 K get key; | |
509 | |
510 /** | |
511 * Return the value associated with the current element. | |
512 * | |
513 * @return the value associated with the current element | |
514 * @throws NoSuchElementException if there is no current element | |
515 */ | |
516 V get value; | |
517 | |
518 /** | |
519 * Set the value associated with the current element to the given value. | |
520 * | |
521 * @param newValue the new value to be associated with the current element | |
522 * @throws NoSuchElementException if there is no current element | |
523 */ | |
524 void set value(V newValue); | |
525 | |
526 /** | |
527 * Advance to the next entry in the map. Return `true` if there is a current e
lement that | |
528 * can be accessed after this method returns. It is safe to invoke this method
even if the | |
529 * previous invocation returned `false`. | |
530 * | |
531 * @return `true` if there is a current element that can be accessed | |
532 */ | |
533 bool moveNext(); | |
534 } | |
535 | |
536 /** | |
537 * Instances of the class `MultipleMapIterator` implement an iterator that can b
e used to | |
538 * sequentially access the entries in multiple maps. | |
539 */ | |
540 class MultipleMapIterator<K, V> implements MapIterator<K, V> { | |
541 /** | |
542 * The iterators used to access the entries. | |
543 */ | |
544 List<MapIterator<K, V>> _iterators; | |
545 | |
546 /** | |
547 * The index of the iterator currently being used to access the entries. | |
548 */ | |
549 int _iteratorIndex = -1; | |
550 | |
551 /** | |
552 * The current iterator, or `null` if there is no current iterator. | |
553 */ | |
554 MapIterator<K, V> _currentIterator; | |
555 | |
556 /** | |
557 * Initialize a newly created iterator to return the entries from the given ma
ps. | |
558 * | |
559 * @param maps the maps containing the entries to be iterated | |
560 */ | |
561 MultipleMapIterator(List<Map<K, V>> maps) { | |
562 int count = maps.length; | |
563 _iterators = new List<MapIterator<K, V>>(count); | |
564 for (int i = 0; i < count; i++) { | |
565 _iterators[i] = new SingleMapIterator<K, V>(maps[i]); | |
566 } | |
567 } | |
568 | |
569 @override | |
570 K get key { | |
571 if (_currentIterator == null) { | |
572 throw new NoSuchElementException(); | |
573 } | |
574 return _currentIterator.key; | |
575 } | |
576 | |
577 @override | |
578 V get value { | |
579 if (_currentIterator == null) { | |
580 throw new NoSuchElementException(); | |
581 } | |
582 return _currentIterator.value; | |
583 } | |
584 | |
585 @override | |
586 void set value(V newValue) { | |
587 if (_currentIterator == null) { | |
588 throw new NoSuchElementException(); | |
589 } | |
590 _currentIterator.value = newValue; | |
591 } | |
592 | |
593 @override | |
594 bool moveNext() { | |
595 if (_iteratorIndex < 0) { | |
596 if (_iterators.length == 0) { | |
597 _currentIterator = null; | |
598 return false; | |
599 } | |
600 if (_advanceToNextIterator()) { | |
601 return true; | |
602 } else { | |
603 _currentIterator = null; | |
604 return false; | |
605 } | |
606 } | |
607 if (_currentIterator.moveNext()) { | |
608 return true; | |
609 } else if (_advanceToNextIterator()) { | |
610 return true; | |
611 } else { | |
612 _currentIterator = null; | |
613 return false; | |
614 } | |
615 } | |
616 | |
617 /** | |
618 * Under the assumption that there are no more entries that can be returned us
ing the current | |
619 * iterator, advance to the next iterator that has entries. | |
620 * | |
621 * @return `true` if there is a current iterator that has entries | |
622 */ | |
623 bool _advanceToNextIterator() { | |
624 _iteratorIndex++; | |
625 while (_iteratorIndex < _iterators.length) { | |
626 MapIterator<K, V> iterator = _iterators[_iteratorIndex]; | |
627 if (iterator.moveNext()) { | |
628 _currentIterator = iterator; | |
629 return true; | |
630 } | |
631 _iteratorIndex++; | |
632 } | |
633 return false; | |
634 } | |
635 } | |
636 | |
637 /** | |
638 * Instances of the class `SingleMapIterator` implement an iterator that can be
used to access | |
639 * the entries in a single map. | |
640 */ | |
641 class SingleMapIterator<K, V> implements MapIterator<K, V> { | |
642 /** | |
643 * The [Map] containing the entries to be iterated over. | |
644 */ | |
645 final Map<K, V> _map; | |
646 | |
647 /** | |
648 * The iterator used to access the entries. | |
649 */ | |
650 Iterator<K> _keyIterator; | |
651 | |
652 /** | |
653 * The current key, or `null` if there is no current key. | |
654 */ | |
655 K _currentKey; | |
656 | |
657 /** | |
658 * The current value. | |
659 */ | |
660 V _currentValue; | |
661 | |
662 /** | |
663 * Initialize a newly created iterator to return the entries from the given ma
p. | |
664 * | |
665 * @param map the map containing the entries to be iterated over | |
666 */ | |
667 SingleMapIterator(this._map) { | |
668 this._keyIterator = _map.keys.iterator; | |
669 } | |
670 | |
671 @override | |
672 K get key { | |
673 if (_currentKey == null) { | |
674 throw new NoSuchElementException(); | |
675 } | |
676 return _currentKey; | |
677 } | |
678 | |
679 @override | |
680 V get value { | |
681 if (_currentKey == null) { | |
682 throw new NoSuchElementException(); | |
683 } | |
684 if (_currentValue == null) { | |
685 _currentValue = _map[_currentKey]; | |
686 } | |
687 return _currentValue; | |
688 } | |
689 | |
690 @override | |
691 void set value(V newValue) { | |
692 if (_currentKey == null) { | |
693 throw new NoSuchElementException(); | |
694 } | |
695 _currentValue = newValue; | |
696 _map[_currentKey] = newValue; | |
697 } | |
698 | |
699 @override | |
700 bool moveNext() { | |
701 if (_keyIterator.moveNext()) { | |
702 _currentKey = _keyIterator.current; | |
703 _currentValue = null; | |
704 return true; | |
705 } else { | |
706 _currentKey = null; | |
707 return false; | |
708 } | |
709 } | |
710 | |
711 /** | |
712 * Returns a new [SingleMapIterator] instance for the given [Map]. | |
713 */ | |
714 static SingleMapIterator forMap(Map map) => new SingleMapIterator(map); | |
715 } | |
716 | |
717 /** | |
718 * Instances of the class `TokenMap` map one set of tokens to another set of tok
ens. | |
719 */ | |
720 class TokenMap { | |
721 /** | |
722 * A table mapping tokens to tokens. This should be replaced by a more perform
ant implementation. | |
723 * One possibility is a pair of parallel arrays, with keys being sorted by the
ir offset and a | |
724 * cursor indicating where to start searching. | |
725 */ | |
726 HashMap<Token, Token> _map = new HashMap<Token, Token>(); | |
727 | |
728 /** | |
729 * Return the token that is mapped to the given token, or `null` if there is n
o token | |
730 * corresponding to the given token. | |
731 * | |
732 * @param key the token being mapped to another token | |
733 * @return the token that is mapped to the given token | |
734 */ | |
735 Token get(Token key) => _map[key]; | |
736 | |
737 /** | |
738 * Map the key to the value. | |
739 * | |
740 * @param key the token being mapped to the value | |
741 * @param value the token to which the key will be mapped | |
742 */ | |
743 void put(Token key, Token value) { | |
744 _map[key] = value; | |
745 } | |
746 } | |
OLD | NEW |