1 // Written in the D programming language.
4 Serialize data to $(D ubyte) arrays.
6 * Copyright: Copyright Digital Mars 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;)
15 import core
.stdc
.stdarg
; // : va_list;
17 /*********************************************
18 * OutBuffer provides a way to build up an array of bytes out
19 * of raw data. It is useful for things like preparing an
20 * array of bytes to write out to a file.
21 * OutBuffer's byte order is the format native to the computer.
22 * To control the byte order (endianness), use a class derived
24 * OutBuffer's internal buffer is allocated with the GC. Pointers
25 * stored into the buffer are scanned by the GC, but you have to
26 * ensure proper alignment, e.g. by using alignSize((void*).sizeof).
36 assert(offset
<= data
.length
);
41 /*********************************
42 * Convert to array of bytes.
44 ubyte[] toBytes() { return data
[0 .. offset
]; }
46 /***********************************
47 * Preallocate nbytes more to the size of the internal buffer.
50 * speed optimization, a good guess at the maximum size of the resulting
51 * buffer will improve performance by eliminating reallocations and copying.
53 void reserve(size_t nbytes
) @trusted
56 assert(offset
+ nbytes
>= offset
);
60 assert(offset
+ nbytes
<= data
.length
);
64 if (data
.length
< offset
+ nbytes
)
67 vdata
.length
= (offset
+ nbytes
+ 7) * 2; // allocates as void[] to not set BlkAttr.NO_SCAN
68 data
= cast(ubyte[]) vdata
;
72 /**********************************
73 * put enables OutBuffer to be used as an OutputRange.
77 /*************************************
78 * Append data to the internal buffer.
81 void write(const(ubyte)[] bytes
)
83 reserve(bytes
.length
);
84 data
[offset
.. offset
+ bytes
.length
] = bytes
[];
85 offset
+= bytes
.length
;
88 void write(in wchar[] chars
) @trusted
90 write(cast(ubyte[]) chars
);
93 void write(const(dchar)[] chars
) @trusted
95 write(cast(ubyte[]) chars
);
98 void write(ubyte b
) /// ditto
100 reserve(ubyte.sizeof
);
101 this.data
[offset
] = b
;
102 offset
+= ubyte.sizeof
;
105 void write(byte b
) { write(cast(ubyte) b
); } /// ditto
106 void write(char c
) { write(cast(ubyte) c
); } /// ditto
107 void write(dchar c
) { write(cast(uint) c
); } /// ditto
109 void write(ushort w
) @trusted /// ditto
111 reserve(ushort.sizeof
);
112 *cast(ushort *)&data
[offset
] = w
;
113 offset
+= ushort.sizeof
;
116 void write(short s
) { write(cast(ushort) s
); } /// ditto
118 void write(wchar c
) @trusted /// ditto
120 reserve(wchar.sizeof
);
121 *cast(wchar *)&data
[offset
] = c
;
122 offset
+= wchar.sizeof
;
125 void write(uint w
) @trusted /// ditto
127 reserve(uint.sizeof
);
128 *cast(uint *)&data
[offset
] = w
;
129 offset
+= uint.sizeof
;
132 void write(int i
) { write(cast(uint) i
); } /// ditto
134 void write(ulong l
) @trusted /// ditto
136 reserve(ulong.sizeof
);
137 *cast(ulong *)&data
[offset
] = l
;
138 offset
+= ulong.sizeof
;
141 void write(long l
) { write(cast(ulong) l
); } /// ditto
143 void write(float f
) @trusted /// ditto
145 reserve(float.sizeof
);
146 *cast(float *)&data
[offset
] = f
;
147 offset
+= float.sizeof
;
150 void write(double f
) @trusted /// ditto
152 reserve(double.sizeof
);
153 *cast(double *)&data
[offset
] = f
;
154 offset
+= double.sizeof
;
157 void write(real f
) @trusted /// ditto
159 reserve(real.sizeof
);
160 *cast(real *)&data
[offset
] = f
;
161 offset
+= real.sizeof
;
164 void write(in char[] s
) @trusted /// ditto
166 write(cast(ubyte[]) s
);
169 void write(OutBuffer buf
) /// ditto
171 write(buf
.toBytes());
174 /****************************************
175 * Append nbytes of 0 to the internal buffer.
178 void fill0(size_t nbytes
)
181 data
[offset
.. offset
+ nbytes
] = 0;
185 /**********************************
186 * 0-fill to align on power of 2 boundary.
189 void alignSize(size_t alignsize
)
192 assert(alignsize
&& (alignsize
& (alignsize
- 1)) == 0);
196 assert((offset
& (alignsize
- 1)) == 0);
200 auto nbytes
= offset
& (alignsize
- 1);
202 fill0(alignsize
- nbytes
);
205 /// Clear the data in the buffer
211 /****************************************
212 * Optimize common special case alignSize(2)
221 /****************************************
222 * Optimize common special case alignSize(4)
228 { auto nbytes
= (4 - offset
) & 3;
233 /**************************************
234 * Convert internal buffer to array of chars.
237 override string
toString() const
239 //printf("OutBuffer.toString()\n");
240 return cast(string
) data
[0 .. offset
].idup
;
244 /*****************************************
245 * Append output of C's vprintf() to internal buffer.
248 void vprintf(string format
, va_list args
) @trusted nothrow
250 import core
.stdc
.stdio
: vsnprintf
;
251 import core
.stdc
.stdlib
: alloca
;
252 import std
.string
: toStringz
;
255 char[3] buffer
= void; // trigger reallocation
257 char[128] buffer
= void;
260 // Can't use `tempCString()` here as it will result in compilation error:
261 // "cannot mix core.std.stdlib.alloca() and exception handling".
262 auto f
= toStringz(format
);
264 auto psize
= buffer
.length
;
268 va_copy(args2
, args
);
269 count
= vsnprintf(p
, psize
, f
, args2
);
273 if (psize
> psize
.max
/ 2) assert(0); // overflow check
276 else if (count
>= psize
)
278 if (count
== count
.max
) assert(0); // overflow check
284 p
= cast(char *) alloca(psize
); // buffer too small, try again with larger size
286 write(cast(ubyte[]) p
[0 .. count
]);
289 /*****************************************
290 * Append output of C's printf() to internal buffer.
293 void printf(string format
, ...) @trusted
296 va_start(ap
, format
);
302 * Formats and writes its arguments in text format to the OutBuffer.
305 * fmt = format string as described in $(REF formattedWrite, std,format)
306 * args = arguments to be formatted
309 * $(REF _writef, std,stdio);
310 * $(REF formattedWrite, std,format);
312 void writef(Char
, A
...)(in Char
[] fmt
, A args
)
314 import std
.format
: formattedWrite
;
315 formattedWrite(this, fmt
, args
);
321 OutBuffer b
= new OutBuffer();
322 b
.writef("a%sb", 16);
323 assert(b
.toString() == "a16b");
327 * Formats and writes its arguments in text format to the OutBuffer,
328 * followed by a newline.
331 * fmt = format string as described in $(REF formattedWrite, std,format)
332 * args = arguments to be formatted
335 * $(REF _writefln, std,stdio);
336 * $(REF formattedWrite, std,format);
338 void writefln(Char
, A
...)(in Char
[] fmt
, A args
)
340 import std
.format
: formattedWrite
;
341 formattedWrite(this, fmt
, args
);
348 OutBuffer b
= new OutBuffer();
349 b
.writefln("a%sb", 16);
350 assert(b
.toString() == "a16b\n");
353 /*****************************************
354 * At offset index into buffer, create nbytes of space by shifting upwards
355 * all data past index.
358 void spread(size_t index
, size_t nbytes
) pure nothrow @safe
361 assert(index
<= offset
);
367 // This is an overlapping copy - should use memmove()
368 for (size_t i
= offset
; i
> index
; )
371 data
[i
+ nbytes
] = data
[i
];
380 import std
.string
: cmp;
382 OutBuffer buf
= new OutBuffer();
384 assert(buf
.offset
== 0);
386 buf
.write(cast(byte) 0x20);
388 buf
.printf(" %d", 62665);
389 assert(cmp(buf
.toString(), "hello world 62665") == 0);
392 assert(cmp(buf
.toString(), "") == 0);
393 buf
.write("New data");
394 assert(cmp(buf
.toString(),"New data") == 0);
400 static assert(isOutputRange
!(OutBuffer
, char));
402 import std
.algorithm
;
404 OutBuffer buf
= new OutBuffer();
406 assert(buf
.toBytes() == "hello");
409 OutBuffer buf
= new OutBuffer();
411 assert(buf
.toBytes() == "h\x00e\x00l\x00l\x00o\x00");
414 OutBuffer buf
= new OutBuffer();
416 assert(buf
.toBytes() == "h\x00\x00\x00e\x00\x00\x00l\x00\x00\x00l\x00\x00\x00o\x00\x00\x00");