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 |