| 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 |