libstdc++: Define __glibcxx_assert_fail for non-verbose build [PR115585]
[official-gcc.git] / libphobos / src / std / outbuffer.d
blob92af9a9a16a74865ecf45a91fe7a04568d4efe99
1 // Written in the D programming language.
3 /**
4 Serialize data to `ubyte` arrays.
6 * Copyright: Copyright The D Language Foundation 2000 - 2015.
7 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
8 * Authors: $(HTTP digitalmars.com, Walter Bright)
9 * Source: $(PHOBOSSRC std/outbuffer.d)
11 * $(SCRIPT inhibitQuickIndex = 1;)
13 module std.outbuffer;
15 import core.stdc.stdarg;
16 import std.traits : isSomeString;
18 /*********************************************
19 * OutBuffer provides a way to build up an array of bytes out
20 * of raw data. It is useful for things like preparing an
21 * array of bytes to write out to a file.
22 * OutBuffer's byte order is the format native to the computer.
23 * To control the byte order (endianness), use a class derived
24 * from OutBuffer.
25 * OutBuffer's internal buffer is allocated with the GC. Pointers
26 * stored into the buffer are scanned by the GC, but you have to
27 * ensure proper alignment, e.g. by using alignSize((void*).sizeof).
30 class OutBuffer
32 ubyte[] data;
33 size_t offset;
35 invariant()
37 assert(offset <= data.length);
40 pure nothrow @safe
42 /*********************************
43 * Convert to array of bytes.
45 inout(ubyte)[] toBytes() scope inout { return data[0 .. offset]; }
47 /***********************************
48 * Preallocate nbytes more to the size of the internal buffer.
50 * This is a
51 * speed optimization, a good guess at the maximum size of the resulting
52 * buffer will improve performance by eliminating reallocations and copying.
54 void reserve(size_t nbytes) @trusted
57 assert(offset + nbytes >= offset);
59 out
61 assert(offset + nbytes <= data.length);
65 if (data.length < offset + nbytes)
67 void[] vdata = data;
68 vdata.length = (offset + nbytes + 7) * 2; // allocates as void[] to not set BlkAttr.NO_SCAN
69 data = cast(ubyte[]) vdata;
73 /**********************************
74 * put enables OutBuffer to be used as an OutputRange.
76 alias put = write;
78 /*************************************
79 * Append data to the internal buffer.
82 void write(scope const(ubyte)[] bytes)
84 reserve(bytes.length);
85 data[offset .. offset + bytes.length] = bytes[];
86 offset += bytes.length;
89 void write(scope const(wchar)[] chars) @trusted
91 write(cast(ubyte[]) chars);
94 void write(scope const(dchar)[] chars) @trusted
96 write(cast(ubyte[]) chars);
99 void write(ubyte b) /// ditto
101 reserve(ubyte.sizeof);
102 this.data[offset] = b;
103 offset += ubyte.sizeof;
106 void write(byte b) { write(cast(ubyte) b); } /// ditto
107 void write(char c) { write(cast(ubyte) c); } /// ditto
108 void write(dchar c) { write(cast(uint) c); } /// ditto
110 void write(ushort w) @trusted /// ditto
112 reserve(ushort.sizeof);
113 *cast(ushort *)&data[offset] = w;
114 offset += ushort.sizeof;
117 void write(short s) { write(cast(ushort) s); } /// ditto
119 void write(wchar c) @trusted /// ditto
121 reserve(wchar.sizeof);
122 *cast(wchar *)&data[offset] = c;
123 offset += wchar.sizeof;
126 void write(uint w) @trusted /// ditto
128 reserve(uint.sizeof);
129 *cast(uint *)&data[offset] = w;
130 offset += uint.sizeof;
133 void write(int i) { write(cast(uint) i); } /// ditto
135 void write(ulong l) @trusted /// ditto
137 reserve(ulong.sizeof);
138 *cast(ulong *)&data[offset] = l;
139 offset += ulong.sizeof;
142 void write(long l) { write(cast(ulong) l); } /// ditto
144 void write(float f) @trusted /// ditto
146 reserve(float.sizeof);
147 *cast(float *)&data[offset] = f;
148 offset += float.sizeof;
151 void write(double f) @trusted /// ditto
153 reserve(double.sizeof);
154 *cast(double *)&data[offset] = f;
155 offset += double.sizeof;
158 void write(real f) @trusted /// ditto
160 reserve(real.sizeof);
161 *cast(real *)&data[offset] = f;
162 offset += real.sizeof;
165 void write(scope const(char)[] s) @trusted /// ditto
167 write(cast(ubyte[]) s);
170 void write(scope const OutBuffer buf) /// ditto
172 write(buf.toBytes());
175 /****************************************
176 * Append nbytes of val to the internal buffer.
177 * Params:
178 * nbytes = Number of bytes to fill.
179 * val = Value to fill, defaults to 0.
182 void fill(size_t nbytes, ubyte val = 0)
184 reserve(nbytes);
185 data[offset .. offset + nbytes] = val;
186 offset += nbytes;
189 /****************************************
190 * Append nbytes of 0 to the internal buffer.
191 * Param:
192 * nbytes - number of bytes to fill.
194 void fill0(size_t nbytes)
196 fill(nbytes);
199 /**********************************
200 * Append bytes until the buffer aligns on a power of 2 boundary.
202 * By default fills with 0 bytes.
204 * Params:
205 * alignsize = Alignment value. Must be power of 2.
206 * val = Value to fill, defaults to 0.
209 void alignSize(size_t alignsize, ubyte val = 0)
212 assert(alignsize && (alignsize & (alignsize - 1)) == 0);
216 assert((offset & (alignsize - 1)) == 0);
220 auto nbytes = offset & (alignsize - 1);
221 if (nbytes)
222 fill(alignsize - nbytes, val);
225 @safe unittest
227 OutBuffer buf = new OutBuffer();
228 buf.write(cast(ubyte) 1);
229 buf.align2();
230 assert(buf.toBytes() == "\x01\x00");
231 buf.write(cast(ubyte) 2);
232 buf.align4();
233 assert(buf.toBytes() == "\x01\x00\x02\x00");
234 buf.write(cast(ubyte) 3);
235 buf.alignSize(8);
236 assert(buf.toBytes() == "\x01\x00\x02\x00\x03\x00\x00\x00");
238 /// ditto
239 @safe unittest
241 OutBuffer buf = new OutBuffer();
242 buf.write(cast(ubyte) 1);
243 buf.align2(0x55);
244 assert(buf.toBytes() == "\x01\x55");
245 buf.write(cast(ubyte) 2);
246 buf.align4(0x55);
247 assert(buf.toBytes() == "\x01\x55\x02\x55");
248 buf.write(cast(ubyte) 3);
249 buf.alignSize(8, 0x55);
250 assert(buf.toBytes() == "\x01\x55\x02\x55\x03\x55\x55\x55");
253 /// Clear the data in the buffer
254 void clear()
256 offset = 0;
259 /****************************************
260 * Optimize common special case alignSize(2)
261 * Params:
262 * val = Value to fill, defaults to 0.
265 void align2(ubyte val = 0)
267 if (offset & 1)
268 write(cast(byte) val);
271 /****************************************
272 * Optimize common special case alignSize(4)
273 * Params:
274 * val = Value to fill, defaults to 0.
277 void align4(ubyte val = 0)
279 if (offset & 3)
280 { auto nbytes = (4 - offset) & 3;
281 fill(nbytes, val);
285 /**************************************
286 * Convert internal buffer to array of chars.
289 override string toString() const
291 //printf("OutBuffer.toString()\n");
292 return cast(string) data[0 .. offset].idup;
296 /*****************************************
297 * Append output of C's vprintf() to internal buffer.
300 void vprintf(scope string format, va_list args) @trusted nothrow
302 import core.stdc.stdio : vsnprintf;
303 import core.stdc.stdlib : alloca;
304 import std.string : toStringz;
306 version (StdUnittest)
307 char[3] buffer = void; // trigger reallocation
308 else
309 char[128] buffer = void;
310 int count;
312 // Can't use `tempCString()` here as it will result in compilation error:
313 // "cannot mix core.std.stdlib.alloca() and exception handling".
314 auto f = toStringz(format);
315 auto p = buffer.ptr;
316 auto psize = buffer.length;
317 for (;;)
319 va_list args2;
320 va_copy(args2, args);
321 count = vsnprintf(p, psize, f, args2);
322 va_end(args2);
323 if (count == -1)
325 if (psize > psize.max / 2) assert(0); // overflow check
326 psize *= 2;
328 else if (count >= psize)
330 if (count == count.max) assert(0); // overflow check
331 psize = count + 1;
333 else
334 break;
336 p = cast(char *) alloca(psize); // buffer too small, try again with larger size
338 write(cast(ubyte[]) p[0 .. count]);
341 /*****************************************
342 * Append output of C's printf() to internal buffer.
345 void printf(scope string format, ...) @trusted
347 va_list ap;
348 va_start(ap, format);
349 vprintf(format, ap);
350 va_end(ap);
354 * Formats and writes its arguments in text format to the OutBuffer.
356 * Params:
357 * fmt = format string as described in $(REF formattedWrite, std,format)
358 * args = arguments to be formatted
360 * See_Also:
361 * $(REF _writef, std,stdio);
362 * $(REF formattedWrite, std,format);
364 void writef(Char, A...)(scope const(Char)[] fmt, A args)
366 import std.format.write : formattedWrite;
367 formattedWrite(this, fmt, args);
371 @safe unittest
373 OutBuffer b = new OutBuffer();
374 b.writef("a%sb", 16);
375 assert(b.toString() == "a16b");
378 /// ditto
379 void writef(alias fmt, A...)(A args)
380 if (isSomeString!(typeof(fmt)))
382 import std.format : checkFormatException;
384 alias e = checkFormatException!(fmt, A);
385 static assert(!e, e);
386 return this.writef(fmt, args);
390 @safe unittest
392 OutBuffer b = new OutBuffer();
393 b.writef!"a%sb"(16);
394 assert(b.toString() == "a16b");
398 * Formats and writes its arguments in text format to the OutBuffer,
399 * followed by a newline.
401 * Params:
402 * fmt = format string as described in $(REF formattedWrite, std,format)
403 * args = arguments to be formatted
405 * See_Also:
406 * $(REF _writefln, std,stdio);
407 * $(REF formattedWrite, std,format);
409 void writefln(Char, A...)(scope const(Char)[] fmt, A args)
411 import std.format.write : formattedWrite;
412 formattedWrite(this, fmt, args);
413 put('\n');
417 @safe unittest
419 OutBuffer b = new OutBuffer();
420 b.writefln("a%sb", 16);
421 assert(b.toString() == "a16b\n");
424 /// ditto
425 void writefln(alias fmt, A...)(A args)
426 if (isSomeString!(typeof(fmt)))
428 import std.format : checkFormatException;
430 alias e = checkFormatException!(fmt, A);
431 static assert(!e, e);
432 return this.writefln(fmt, args);
436 @safe unittest
438 OutBuffer b = new OutBuffer();
439 b.writefln!"a%sb"(16);
440 assert(b.toString() == "a16b\n");
443 /*****************************************
444 * At offset index into buffer, create nbytes of space by shifting upwards
445 * all data past index.
448 void spread(size_t index, size_t nbytes) pure nothrow @safe
451 assert(index <= offset);
455 reserve(nbytes);
457 // This is an overlapping copy - should use memmove()
458 for (size_t i = offset; i > index; )
460 --i;
461 data[i + nbytes] = data[i];
463 offset += nbytes;
468 @safe unittest
470 import std.string : cmp;
472 OutBuffer buf = new OutBuffer();
474 assert(buf.offset == 0);
475 buf.write("hello");
476 buf.write(cast(byte) 0x20);
477 buf.write("world");
478 buf.printf(" %d", 62665);
479 assert(cmp(buf.toString(), "hello world 62665") == 0);
481 buf.clear();
482 assert(cmp(buf.toString(), "") == 0);
483 buf.write("New data");
484 assert(cmp(buf.toString(),"New data") == 0);
487 @safe unittest
489 import std.range;
490 static assert(isOutputRange!(OutBuffer, char));
492 import std.algorithm;
494 OutBuffer buf = new OutBuffer();
495 "hello".copy(buf);
496 assert(buf.toBytes() == "hello");
499 OutBuffer buf = new OutBuffer();
500 "hello"w.copy(buf);
501 version (LittleEndian)
502 assert(buf.toBytes() == "h\x00e\x00l\x00l\x00o\x00");
503 version (BigEndian)
504 assert(buf.toBytes() == "\x00h\x00e\x00l\x00l\x00o");
507 OutBuffer buf = new OutBuffer();
508 "hello"d.copy(buf);
509 version (LittleEndian)
510 assert(buf.toBytes() == "h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00");
511 version (BigEndian)
512 assert(buf.toBytes() == "\x00\x00\x00h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o");