1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1994-1998 by Symantec
6  *              Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/outbuf.d, backend/outbuf.d)
10  * Documentation: https://dlang.org/phobos/dmd_backend_outbuf.html
11  */
12 
13 module dmd.backend.outbuf;
14 
15 import core.stdc.stdio;
16 import core.stdc.stdlib;
17 import core.stdc.string;
18 
19 // Output buffer
20 
21 // (This used to be called OutBuffer, renamed to avoid name conflicts with Mars.)
22 
23 extern (C++):
24 
25 private nothrow void err_nomem();
26 
27 struct Outbuffer
28 {
29     ubyte *buf;         // the buffer itself
30     ubyte *pend;        // pointer past the end of the buffer
31     private ubyte *p;   // current position in buffer
32 
33   nothrow:
34     this(size_t initialSize)
35     {
36         reserve(initialSize);
37     }
38 
39     //~this() { dtor(); }
40 
41     void dtor()
42     {
43         if (auto slice = this.extractSlice())
44             free(slice.ptr);
45     }
46 
47     void reset()
48     {
49         p = buf;
50     }
51 
52     // Returns: A slice to the data written so far
53     extern(D) inout(ubyte)[] opSlice(size_t from, size_t to) inout
54         @trusted pure nothrow @nogc
55     {
56         assert(this.buf, "Attempt to dereference a null pointer");
57         assert(from < to, "First index must be <= to second one");
58         assert(this.length() <= (to - from), "Out of bound access");
59         return this.buf[from .. to];
60     }
61 
62     /// Ditto
63     extern(D) inout(ubyte)[] opSlice() inout @trusted pure nothrow @nogc
64     {
65         return this.buf[0 .. this.p - this.buf];
66     }
67 
68     extern(D) ubyte[] extractSlice() @safe pure nothrow @nogc
69     {
70         auto ret = this[];
71         this.buf = this.p = this.pend = null;
72         return ret;
73     }
74 
75     // Make sure we have at least `nbyte` available for writting
76     void reserve(size_t nbytes)
77     {
78         const size_t oldlen = pend - buf;
79         const size_t used = p - buf;
80 
81         size_t len = used + nbytes;
82         // No need to reallocate
83         if (nbytes < (pend - p))
84             return;
85 
86         const size_t newlen = oldlen + (oldlen >> 1);   // oldlen * 1.5
87         if (len < newlen)
88             len = newlen;
89         len = (len + 15) & ~15;
90 
91         buf = cast(ubyte*) realloc(buf,len);
92         if (!buf)
93             err_nomem();
94 
95         pend = buf + len;
96         p = buf + used;
97     }
98 
99 
100     // Write n zeros; return pointer to start of zeros
101     void *writezeros(size_t n)
102     {
103         reserve(n);
104         void *pstart = memset(p,0,n);
105         p += n;
106         return pstart;
107     }
108 
109     // Position buffer to accept the specified number of bytes at offset
110     void position(size_t offset, size_t nbytes)
111     {
112         if (offset + nbytes > pend - buf)
113         {
114             reserve(offset + nbytes - (p - buf));
115         }
116         p = buf + offset;
117 
118         debug assert(buf <= p);
119         debug assert(p <= pend);
120         debug assert(p + nbytes <= pend);
121     }
122 
123     // Write an array to the buffer, no reserve check
124     void writen(const void *b, size_t len)
125     {
126         memcpy(p,b,len);
127         p += len;
128     }
129 
130     // Write an array to the buffer.
131     extern (D)
132     void write(const(void)[] b)
133     {
134         reserve(b.length);
135         memcpy(p, b.ptr, b.length);
136         p += b.length;
137     }
138 
139     void write(const(void)* b, size_t len)
140     {
141         write(b[0 .. len]);
142     }
143 
144     /**
145      * Writes an 8 bit byte, no reserve check.
146      */
147     void writeByten(ubyte v)
148     {
149         *p++ = v;
150     }
151 
152     /**
153      * Writes an 8 bit byte.
154      */
155     void writeByte(int v)
156     {
157         reserve(1);
158         *p++ = cast(ubyte)v;
159     }
160 
161     /**
162      * Writes a 16 bit value, no reserve check.
163      */
164     void write16n(int v)
165     {
166         *(cast(ushort *) p) = cast(ushort)v;
167         p += 2;
168     }
169 
170 
171     /**
172      * Writes a 16 bit value.
173      */
174     void write16(int v)
175     {
176         reserve(2);
177         write16n(v);
178     }
179 
180     /**
181      * Writes a 32 bit int.
182      */
183     void write32(int v)
184     {
185         reserve(4);
186         *cast(int *)p = v;
187         p += 4;
188     }
189 
190     /**
191      * Writes a 64 bit long.
192      */
193     void write64(long v)
194     {
195         reserve(8);
196         *cast(long *)p = v;
197         p += 8;
198     }
199 
200 
201     /**
202      * Writes a 32 bit float.
203      */
204     void writeFloat(float v)
205     {
206         reserve(float.sizeof);
207         *cast(float *)p = v;
208         p += float.sizeof;
209     }
210 
211     /**
212      * Writes a 64 bit double.
213      */
214     void writeDouble(double v)
215     {
216         reserve(double.sizeof);
217         *cast(double *)p = v;
218         p += double.sizeof;
219     }
220 
221     /**
222      * Writes a String as a sequence of bytes.
223      */
224     void write(const(char)* s)
225     {
226         write(s[0 .. strlen(s)]);
227     }
228 
229     /**
230      * Writes a 0 terminated String
231      */
232     void writeString(const(char)* s)
233     {
234         write(s[0 .. strlen(s)+1]);
235     }
236 
237     /// Ditto
238     extern(D) void writeString(const(char)[] s)
239     {
240         write(s);
241         writeByte(0);
242     }
243 
244     /// Disembiguation for `string`
245     extern(D) void writeString(string s)
246     {
247         writeString(cast(const(char)[])(s));
248     }
249 
250     /**
251      * Inserts string at beginning of buffer.
252      */
253     void prependBytes(const(char)* s)
254     {
255         prepend(s, strlen(s));
256     }
257 
258     /**
259      * Inserts bytes at beginning of buffer.
260      */
261     void prepend(const(void)* b, size_t len)
262     {
263         reserve(len);
264         memmove(buf + len,buf,p - buf);
265         memcpy(buf,b,len);
266         p += len;
267     }
268 
269     /**
270      * Bracket buffer contents with c1 and c2.
271      */
272     void bracket(char c1,char c2)
273     {
274         reserve(2);
275         memmove(buf + 1,buf,p - buf);
276         buf[0] = c1;
277         p[1] = c2;
278         p += 2;
279     }
280 
281     /**
282      * Returns the number of bytes written.
283      */
284     size_t length() const @safe pure nothrow @nogc
285     {
286         return p - buf;
287     }
288 
289     /**
290      * Set current size of buffer.
291      */
292 
293     void setsize(size_t size)
294     {
295         p = buf + size;
296         //debug assert(buf <= p);
297         //debug assert(p <= pend);
298     }
299 
300     void writesLEB128(int value)
301     {
302         while (1)
303         {
304             ubyte b = value & 0x7F;
305 
306             value >>= 7;            // arithmetic right shift
307             if (value == 0 && !(b & 0x40) ||
308                 value == -1 && (b & 0x40))
309             {
310                  writeByte(b);
311                  break;
312             }
313             writeByte(b | 0x80);
314         }
315     }
316 
317     void writeuLEB128(uint value)
318     {
319         do
320         {
321             ubyte b = value & 0x7F;
322 
323             value >>= 7;
324             if (value)
325                 b |= 0x80;
326             writeByte(b);
327         } while (value);
328     }
329 }