1 // Written in the D programming language.
2 
3 /**
4  * Boilerplate:
5  *      $(std_boilerplate.html)
6  * Macros:
7  *      WIKI = Phobos/StdOutbuffer
8  *
9  * Copyright: Copyright Digital Mars 2000 - 2009.
10  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
11  * Authors:   $(WEB digitalmars.com, Walter Bright)
12  */
13 /*          Copyright Digital Mars 2000 - 2009.
14  * Distributed under the Boost Software License, Version 1.0.
15  *    (See accompanying file LICENSE_1_0.txt or copy at
16  *          http://www.boost.org/LICENSE_1_0.txt)
17  */
18 module dmdscript.outbuffer;
19 
20 private
21 {
22     import core.memory;
23     import std.string;
24     import core.stdc.stdio;
25     import core.stdc.stdlib;
26     import core.stdc.stdarg;
27 }
28 
29 /*********************************************
30  * OutBuffer provides a way to build up an array of bytes out
31  * of raw data. It is useful for things like preparing an
32  * array of bytes to write out to a file.
33  * OutBuffer's byte order is the format native to the computer.
34  * To control the byte order (endianness), use a class derived
35  * from OutBuffer.
36  */
37 
38 class OutBuffer
39 {
40     void[] data;
41     uint offset;
42 
43     invariant()
44     {
45         //printf("this = %p, offset = %x, data.length = %u\n", this, offset, data.length);
46         assert(offset <= data.length);
47     }
48 
49     this()
50     {
51         //printf("in OutBuffer constructor\n");
52     }
53 
54     /*********************************
55      * Convert to array
56      */
57 
58     void[] toBytes() { return data[0 .. offset]; }
59 
60     /***********************************
61      * Preallocate nbytes more to the size of the internal buffer.
62      *
63      * This is a
64      * speed optimization, a good guess at the maximum size of the resulting
65      * buffer will improve performance by eliminating reallocations and copying.
66      */
67 
68 
69     void reserve(size_t nbytes)
70         in
71         {
72             assert(offset + nbytes >= offset);
73         }
74         out
75         {
76             assert(offset + nbytes <= data.length);
77         }
78         do
79         {
80             //c.stdio.printf("OutBuffer.reserve: length = %d, offset = %d, nbytes = %d\n", data.length, offset, nbytes);
81             if (data.length < offset + nbytes)
82             {
83                 data.length = (offset + nbytes) * 2;
84             }
85         }
86 
87     /*************************************
88      * Append data to the internal buffer.
89      */
90 
91     void write(const(ubyte)[] bytes)
92         {
93             reserve(bytes.length);
94             (cast(ubyte[])data)[offset .. offset + bytes.length] = bytes[0..$];
95             offset += bytes.length;
96         }
97 
98     void write(in wchar[] chars)
99         {
100         write(cast(ubyte[]) chars);
101         }
102 
103     void write(const(dchar)[] chars)
104         {
105         write(cast(ubyte[]) chars);
106         }
107 
108     void write(ubyte b)         /// ditto
109         {
110             reserve(ubyte.sizeof);
111             *cast(ubyte *)&data[offset] = b;
112             offset += ubyte.sizeof;
113         }
114 
115     void write(byte b) { write(cast(ubyte)b); }         /// ditto
116     void write(char c) { write(cast(ubyte)c); }         /// ditto
117     void write(dchar c) { write(cast(uint)c); }         /// ditto
118 
119     void write(ushort w)                /// ditto
120     {
121         reserve(ushort.sizeof);
122         *cast(ushort *)&data[offset] = w;
123         offset += ushort.sizeof;
124     }
125 
126     void write(short s) { write(cast(ushort)s); }               /// ditto
127 
128     void write(wchar c)         /// ditto
129     {
130         reserve(wchar.sizeof);
131         *cast(wchar *)&data[offset] = c;
132         offset += wchar.sizeof;
133     }
134 
135     void write(uint w)          /// ditto
136     {
137         reserve(uint.sizeof);
138         *cast(uint *)&data[offset] = w;
139         offset += uint.sizeof;
140     }
141 
142     void write(int i) { write(cast(uint)i); }           /// ditto
143 
144     void write(ulong l)         /// ditto
145     {
146         reserve(ulong.sizeof);
147         *cast(ulong *)&data[offset] = l;
148         offset += ulong.sizeof;
149     }
150 
151     void write(long l) { write(cast(ulong)l); }         /// ditto
152 
153     void write(float f)         /// ditto
154     {
155         reserve(float.sizeof);
156         *cast(float *)&data[offset] = f;
157         offset += float.sizeof;
158     }
159 
160     void write(double f)                /// ditto
161     {
162         reserve(double.sizeof);
163         *cast(double *)&data[offset] = f;
164         offset += double.sizeof;
165     }
166 
167     void write(real f)          /// ditto
168     {
169         reserve(real.sizeof);
170         *cast(real *)&data[offset] = f;
171         offset += real.sizeof;
172     }
173 
174     void write(in char[] s)             /// ditto
175     {
176         write(cast(ubyte[])s);
177     }
178     // void write(immutable(char)[] s)          /// ditto
179     // {
180     //     write(cast(ubyte[])s);
181     // }
182 
183     void write(OutBuffer buf)           /// ditto
184     {
185         write(cast(ubyte[])buf.toBytes());
186     }
187 
188     /****************************************
189      * Append nbytes of 0 to the internal buffer.
190      */
191 
192     void fill0(uint nbytes)
193     {
194         reserve(nbytes);
195         auto range = cast(ubyte[])data[offset .. offset + nbytes];
196         range[] = 0;
197         offset += nbytes;
198     }
199 
200     /**********************************
201      * 0-fill to align on power of 2 boundary.
202      */
203 
204     void alignSize(uint alignsize)
205     in
206     {
207         assert(alignsize && (alignsize & (alignsize - 1)) == 0);
208     }
209     out
210     {
211         assert((offset & (alignsize - 1)) == 0);
212     }
213     do
214     {   uint nbytes;
215 
216         nbytes = offset & (alignsize - 1);
217         if (nbytes)
218             fill0(alignsize - nbytes);
219     }
220 
221     /****************************************
222      * Optimize common special case alignSize(2)
223      */
224 
225     void align2()
226     {
227         if (offset & 1)
228             write(cast(byte)0);
229     }
230 
231     /****************************************
232      * Optimize common special case alignSize(4)
233      */
234 
235     void align4()
236     {
237         if (offset & 3)
238         {   uint nbytes = (4 - offset) & 3;
239             fill0(nbytes);
240         }
241     }
242 
243     /**************************************
244      * Convert internal buffer to array of chars.
245      */
246 
247     override string toString()
248     {
249         //printf("OutBuffer.toString()\n");
250         return cast(string) data[0 .. offset].idup;
251     }
252 
253 
254     /*****************************************
255      * At offset index into buffer, create nbytes of space by shifting upwards
256      * all data past index.
257      */
258 
259     void spread(size_t index, size_t nbytes)
260         in
261         {
262             assert(index <= offset);
263         }
264         do
265         {
266             reserve(nbytes);
267 
268             // This is an overlapping copy - should use memmove()
269             for (uint i = offset; i > index; )
270             {
271                 --i;
272                 *cast(ubyte*)&data[i + nbytes] = *cast(ubyte*)&data[i];
273             }
274             offset += nbytes;
275         }
276 }
277 
278 unittest
279 {
280     //printf("Starting OutBuffer test\n");
281 
282     OutBuffer buf = new OutBuffer();
283 
284     //printf("buf = %p\n", buf);
285     //printf("buf.offset = %x\n", buf.offset);
286     assert(buf.offset == 0);
287     buf.write("hello"[]);
288     buf.write(cast(byte)0x20);
289     buf.write("world"[]);
290     //printf("buf = '%.*s'\n", buf.toString());
291     assert(cmp(buf.toString(), "hello world") == 0);
292 }