Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library source_span.file; | 5 library source_span.file; |
| 6 | 6 |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 import 'dart:typed_data'; | 8 import 'dart:typed_data'; |
| 9 | 9 |
| 10 import 'location.dart'; | 10 import 'location.dart'; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 36 | 36 |
| 37 /// The code points of the characters in the file. | 37 /// The code points of the characters in the file. |
| 38 final Uint32List _decodedChars; | 38 final Uint32List _decodedChars; |
| 39 | 39 |
| 40 /// The length of the file in characters. | 40 /// The length of the file in characters. |
| 41 int get length => _decodedChars.length; | 41 int get length => _decodedChars.length; |
| 42 | 42 |
| 43 /// The number of lines in the file. | 43 /// The number of lines in the file. |
| 44 int get lines => _lineStarts.length; | 44 int get lines => _lineStarts.length; |
| 45 | 45 |
| 46 /// The line that the offset fell on the last time [getLine] was called. | |
| 47 /// | |
| 48 /// In many cases, sequential calls to getLine() are for nearby, usually | |
| 49 /// increasing offsets. In that case, we can find the line for an offset | |
| 50 /// quickly by first checking to see if the offset is on the same line as the | |
| 51 /// previous result. | |
| 52 int _cachedLine; | |
| 53 | |
| 46 /// Creates a new source file from [text]. | 54 /// Creates a new source file from [text]. |
| 47 /// | 55 /// |
| 48 /// [url] may be either a [String], a [Uri], or `null`. | 56 /// [url] may be either a [String], a [Uri], or `null`. |
| 49 SourceFile(String text, {url}) | 57 SourceFile(String text, {url}) |
| 50 : this.decoded(text.runes, url: url); | 58 : this.decoded(text.runes, url: url); |
| 51 | 59 |
| 52 /// Creates a new source file from a list of decoded characters. | 60 /// Creates a new source file from a list of decoded characters. |
| 53 /// | 61 /// |
| 54 /// [url] may be either a [String], a [Uri], or `null`. | 62 /// [url] may be either a [String], a [Uri], or `null`. |
| 55 SourceFile.decoded(Iterable<int> decodedChars, {url}) | 63 SourceFile.decoded(Iterable<int> decodedChars, {url}) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 78 FileLocation location(int offset) => new FileLocation._(this, offset); | 86 FileLocation location(int offset) => new FileLocation._(this, offset); |
| 79 | 87 |
| 80 /// Gets the 0-based line corresponding to [offset]. | 88 /// Gets the 0-based line corresponding to [offset]. |
| 81 int getLine(int offset) { | 89 int getLine(int offset) { |
| 82 if (offset < 0) { | 90 if (offset < 0) { |
| 83 throw new RangeError("Offset may not be negative, was $offset."); | 91 throw new RangeError("Offset may not be negative, was $offset."); |
| 84 } else if (offset > length) { | 92 } else if (offset > length) { |
| 85 throw new RangeError("Offset $offset must not be greater than the number " | 93 throw new RangeError("Offset $offset must not be greater than the number " |
| 86 "of characters in the file, $length."); | 94 "of characters in the file, $length."); |
| 87 } | 95 } |
| 88 return binarySearch(_lineStarts, (o) => o > offset) - 1; | 96 |
| 97 if (_isNearCachedLine(offset)) return _cachedLine; | |
| 98 | |
| 99 return _cachedLine = _binarySearch(offset) - 1; | |
|
nweiz
2015/09/02 00:06:30
This is cute, but I think it's clearer to assign s
| |
| 100 } | |
| 101 | |
| 102 /// Returns `true` if [offset] is within [_cachedLine]. | |
|
nweiz
2015/09/02 00:06:30
"within" -> "near"
| |
| 103 /// | |
| 104 /// This actually checks on [_cachedLine] and the next line. If it's on the | |
| 105 /// next line, it updates [_cachedLine] to point to that. | |
| 106 bool _isNearCachedLine(int offset) { | |
| 107 if (_cachedLine == null) return false; | |
| 108 | |
| 109 // See if it's before the cached line. | |
| 110 if (offset < _lineStarts[_cachedLine]) return false; | |
| 111 | |
| 112 // See if it's on the cached line. | |
| 113 if (_cachedLine >= _lineStarts.length - 1 || | |
| 114 offset < _lineStarts[_cachedLine + 1]) { | |
| 115 return true; | |
| 116 } | |
| 117 | |
| 118 // See if it's on the next line. | |
| 119 if (_cachedLine >= _lineStarts.length - 2 || | |
| 120 offset < _lineStarts[_cachedLine + 2]) { | |
| 121 _cachedLine++; | |
| 122 return true; | |
| 123 } | |
| 124 | |
| 125 return false; | |
| 126 } | |
| 127 | |
| 128 /// Binary search through [_lineStarts] to find the line containing [offset]. | |
| 129 /// | |
| 130 /// Given a result `n`, that all items before `n` will not match, `n` matches, | |
| 131 /// and all items after `n` match too. The result is -1 when there are no | |
| 132 /// items, 0 when all items match, and list.length when none does. | |
|
nweiz
2015/09/02 00:06:30
Since we can guarantee there will be at least one
| |
| 133 int _binarySearch(int offset) { | |
| 134 int min = 0; | |
| 135 int max = _lineStarts.length - 1; | |
| 136 while (min < max) { | |
| 137 var half = min + ((max - min) ~/ 2); | |
| 138 if (_lineStarts[half] > offset) { | |
| 139 max = half; | |
| 140 } else { | |
| 141 min = half + 1; | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 return max; | |
| 89 } | 146 } |
| 90 | 147 |
| 91 /// Gets the 0-based column corresponding to [offset]. | 148 /// Gets the 0-based column corresponding to [offset]. |
| 92 /// | 149 /// |
| 93 /// If [line] is passed, it's assumed to be the line containing [offset] and | 150 /// If [line] is passed, it's assumed to be the line containing [offset] and |
| 94 /// is used to more efficiently compute the column. | 151 /// is used to more efficiently compute the column. |
| 95 int getColumn(int offset, {int line}) { | 152 int getColumn(int offset, {int line}) { |
| 96 if (offset < 0) { | 153 if (offset < 0) { |
| 97 throw new RangeError("Offset may not be negative, was $offset."); | 154 throw new RangeError("Offset may not be negative, was $offset."); |
| 98 } else if (offset > length) { | 155 } else if (offset > length) { |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 var start = math.min(this._start, other._start); | 337 var start = math.min(this._start, other._start); |
| 281 var end = math.max(this._end, other._end); | 338 var end = math.max(this._end, other._end); |
| 282 return new _FileSpan(file, start, end); | 339 return new _FileSpan(file, start, end); |
| 283 } else { | 340 } else { |
| 284 var start = math.min(this._start, other.start.offset); | 341 var start = math.min(this._start, other.start.offset); |
| 285 var end = math.max(this._end, other.end.offset); | 342 var end = math.max(this._end, other.end.offset); |
| 286 return new _FileSpan(file, start, end); | 343 return new _FileSpan(file, start, end); |
| 287 } | 344 } |
| 288 } | 345 } |
| 289 } | 346 } |
| OLD | NEW |