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..7044837e57f1c59deff91133f9a1ef7c15ae16e7 |
--- /dev/null |
+++ b/sdk/lib/convert/byte_conversion.dart |
@@ -0,0 +1,146 @@ |
+// 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 == ByteConversionSink.INTERFACE) return sink; |
+ return new _ByteAdapterSink(sink); |
+ } |
+ |
+ /** |
+ * Creates a [ByteConversionSink] with a callback. |
+ * |
+ * The [callback] is invoked with the accumulated data when the sink is |
+ * closed. |
+ */ |
+ ByteConversionSink createSink(void callback(List<int> accumulated)) { |
+ return new _ByteCallbackSink(callback); |
+ } |
+} |
+ |
+/** |
+ * 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>> { |
+ |
+ /** The Interface that represents the [ByteConversionSink]. */ |
+ static const ChunkedConversionInterface INTERFACE = const _ByteInterface(); |
+ |
+ ByteConversionSink(); |
+ |
+ /** |
+ * Adds the next [chunk] to `this`. |
+ * |
+ * Adds the substring defined by [start] and [end]-exclusive to `this`. |
Søren Gjesse
2013/07/25 08:07:00
substring -> bytes
floitsch
2013/07/25 12:57:24
Done.
|
+ * |
+ * If [isLast] is `true` closes `this`. |
+ * |
+ * The given [chunk] is not hold onto. Once the method returns, it is safe to |
Søren Gjesse
2013/07/25 08:07:00
hold -> held (I think).
floitsch
2013/07/25 12:57:24
Done.
|
+ * 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 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; |
+} |
+ |
+/** |
+ * This class adapts a simple [ChunkedConversionSink] to a [ByteConversionSink]. |
+ * |
+ * All additional methods of the [ByteConversionSink] (compared to the |
+ * ChunkedConversionSink) are redirected to the `add` method. |
+ */ |
+class _ByteAdapterSink extends ByteConversionSinkBase { |
+ final ChunkedConversionSink<List<int>> _sink; |
+ |
+ _ByteAdapterSink(this._sink); |
+ |
+ void add(List<int> chunk) => _sink.add(chunk); |
+ void close() => _sink.close(); |
+} |
+ |
+/** |
+ * This class accumulates all chunks into one list of bytes |
+ * and invokes a callback when the sink is closed. |
+ * |
+ * This class can be used to terminate a chunked conversion. |
+ */ |
+class _ByteCallbackSink extends ByteConversionSinkBase { |
+ static const _INITIAL_BUFFER_SIZE = 1024; |
+ |
+ final _ChunkedConversionCallback<List<int>> _callback; |
+ // TODO(11971, floitsch): use Uint8List instead of normal lists. |
+ List<int> _buffer = new List<int>(_INITIAL_BUFFER_SIZE); |
+ int _bufferIndex = 0; |
+ |
+ _ByteCallbackSink(void callback(List<int> accumulated)) |
+ : this._callback = callback; |
+ |
+ 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. |
Søren Gjesse
2013/07/25 08:07:00
We have the class BytesBuilder in dart:io which do
floitsch
2013/07/25 12:57:24
I think we want to add growable typed lists to typ
|
+ List<int> grown = new List<int>(newLength); |
+ grown.setRange(0, _buffer.length, _buffer); |
+ _buffer = grown; |
+ } |
+ _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk); |
+ _bufferIndex += chunk.length; |
+ } |
+ |
+ static int _roundToPowerOf2(int v) { |
+ assert(v > 0); |
+ v--; |
+ v |= v >> 1; |
+ v |= v >> 2; |
+ v |= v >> 4; |
+ v |= v >> 8; |
+ v |= v >> 16; |
+ v++; |
+ return v; |
+ } |
+ |
+ void close() { |
+ _callback(_buffer.sublist(0, _bufferIndex)); |
+ } |
+} |