Index: sdk/lib/convert/byte_conversion.dart |
diff --git a/sdk/lib/convert/byte_conversion.dart b/sdk/lib/convert/byte_conversion.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9eb834115b0cfcd3d1a2c9cccbbbc93e72982b44 |
--- /dev/null |
+++ b/sdk/lib/convert/byte_conversion.dart |
@@ -0,0 +1,153 @@ |
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of dart.convert; |
+ |
+/** |
+ * This class represents the [ByteConversionSink] interface. It is |
+ * accessed through [ByteConversionSink.INTERFACE] or as instance field |
+ * `interface` from [ByteConversionSink]s. |
+ */ |
+class _ByteInterface extends ChunkedConversionInterface { |
+ const _ByteInterface(); |
+ |
+ ByteConversionSink adapt(ChunkedConversionSink sink) { |
+ 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.
|
+ // Common denominator is ChunkedConversionSink. |
+ return new _ByteAdapterSink(sink); |
+ } |
+} |
+ |
+/** |
+ * The [ByteConversionSink] provides an interface for converters to |
+ * efficiently transmit byte data. |
+ * |
+ * Instead of limiting the interface to one non-chunked list of bytes it |
+ * accepts its input in chunks (themselves being lists of bytes). |
+ */ |
+abstract class ByteConversionSink |
+ extends ChunkedConversionSink<List<int>, List<int>> { |
+ |
+ /** The Interface that represents the [ByteConversionSink]. */ |
+ static const ChunkedConversionInterface INTERFACE = const _ByteInterface(); |
+ |
+ ByteConversionSink(); |
+ /** |
+ * Creates a [ByteConversionSink] with a callback. |
+ * |
+ * The [callback] is invoked with the accumulated data when the sink is |
+ * closed (which automatically happens when it receives data through |
+ * [addNonChunked]). |
+ */ |
+ factory ByteConversionSink.withCallback(void callback(List<int> list)) = |
+ _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
|
+ |
+ /** |
+ * Adds the next [chunk] to `this`. |
+ * |
+ * Adds the substring defined by [start] and [end]-exclusive to `this`. |
+ * |
+ * If [isLast] is `true` closes `this`. |
+ * |
+ * The given [chunk] is not hold onto. Once the method returns, it is safe to |
+ * overwrite the data in it. |
+ */ |
+ void addSlice(List<int> chunk, int start, int end, bool isLast); |
+ |
+ // TODO(floitsch): add more methods: |
+ // - iterateBytes. |
+ |
+ ChunkedConversionInterface get interface => INTERFACE; |
+} |
+ |
+/** |
+ * The [StringConversionSinkBase] provides a base-class for converters that |
+ * need to accept byte inputs. |
+ */ |
+abstract class ByteConversionSinkBase extends ByteConversionSink { |
+ |
+ void add(List<int> chunk); |
+ void close(); |
+ |
+ void addNonChunked(List<int> list) { |
+ add(list); |
+ close(); |
+ } |
+ |
+ void addSlice(List<int> chunk, int start, int end, bool isLast) { |
+ if (start != 0 || end != chunk.length) { |
+ add(chunk.sublist(start, end)); |
+ } else { |
+ add(chunk); |
+ } |
+ if (isLast) close(); |
+ } |
+ |
+ ChunkedConversionInterface get interface => ByteConversionSink.INTERFACE; |
+} |
+ |
+/** |
+ * A [ByteConversionSink] accumulates all chunks and gives it to |
+ * the wrapped sink in one go (using `addNonChunked`). |
+ * |
+ * This class can be used to terminate a chunked conversion. |
+ */ |
+class _ByteAdapterSink extends ByteConversionSinkBase { |
+ static const _INITIAL_BUFFER_SIZE = 1024; |
+ final ChunkedConversionSink _otherSink; |
+ // TODO(11971, floitsch): use Uint8List instead of normal lists. |
+ final List<int> _buffer = new List<int>(_INITIAL_BUFFER_SIZE); |
+ int _bufferIndex = 0; |
+ |
+ _ByteAdapterSink(this._otherSink); |
+ |
+ void add(Iterable<int> chunk) { |
+ int freeCount = _buffer.length - _bufferIndex; |
+ if (chunk.length > freeCount) { |
+ // Grow the buffer. |
+ int oldLength = _buffer.length; |
+ int newLength = _roundToPowerOf2(chunk.length + oldLength) * 2; |
+ // TODO(11971, floitsch): use Uint8List instead of normal lists. |
+ List<int> grown = new List<int>(newLength); |
+ grown.setRange(0, _buffer.length, _buffer); |
+ } |
+ _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk); |
+ _bufferIndex += chunk.length; |
+ } |
+ |
+ 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.
|
+ assert(v > 0); |
+ v--; |
+ v |= v >> 1; |
+ v |= v >> 2; |
+ v |= v >> 4; |
+ v |= v >> 8; |
+ v |= v >> 16; |
+ v++; |
+ return v; |
+ } |
+ |
+ void close() { |
+ _otherSink.addNonChunked(_buffer.sublist(0, _bufferIndex)); |
+ } |
+ |
+ void addNonChunked(List<int> list) => _otherSink.addNonChunked(list); |
+} |
+ |
+/** |
+ * A [ByteConversionSink] accumulating all chunks and invoking a |
+ * callback when the sink is closed. |
+ */ |
+class _ByteConversionCallbackSink extends ByteConversionSinkBase { |
+ final _ChunkedConversionCallback<List<int>> _callback; |
+ // TODO(floitsch): use typed lists. |
+ final List<int> _accumulated = <int>[]; |
+ |
+ _ByteConversionCallbackSink(this._callback); |
+ |
+ void add(Iterable<int> chunk) { _accumulated.addAll(chunk); } |
+ void close() { _callback(_accumulated); } |
+ |
+ void addNonChunked(List<int> list) => _callback(list); |
+} |