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

Side by Side Diff: lib/src/file.dart

Issue 1319303004: Optimize successive calls SourceFile.getLine(). (Closed) Base URL: https://github.com/dart-lang/source_span.git@master
Patch Set: Created 5 years, 3 months 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
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/utils.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698