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

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: Add boundary case checking back in and remove tests for old binary search. 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/location.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';
11 import 'span.dart'; 11 import 'span.dart';
12 import 'span_mixin.dart'; 12 import 'span_mixin.dart';
13 import 'span_with_context.dart'; 13 import 'span_with_context.dart';
14 import 'utils.dart';
15 14
16 // Constants to determine end-of-lines. 15 // Constants to determine end-of-lines.
17 const int _LF = 10; 16 const int _LF = 10;
18 const int _CR = 13; 17 const int _CR = 13;
19 18
20 /// A class representing a source file. 19 /// A class representing a source file.
21 /// 20 ///
22 /// This doesn't necessarily have to correspond to a file on disk, just a chunk 21 /// This doesn't necessarily have to correspond to a file on disk, just a chunk
23 /// of text usually with a URL associated with it. 22 /// of text usually with a URL associated with it.
24 class SourceFile { 23 class SourceFile {
(...skipping 11 matching lines...) Expand all
36 35
37 /// The code points of the characters in the file. 36 /// The code points of the characters in the file.
38 final Uint32List _decodedChars; 37 final Uint32List _decodedChars;
39 38
40 /// The length of the file in characters. 39 /// The length of the file in characters.
41 int get length => _decodedChars.length; 40 int get length => _decodedChars.length;
42 41
43 /// The number of lines in the file. 42 /// The number of lines in the file.
44 int get lines => _lineStarts.length; 43 int get lines => _lineStarts.length;
45 44
45 /// The line that the offset fell on the last time [getLine] was called.
46 ///
47 /// In many cases, sequential calls to getLine() are for nearby, usually
48 /// increasing offsets. In that case, we can find the line for an offset
49 /// quickly by first checking to see if the offset is on the same line as the
50 /// previous result.
51 int _cachedLine;
52
46 /// Creates a new source file from [text]. 53 /// Creates a new source file from [text].
47 /// 54 ///
48 /// [url] may be either a [String], a [Uri], or `null`. 55 /// [url] may be either a [String], a [Uri], or `null`.
49 SourceFile(String text, {url}) 56 SourceFile(String text, {url})
50 : this.decoded(text.runes, url: url); 57 : this.decoded(text.runes, url: url);
51 58
52 /// Creates a new source file from a list of decoded characters. 59 /// Creates a new source file from a list of decoded characters.
53 /// 60 ///
54 /// [url] may be either a [String], a [Uri], or `null`. 61 /// [url] may be either a [String], a [Uri], or `null`.
55 SourceFile.decoded(Iterable<int> decodedChars, {url}) 62 SourceFile.decoded(Iterable<int> decodedChars, {url})
(...skipping 22 matching lines...) Expand all
78 FileLocation location(int offset) => new FileLocation._(this, offset); 85 FileLocation location(int offset) => new FileLocation._(this, offset);
79 86
80 /// Gets the 0-based line corresponding to [offset]. 87 /// Gets the 0-based line corresponding to [offset].
81 int getLine(int offset) { 88 int getLine(int offset) {
82 if (offset < 0) { 89 if (offset < 0) {
83 throw new RangeError("Offset may not be negative, was $offset."); 90 throw new RangeError("Offset may not be negative, was $offset.");
84 } else if (offset > length) { 91 } else if (offset > length) {
85 throw new RangeError("Offset $offset must not be greater than the number " 92 throw new RangeError("Offset $offset must not be greater than the number "
86 "of characters in the file, $length."); 93 "of characters in the file, $length.");
87 } 94 }
88 return binarySearch(_lineStarts, (o) => o > offset) - 1; 95
96 if (offset < _lineStarts.first) return -1;
97 if (offset >= _lineStarts.last) return _lineStarts.length - 1;
98
99 if (_isNearCachedLine(offset)) return _cachedLine;
100
101 _cachedLine = _binarySearch(offset) - 1;
102 return _cachedLine;
103 }
104
105 /// Returns `true` if [offset] is near [_cachedLine].
106 ///
107 /// Checks on [_cachedLine] and the next line. If it's on the next line, it
108 /// updates [_cachedLine] to point to that.
109 bool _isNearCachedLine(int offset) {
110 if (_cachedLine == null) return false;
111
112 // See if it's before the cached line.
113 if (offset < _lineStarts[_cachedLine]) return false;
114
115 // See if it's on the cached line.
116 if (_cachedLine >= _lineStarts.length - 1 ||
117 offset < _lineStarts[_cachedLine + 1]) {
118 return true;
119 }
120
121 // See if it's on the next line.
122 if (_cachedLine >= _lineStarts.length - 2 ||
123 offset < _lineStarts[_cachedLine + 2]) {
124 _cachedLine++;
125 return true;
126 }
127
128 return false;
129 }
130
131 /// Binary search through [_lineStarts] to find the line containing [offset].
132 ///
133 /// Returns the index of the line in [_lineStarts].
134 int _binarySearch(int offset) {
135 int min = 0;
136 int max = _lineStarts.length - 1;
137 while (min < max) {
138 var half = min + ((max - min) ~/ 2);
139 if (_lineStarts[half] > offset) {
140 max = half;
141 } else {
142 min = half + 1;
143 }
144 }
145
146 return max;
89 } 147 }
90 148
91 /// Gets the 0-based column corresponding to [offset]. 149 /// Gets the 0-based column corresponding to [offset].
92 /// 150 ///
93 /// If [line] is passed, it's assumed to be the line containing [offset] and 151 /// If [line] is passed, it's assumed to be the line containing [offset] and
94 /// is used to more efficiently compute the column. 152 /// is used to more efficiently compute the column.
95 int getColumn(int offset, {int line}) { 153 int getColumn(int offset, {int line}) {
96 if (offset < 0) { 154 if (offset < 0) {
97 throw new RangeError("Offset may not be negative, was $offset."); 155 throw new RangeError("Offset may not be negative, was $offset.");
98 } else if (offset > length) { 156 } 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); 338 var start = math.min(this._start, other._start);
281 var end = math.max(this._end, other._end); 339 var end = math.max(this._end, other._end);
282 return new _FileSpan(file, start, end); 340 return new _FileSpan(file, start, end);
283 } else { 341 } else {
284 var start = math.min(this._start, other.start.offset); 342 var start = math.min(this._start, other.start.offset);
285 var end = math.max(this._end, other.end.offset); 343 var end = math.max(this._end, other.end.offset);
286 return new _FileSpan(file, start, end); 344 return new _FileSpan(file, start, end);
287 } 345 }
288 } 346 }
289 } 347 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/location.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698