Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013, 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 part of dart.convert; | |
| 6 | |
| 7 /** | |
| 8 * This class represents the [ByteConversionSink] interface. It is | |
| 9 * accessed through [ByteConversionSink.INTERFACE] or as instance field | |
| 10 * `interface` from [ByteConversionSink]s. | |
| 11 */ | |
| 12 class _ByteInterface extends ChunkedConversionInterface { | |
| 13 const _ByteInterface(); | |
| 14 | |
| 15 ByteConversionSink adapt(ChunkedConversionSink sink) { | |
| 16 if (sink.interface == _ByteInterface) return sink; | |
|
Søren Gjesse
2013/07/24 09:26:41
_ByteInterface => ByteConvertionSink.INTERFACE
floitsch
2013/07/24 18:31:15
Done.
| |
| 17 // Common denominator is ChunkedConversionSink. | |
| 18 return new _ByteAdapterSink(sink); | |
| 19 } | |
| 20 } | |
| 21 | |
| 22 /** | |
| 23 * The [ByteConversionSink] provides an interface for converters to | |
| 24 * efficiently transmit byte data. | |
| 25 * | |
| 26 * Instead of limiting the interface to one non-chunked list of bytes it | |
| 27 * accepts its input in chunks (themselves being lists of bytes). | |
| 28 */ | |
| 29 abstract class ByteConversionSink | |
| 30 extends ChunkedConversionSink<List<int>, List<int>> { | |
| 31 | |
| 32 /** The Interface that represents the [ByteConversionSink]. */ | |
| 33 static const ChunkedConversionInterface INTERFACE = const _ByteInterface(); | |
| 34 | |
| 35 ByteConversionSink(); | |
| 36 /** | |
| 37 * Creates a [ByteConversionSink] with a callback. | |
| 38 * | |
| 39 * The [callback] is invoked with the accumulated data when the sink is | |
| 40 * closed (which automatically happens when it receives data through | |
| 41 * [addNonChunked]). | |
| 42 */ | |
| 43 factory ByteConversionSink.withCallback(void callback(List<int> list)) = | |
| 44 _ByteConversionCallbackSink; | |
|
Søren Gjesse
2013/07/24 09:26:41
How about also having a ByteConvertionSink.withFu
floitsch
2013/07/24 18:31:15
Removed that constructor during removal of addNonC
| |
| 45 | |
| 46 /** | |
| 47 * Adds the next [chunk] to `this`. | |
| 48 * | |
| 49 * Adds the substring defined by [start] and [end]-exclusive to `this`. | |
| 50 * | |
| 51 * If [isLast] is `true` closes `this`. | |
| 52 * | |
| 53 * The given [chunk] is not hold onto. Once the method returns, it is safe to | |
| 54 * overwrite the data in it. | |
| 55 */ | |
| 56 void addSlice(List<int> chunk, int start, int end, bool isLast); | |
| 57 | |
| 58 // TODO(floitsch): add more methods: | |
| 59 // - iterateBytes. | |
| 60 | |
| 61 ChunkedConversionInterface get interface => INTERFACE; | |
| 62 } | |
| 63 | |
| 64 /** | |
| 65 * The [StringConversionSinkBase] provides a base-class for converters that | |
| 66 * need to accept byte inputs. | |
| 67 */ | |
| 68 abstract class ByteConversionSinkBase extends ByteConversionSink { | |
| 69 | |
| 70 void add(List<int> chunk); | |
| 71 void close(); | |
| 72 | |
| 73 void addNonChunked(List<int> list) { | |
| 74 add(list); | |
| 75 close(); | |
| 76 } | |
| 77 | |
| 78 void addSlice(List<int> chunk, int start, int end, bool isLast) { | |
| 79 if (start != 0 || end != chunk.length) { | |
| 80 add(chunk.sublist(start, end)); | |
| 81 } else { | |
| 82 add(chunk); | |
| 83 } | |
| 84 if (isLast) close(); | |
| 85 } | |
| 86 | |
| 87 ChunkedConversionInterface get interface => ByteConversionSink.INTERFACE; | |
| 88 } | |
| 89 | |
| 90 /** | |
| 91 * A [ByteConversionSink] accumulates all chunks and gives it to | |
| 92 * the wrapped sink in one go (using `addNonChunked`). | |
| 93 * | |
| 94 * This class can be used to terminate a chunked conversion. | |
| 95 */ | |
| 96 class _ByteAdapterSink extends ByteConversionSinkBase { | |
| 97 static const _INITIAL_BUFFER_SIZE = 1024; | |
| 98 final ChunkedConversionSink _otherSink; | |
| 99 // TODO(11971, floitsch): use Uint8List instead of normal lists. | |
| 100 final List<int> _buffer = new List<int>(_INITIAL_BUFFER_SIZE); | |
| 101 int _bufferIndex = 0; | |
| 102 | |
| 103 _ByteAdapterSink(this._otherSink); | |
| 104 | |
| 105 void add(Iterable<int> chunk) { | |
| 106 int freeCount = _buffer.length - _bufferIndex; | |
| 107 if (chunk.length > freeCount) { | |
| 108 // Grow the buffer. | |
| 109 int oldLength = _buffer.length; | |
| 110 int newLength = _roundToPowerOf2(chunk.length + oldLength) * 2; | |
| 111 // TODO(11971, floitsch): use Uint8List instead of normal lists. | |
| 112 List<int> grown = new List<int>(newLength); | |
| 113 grown.setRange(0, _buffer.length, _buffer); | |
| 114 } | |
| 115 _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk); | |
| 116 _bufferIndex += chunk.length; | |
| 117 } | |
| 118 | |
| 119 static int _roundToPowerOf2(int v) { | |
|
Søren Gjesse
2013/07/24 09:26:41
This is not the first time I have seen this code.
floitsch
2013/07/24 18:31:15
Filed http://dartbug.com/12008.
| |
| 120 assert(v > 0); | |
| 121 v--; | |
| 122 v |= v >> 1; | |
| 123 v |= v >> 2; | |
| 124 v |= v >> 4; | |
| 125 v |= v >> 8; | |
| 126 v |= v >> 16; | |
| 127 v++; | |
| 128 return v; | |
| 129 } | |
| 130 | |
| 131 void close() { | |
| 132 _otherSink.addNonChunked(_buffer.sublist(0, _bufferIndex)); | |
| 133 } | |
| 134 | |
| 135 void addNonChunked(List<int> list) => _otherSink.addNonChunked(list); | |
| 136 } | |
| 137 | |
| 138 /** | |
| 139 * A [ByteConversionSink] accumulating all chunks and invoking a | |
| 140 * callback when the sink is closed. | |
| 141 */ | |
| 142 class _ByteConversionCallbackSink extends ByteConversionSinkBase { | |
| 143 final _ChunkedConversionCallback<List<int>> _callback; | |
| 144 // TODO(floitsch): use typed lists. | |
| 145 final List<int> _accumulated = <int>[]; | |
| 146 | |
| 147 _ByteConversionCallbackSink(this._callback); | |
| 148 | |
| 149 void add(Iterable<int> chunk) { _accumulated.addAll(chunk); } | |
| 150 void close() { _callback(_accumulated); } | |
| 151 | |
| 152 void addNonChunked(List<int> list) => _callback(list); | |
| 153 } | |
| OLD | NEW |