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 == ByteConversionSink.INTERFACE) return sink; | |
| 17 return new _ByteAdapterSink(sink); | |
| 18 } | |
| 19 | |
| 20 /** | |
| 21 * Creates a [ByteConversionSink] with a callback. | |
| 22 * | |
| 23 * The [callback] is invoked with the accumulated data when the sink is | |
| 24 * closed. | |
| 25 */ | |
| 26 ByteConversionSink createSink(void callback(List<int> accumulated)) { | |
| 27 return new _ByteCallbackSink(callback); | |
| 28 } | |
| 29 } | |
| 30 | |
| 31 /** | |
| 32 * The [ByteConversionSink] provides an interface for converters to | |
| 33 * efficiently transmit byte data. | |
| 34 * | |
| 35 * Instead of limiting the interface to one non-chunked list of bytes it | |
| 36 * accepts its input in chunks (themselves being lists of bytes). | |
| 37 */ | |
| 38 abstract class ByteConversionSink extends ChunkedConversionSink<List<int>> { | |
| 39 | |
| 40 /** The Interface that represents the [ByteConversionSink]. */ | |
| 41 static const ChunkedConversionInterface INTERFACE = const _ByteInterface(); | |
| 42 | |
| 43 ByteConversionSink(); | |
| 44 | |
| 45 /** | |
| 46 * Adds the next [chunk] to `this`. | |
| 47 * | |
| 48 * 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.
| |
| 49 * | |
| 50 * If [isLast] is `true` closes `this`. | |
| 51 * | |
| 52 * 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.
| |
| 53 * overwrite the data in it. | |
| 54 */ | |
| 55 void addSlice(List<int> chunk, int start, int end, bool isLast); | |
| 56 | |
| 57 // TODO(floitsch): add more methods: | |
| 58 // - iterateBytes. | |
| 59 | |
| 60 ChunkedConversionInterface get interface => INTERFACE; | |
| 61 } | |
| 62 | |
| 63 /** | |
| 64 * The [StringConversionSinkBase] provides a base-class for converters that | |
| 65 * need to accept byte inputs. | |
| 66 */ | |
| 67 abstract class ByteConversionSinkBase extends ByteConversionSink { | |
| 68 | |
| 69 void add(List<int> chunk); | |
| 70 void close(); | |
| 71 | |
| 72 void addSlice(List<int> chunk, int start, int end, bool isLast) { | |
| 73 if (start != 0 || end != chunk.length) { | |
| 74 add(chunk.sublist(start, end)); | |
| 75 } else { | |
| 76 add(chunk); | |
| 77 } | |
| 78 if (isLast) close(); | |
| 79 } | |
| 80 | |
| 81 ChunkedConversionInterface get interface => ByteConversionSink.INTERFACE; | |
| 82 } | |
| 83 | |
| 84 /** | |
| 85 * This class adapts a simple [ChunkedConversionSink] to a [ByteConversionSink]. | |
| 86 * | |
| 87 * All additional methods of the [ByteConversionSink] (compared to the | |
| 88 * ChunkedConversionSink) are redirected to the `add` method. | |
| 89 */ | |
| 90 class _ByteAdapterSink extends ByteConversionSinkBase { | |
| 91 final ChunkedConversionSink<List<int>> _sink; | |
| 92 | |
| 93 _ByteAdapterSink(this._sink); | |
| 94 | |
| 95 void add(List<int> chunk) => _sink.add(chunk); | |
| 96 void close() => _sink.close(); | |
| 97 } | |
| 98 | |
| 99 /** | |
| 100 * This class accumulates all chunks into one list of bytes | |
| 101 * and invokes a callback when the sink is closed. | |
| 102 * | |
| 103 * This class can be used to terminate a chunked conversion. | |
| 104 */ | |
| 105 class _ByteCallbackSink extends ByteConversionSinkBase { | |
| 106 static const _INITIAL_BUFFER_SIZE = 1024; | |
| 107 | |
| 108 final _ChunkedConversionCallback<List<int>> _callback; | |
| 109 // TODO(11971, floitsch): use Uint8List instead of normal lists. | |
| 110 List<int> _buffer = new List<int>(_INITIAL_BUFFER_SIZE); | |
| 111 int _bufferIndex = 0; | |
| 112 | |
| 113 _ByteCallbackSink(void callback(List<int> accumulated)) | |
| 114 : this._callback = callback; | |
| 115 | |
| 116 void add(Iterable<int> chunk) { | |
| 117 int freeCount = _buffer.length - _bufferIndex; | |
| 118 if (chunk.length > freeCount) { | |
| 119 // Grow the buffer. | |
| 120 int oldLength = _buffer.length; | |
| 121 int newLength = _roundToPowerOf2(chunk.length + oldLength) * 2; | |
| 122 // 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
| |
| 123 List<int> grown = new List<int>(newLength); | |
| 124 grown.setRange(0, _buffer.length, _buffer); | |
| 125 _buffer = grown; | |
| 126 } | |
| 127 _buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk); | |
| 128 _bufferIndex += chunk.length; | |
| 129 } | |
| 130 | |
| 131 static int _roundToPowerOf2(int v) { | |
| 132 assert(v > 0); | |
| 133 v--; | |
| 134 v |= v >> 1; | |
| 135 v |= v >> 2; | |
| 136 v |= v >> 4; | |
| 137 v |= v >> 8; | |
| 138 v |= v >> 16; | |
| 139 v++; | |
| 140 return v; | |
| 141 } | |
| 142 | |
| 143 void close() { | |
| 144 _callback(_buffer.sublist(0, _bufferIndex)); | |
| 145 } | |
| 146 } | |
| OLD | NEW |