| Index: tool/input_sdk/lib/convert/line_splitter.dart
|
| diff --git a/tool/input_sdk/lib/convert/line_splitter.dart b/tool/input_sdk/lib/convert/line_splitter.dart
|
| index 53337f00fffc0bf049c08659a3978df5e1e82773..a9c94488a6c366e35d8650785403ef71338aac88 100644
|
| --- a/tool/input_sdk/lib/convert/line_splitter.dart
|
| +++ b/tool/input_sdk/lib/convert/line_splitter.dart
|
| @@ -4,22 +4,77 @@
|
|
|
| part of dart.convert;
|
|
|
| +// Character constants.
|
| +const int _LF = 10;
|
| +const int _CR = 13;
|
| +
|
| /**
|
| - * This class splits [String] values into individual lines.
|
| + * A [Converter] that splits a [String] into individual lines.
|
| + *
|
| + * A line is terminated by either a CR (U+000D), a LF (U+000A), a
|
| + * CR+LF sequence (DOS line ending),
|
| + * and a final non-empty line can be ended by the end of the string.
|
| + *
|
| + * The returned lines do not contain the line terminators.
|
| */
|
| -class LineSplitter extends Converter<String, List<String>> {
|
| +class LineSplitter extends
|
| + ChunkedConverter<String, List<String>, String, String> {
|
|
|
| const LineSplitter();
|
|
|
| - List<String> convert(String data) {
|
| - var lines = new List<String>();
|
| -
|
| - _LineSplitterSink._addSlice(data, 0, data.length, true, lines.add);
|
| + /// Split [lines] into individual lines.
|
| + ///
|
| + /// If [start] and [end] are provided, only split the contents of
|
| + /// `lines.substring(start, end)`. The [start] and [end] values must
|
| + /// specify a valid sub-range of [lines]
|
| + /// (`0 <= start <= end <= lines.length`).
|
| + static Iterable<String> split(String lines, [int start = 0, int end]) sync* {
|
| + end = RangeError.checkValidRange(start, end, lines.length);
|
| + int sliceStart = start;
|
| + int char = 0;
|
| + for (int i = start; i < end; i++) {
|
| + int previousChar = char;
|
| + char = lines.codeUnitAt(i);
|
| + if (char != _CR) {
|
| + if (char != _LF) continue;
|
| + if (previousChar == _CR) {
|
| + sliceStart = i + 1;
|
| + continue;
|
| + }
|
| + }
|
| + yield lines.substring(sliceStart, i);
|
| + sliceStart = i + 1;
|
| + }
|
| + if (sliceStart < end) {
|
| + yield lines.substring(sliceStart, end);
|
| + }
|
| + }
|
|
|
| + List<String> convert(String data) {
|
| + List<String> lines = <String>[];
|
| + int end = data.length;
|
| + int sliceStart = 0;
|
| + int char = 0;
|
| + for (int i = 0; i < end; i++) {
|
| + int previousChar = char;
|
| + char = data.codeUnitAt(i);
|
| + if (char != _CR) {
|
| + if (char != _LF) continue;
|
| + if (previousChar == _CR) {
|
| + sliceStart = i + 1;
|
| + continue;
|
| + }
|
| + }
|
| + lines.add(data.substring(sliceStart, i));
|
| + sliceStart = i + 1;
|
| + }
|
| + if (sliceStart < end) {
|
| + lines.add(data.substring(sliceStart, end));
|
| + }
|
| return lines;
|
| }
|
|
|
| - StringConversionSink startChunkedConversion(Sink<dynamic> sink) {
|
| + StringConversionSink startChunkedConversion(Sink<String> sink) {
|
| if (sink is! StringConversionSink) {
|
| sink = new StringConversionSink.from(sink);
|
| }
|
| @@ -29,65 +84,76 @@ class LineSplitter extends Converter<String, List<String>> {
|
|
|
| // TODO(floitsch): deal with utf8.
|
| class _LineSplitterSink extends StringConversionSinkBase {
|
| - static const int _LF = 10;
|
| - static const int _CR = 13;
|
| -
|
| final StringConversionSink _sink;
|
|
|
| + /// The carry-over from the previous chunk.
|
| + ///
|
| + /// If the previous slice ended in a line without a line terminator,
|
| + /// then the next slice may continue the line.
|
| String _carry;
|
|
|
| + /// Whether to skip a leading LF character from the next slice.
|
| + ///
|
| + /// If the previous slice ended on a CR character, a following LF
|
| + /// would be part of the same line termination, and should be ignored.
|
| + ///
|
| + /// Only `true` when [_carry] is `null`.
|
| + bool _skipLeadingLF = false;
|
| +
|
| _LineSplitterSink(this._sink);
|
|
|
| void addSlice(String chunk, int start, int end, bool isLast) {
|
| + end = RangeError.checkValidRange(start, end, chunk.length);
|
| + // If the chunk is empty, it's probably because it's the last one.
|
| + // Handle that here, so we know the range is non-empty below.
|
| + if (start >= end) {
|
| + if (isLast) close();
|
| + return;
|
| + }
|
| if (_carry != null) {
|
| + assert(!_skipLeadingLF);
|
| chunk = _carry + chunk.substring(start, end);
|
| start = 0;
|
| end = chunk.length;
|
| _carry = null;
|
| + } else if (_skipLeadingLF) {
|
| + if (chunk.codeUnitAt(start) == _LF) {
|
| + start += 1;
|
| + }
|
| + _skipLeadingLF = false;
|
| }
|
| - _carry = _addSlice(chunk, start, end, isLast, _sink.add);
|
| - if (isLast) _sink.close();
|
| + _addLines(chunk, start, end);
|
| + if (isLast) close();
|
| }
|
|
|
| void close() {
|
| - addSlice('', 0, 0, true);
|
| + if (_carry != null) {
|
| + _sink.add(_carry);
|
| + _carry = null;
|
| + }
|
| + _sink.close();
|
| }
|
|
|
| - static String _addSlice(String chunk, int start, int end, bool isLast,
|
| - void adder(String val)) {
|
| -
|
| - int pos = start;
|
| - while (pos < end) {
|
| - int skip = 0;
|
| - int char = chunk.codeUnitAt(pos);
|
| - if (char == _LF) {
|
| - skip = 1;
|
| - } else if (char == _CR) {
|
| - skip = 1;
|
| - if (pos + 1 < end) {
|
| - if (chunk.codeUnitAt(pos + 1) == _LF) {
|
| - skip = 2;
|
| - }
|
| - } else if (!isLast) {
|
| - return chunk.substring(start, end);
|
| + void _addLines(String lines, int start, int end) {
|
| + int sliceStart = start;
|
| + int char = 0;
|
| + for (int i = start; i < end; i++) {
|
| + int previousChar = char;
|
| + char = lines.codeUnitAt(i);
|
| + if (char != _CR) {
|
| + if (char != _LF) continue;
|
| + if (previousChar == _CR) {
|
| + sliceStart = i + 1;
|
| + continue;
|
| }
|
| }
|
| - if (skip > 0) {
|
| - adder(chunk.substring(start, pos));
|
| - start = pos = pos + skip;
|
| - } else {
|
| - pos++;
|
| - }
|
| + _sink.add(lines.substring(sliceStart, i));
|
| + sliceStart = i + 1;
|
| }
|
| - if (pos != start) {
|
| - var carry = chunk.substring(start, pos);
|
| - if (isLast) {
|
| - // Add remaining
|
| - adder(carry);
|
| - } else {
|
| - return carry;
|
| - }
|
| + if (sliceStart < end) {
|
| + _carry = lines.substring(sliceStart, end);
|
| + } else {
|
| + _skipLeadingLF = (char == _CR);
|
| }
|
| - return null;
|
| }
|
| }
|
|
|