| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2017, 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 fasta.scanner.abstract_scanner; |
| 6 |
| 7 import 'dart:convert'; |
| 8 |
| 9 class Node { |
| 10 var /* String | List<int> */ data; |
| 11 int start; |
| 12 int end; |
| 13 String payload; |
| 14 Node next; |
| 15 Node(this.data, this.start, this.end, this.payload, this.next); |
| 16 } |
| 17 |
| 18 /** |
| 19 * A hash table for triples: |
| 20 * (list of bytes, start, end) --> canonicalized string |
| 21 * Using triples avoids allocating string slices before checking if they |
| 22 * are canonical. |
| 23 * |
| 24 * Gives about 3% speedup on dart2js. |
| 25 */ |
| 26 class StringCanonicalizer { |
| 27 /// Mask away top bits to keep hash calculation within 32-bit SMI range. |
| 28 static const int MASK = 16 * 1024 * 1024 - 1; |
| 29 |
| 30 static const int INITIAL_SIZE = 8 * 1024; |
| 31 |
| 32 /// Linear size of a hash table. |
| 33 int _size = INITIAL_SIZE; |
| 34 /// Items in a hash table. |
| 35 int _count = 0; |
| 36 /// The table itself. |
| 37 Node _nodes = new List<Node>(INITIAL_SIZE); |
| 38 |
| 39 static String decode(List<int> data, int start, int end, bool asciiOnly) { |
| 40 var s; |
| 41 if (asciiOnly) { |
| 42 s = new String.fromCharCodes(data, start, end); |
| 43 } else { |
| 44 s = new Utf8Decoder(allowMalformed: true).convert(data, start, end); |
| 45 } |
| 46 return s; |
| 47 } |
| 48 |
| 49 static int hashBytes(List<int> data, int start, int end) { |
| 50 int h = 5381; |
| 51 for (int i = start; i < end; i++) { |
| 52 h = ((h << 5) + h + data[i]) & MASK; |
| 53 } |
| 54 return h; |
| 55 } |
| 56 |
| 57 static int hashString(String data, int start, int end) { |
| 58 int h = 5381; |
| 59 for (int i = start; i < end; i++) { |
| 60 h = ((h << 5) + h + data.codeUnitAt(i)) & MASK; |
| 61 } |
| 62 return h; |
| 63 } |
| 64 |
| 65 rehash() { |
| 66 var newSize = _size * 2; |
| 67 var newNodes = new List<Node>(newSize); |
| 68 for (int i = 0; i < _size; i++) { |
| 69 Node t = _nodes[i]; |
| 70 while (t != null) { |
| 71 Node n = t.next; |
| 72 int newIndex = hashBytes(t.data, t.start, t.end) & (newSize - 1); |
| 73 Node s = newNodes[newIndex]; |
| 74 t.next = s; |
| 75 newNodes[newIndex] = t; |
| 76 t = n; |
| 77 } |
| 78 } |
| 79 _size = newSize; |
| 80 _nodes = newNodes; |
| 81 } |
| 82 |
| 83 String canonicalize(data, int start, int end, bool asciiOnly) { |
| 84 if (_count > _size) rehash(); |
| 85 int index = data is String |
| 86 ? hashString(data, start, end) |
| 87 : hashBytes(data, start, end); |
| 88 index = index & (_size - 1); |
| 89 Node s = _nodes[index]; |
| 90 Node t = s; |
| 91 int len = end - start; |
| 92 while (t != null) { |
| 93 if (t.end - t.start == len) { |
| 94 int i = start, j = t.start; |
| 95 while (i < end && data[i] == t.data[j]) { |
| 96 i++; |
| 97 j++; |
| 98 } |
| 99 if (i == end) { |
| 100 return t.payload; |
| 101 } |
| 102 } |
| 103 t = t.next; |
| 104 } |
| 105 String payload; |
| 106 if (data is String) |
| 107 payload = data.substring(start, end); |
| 108 else |
| 109 payload = decode(data, start, end, asciiOnly); |
| 110 _nodes[index] = new Node(data, start, end, payload, s); |
| 111 _count++; |
| 112 return payload; |
| 113 } |
| 114 |
| 115 clear() { |
| 116 _nodes = new List<Node>(size); |
| 117 } |
| 118 } |
| OLD | NEW |