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 |