Chromium Code Reviews| 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); |
| +} |