Mercurial > projects > ldc
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 } |