comparison lphobos/std/outbuffer.d @ 473:373489eeaf90

Applied downs' lphobos update
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Mon, 04 Aug 2008 19:28:49 +0200
parents
children 88e23f8c2354
comparison
equal deleted inserted replaced
472:15c804b6ce77 473:373489eeaf90
1 // outbuffer.d
2
3 /**
4 * Boilerplate:
5 * $(std_boilerplate.html)
6 * Macros:
7 * WIKI = Phobos/StdOutbuffer
8 * Copyright:
9 * Copyright (c) 2001-2005 by Digital Mars
10 * All Rights Reserved
11 * www.digitalmars.com
12 */
13
14
15 // Written by Walter Bright
16
17 /* NOTE: This file has been patched from the original DMD distribution to
18 work with the GDC compiler.
19
20 Modified by David Friedman, September 2004
21 */
22
23 module std.outbuffer;
24
25 private
26 {
27 import std.string;
28 import std.gc;
29 import std.c.stdio;
30 import std.c.stdlib;
31 import std.c.stdarg;
32 }
33
34 /*********************************************
35 * OutBuffer provides a way to build up an array of bytes out
36 * of raw data. It is useful for things like preparing an
37 * array of bytes to write out to a file.
38 * OutBuffer's byte order is the format native to the computer.
39 * To control the byte order (endianness), use a class derived
40 * from OutBuffer.
41 */
42
43 class OutBuffer
44 {
45 ubyte data[];
46 size_t offset;
47
48 invariant
49 {
50 //printf("this = %p, offset = %x, data.length = %u\n", this, offset, data.length);
51 assert(offset <= data.length);
52 assert(data.length <= std.gc.capacity(data.ptr));
53 }
54
55 this()
56 {
57 //printf("in OutBuffer constructor\n");
58 }
59
60 /*********************************
61 * Convert to array of bytes.
62 */
63
64 ubyte[] toBytes() { return data[0 .. offset]; }
65
66 /***********************************
67 * Preallocate nbytes more to the size of the internal buffer.
68 *
69 * This is a
70 * speed optimization, a good guess at the maximum size of the resulting
71 * buffer will improve performance by eliminating reallocations and copying.
72 */
73
74
75 void reserve(size_t nbytes)
76 in
77 {
78 assert(offset + nbytes >= offset);
79 }
80 out
81 {
82 assert(offset + nbytes <= data.length);
83 assert(data.length <= std.gc.capacity(data.ptr));
84 }
85 body
86 {
87 if (data.length < offset + nbytes)
88 {
89 //std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, offset = %d, nbytes = %d, capacity = %d\n", data.ptr, data.length, offset, nbytes, std.gc.capacity(data.ptr));
90 data.length = (offset + nbytes) * 2;
91 //std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, capacity = %d\n", data.ptr, data.length, std.gc.capacity(data.ptr));
92 std.gc.hasPointers(data.ptr);
93 }
94 }
95
96 /*************************************
97 * Append data to the internal buffer.
98 */
99
100 void write(ubyte[] bytes)
101 {
102 reserve(bytes.length);
103 data[offset .. offset + bytes.length] = bytes;
104 offset += bytes.length;
105 }
106
107 void write(ubyte b) /// ditto
108 {
109 reserve(ubyte.sizeof);
110 this.data[offset] = b;
111 offset += ubyte.sizeof;
112 }
113
114 void write(byte b) { write(cast(ubyte)b); } /// ditto
115 void write(char c) { write(cast(ubyte)c); } /// ditto
116
117 void write(ushort w) /// ditto
118 {
119 reserve(ushort.sizeof);
120 *cast(ushort *)&data[offset] = w;
121 offset += ushort.sizeof;
122 }
123
124 void write(short s) { write(cast(ushort)s); } /// ditto
125
126 void write(wchar c) /// ditto
127 {
128 reserve(wchar.sizeof);
129 *cast(wchar *)&data[offset] = c;
130 offset += wchar.sizeof;
131 }
132
133 void write(uint w) /// ditto
134 {
135 reserve(uint.sizeof);
136 *cast(uint *)&data[offset] = w;
137 offset += uint.sizeof;
138 }
139
140 void write(int i) { write(cast(uint)i); } /// ditto
141
142 void write(ulong l) /// ditto
143 {
144 reserve(ulong.sizeof);
145 *cast(ulong *)&data[offset] = l;
146 offset += ulong.sizeof;
147 }
148
149 void write(long l) { write(cast(ulong)l); } /// ditto
150
151 void write(float f) /// ditto
152 {
153 reserve(float.sizeof);
154 *cast(float *)&data[offset] = f;
155 offset += float.sizeof;
156 }
157
158 void write(double f) /// ditto
159 {
160 reserve(double.sizeof);
161 *cast(double *)&data[offset] = f;
162 offset += double.sizeof;
163 }
164
165 void write(real f) /// ditto
166 {
167 reserve(real.sizeof);
168 *cast(real *)&data[offset] = f;
169 offset += real.sizeof;
170 }
171
172 void write(char[] s) /// ditto
173 {
174 write(cast(ubyte[])s);
175 }
176
177 void write(OutBuffer buf) /// ditto
178 {
179 write(buf.toBytes());
180 }
181
182 /****************************************
183 * Append nbytes of 0 to the internal buffer.
184 */
185
186 void fill0(uint nbytes)
187 {
188 reserve(nbytes);
189 data[offset .. offset + nbytes] = 0;
190 offset += nbytes;
191 }
192
193 /**********************************
194 * 0-fill to align on power of 2 boundary.
195 */
196
197 void alignSize(size_t alignsize)
198 in
199 {
200 assert(alignsize && (alignsize & (alignsize - 1)) == 0);
201 }
202 out
203 {
204 assert((offset & (alignsize - 1)) == 0);
205 }
206 body
207 { size_t nbytes;
208
209 nbytes = offset & (alignsize - 1);
210 if (nbytes)
211 fill0(alignsize - nbytes);
212 }
213
214 /****************************************
215 * Optimize common special case alignSize(2)
216 */
217
218 void align2()
219 {
220 if (offset & 1)
221 write(cast(byte)0);
222 }
223
224 /****************************************
225 * Optimize common special case alignSize(4)
226 */
227
228 void align4()
229 {
230 if (offset & 3)
231 { size_t nbytes = (4 - offset) & 3;
232 fill0(nbytes);
233 }
234 }
235
236 /**************************************
237 * Convert internal buffer to array of chars.
238 */
239
240 char[] toString()
241 {
242 //printf("OutBuffer.toString()\n");
243 return cast(char[])data[0 .. offset];
244 }
245
246 /*****************************************
247 * Append output of C's vprintf() to internal buffer.
248 */
249
250 void vprintf(char[] format, va_list args)
251 {
252 char[128] buffer;
253 char* p;
254 char* f;
255 uint psize;
256 int count;
257 va_list args_copy;
258
259 f = toStringz(format);
260 p = buffer.ptr;
261 psize = buffer.length;
262 for (;;)
263 {
264 va_copy(args_copy, args);
265 version(Win32)
266 {
267 count = _vsnprintf(p,psize,f,args_copy);
268 if (count != -1)
269 break;
270 psize *= 2;
271 p = cast(char *) alloca(psize); // buffer too small, try again with larger size
272 }
273 else version(GNU) {
274 count = vsnprintf(p,psize,f,args_copy);
275 if (count == -1)
276 psize *= 2;
277 else if (count >= psize)
278 psize = count + 1;
279 else
280 break;
281 p = cast(char *) alloca(psize); // buffer too small, try again with larger size
282 }
283 else version(linux)
284 {
285 count = vsnprintf(p,psize,f,args_copy);
286 if (count == -1)
287 psize *= 2;
288 else if (count >= psize)
289 psize = count + 1;
290 else
291 break;
292 /+
293 if (p != buffer)
294 c.stdlib.free(p);
295 p = (char *) c.stdlib.malloc(psize); // buffer too small, try again with larger size
296 +/
297 p = cast(char *) alloca(psize); // buffer too small, try again with larger size
298 }
299 }
300 write(p[0 .. count]);
301 /+
302 version (linux)
303 {
304 if (p != buffer)
305 c.stdlib.free(p);
306 }
307 +/
308 }
309
310 /*****************************************
311 * Append output of C's printf() to internal buffer.
312 */
313
314 void printf(char[] format, ...)
315 {
316 version (GNU)
317 {
318 vprintf(format, _argptr);
319 }
320 else
321 {
322 va_list ap;
323 ap = cast(va_list)&format;
324 ap += format.sizeof;
325 vprintf(format, ap);
326 }
327 }
328
329 /*****************************************
330 * At offset index into buffer, create nbytes of space by shifting upwards
331 * all data past index.
332 */
333
334 void spread(size_t index, size_t nbytes)
335 in
336 {
337 assert(index <= offset);
338 }
339 body
340 {
341 reserve(nbytes);
342
343 // This is an overlapping copy - should use memmove()
344 for (size_t i = offset; i > index; )
345 {
346 --i;
347 data[i + nbytes] = data[i];
348 }
349 offset += nbytes;
350 }
351 }
352
353 unittest
354 {
355 //printf("Starting OutBuffer test\n");
356
357 OutBuffer buf = new OutBuffer();
358
359 //printf("buf = %p\n", buf);
360 //printf("buf.offset = %x\n", buf.offset);
361 assert(buf.offset == 0);
362 buf.write("hello");
363 buf.write(cast(byte)0x20);
364 buf.write("world");
365 buf.printf(" %d", 6);
366 //printf("buf = '%.*s'\n", buf.toString());
367 assert(cmp(buf.toString(), "hello world 6") == 0);
368 }