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-2021 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 smaller than the 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     /********************
76      * Make sure we have at least `nbytes` available for writing,
77      * allocate more if necessary.
78      * This is the inlinable fast path. Prefer `enlarge` if allocation
79      * will always happen.
80      */
81     void reserve(size_t nbytes)
82     {
83         // Keep small so it is inlined
84         if (pend - p < nbytes)
85             enlarge(nbytes);
86     }
87 
88     // Reserve nbytes in buffer
89     void enlarge(size_t nbytes)
90     {
91         pragma(inline, false);  // do not inline slow path
92         const size_t oldlen = pend - buf;
93         const size_t used = p - buf;
94 
95         size_t len = used + nbytes;
96         // No need to reallocate
97         if (nbytes < (pend - p))
98             return;
99 
100         const size_t newlen = oldlen + (oldlen >> 1);   // oldlen * 1.5
101         if (len < newlen)
102             len = newlen;
103         len = (len + 15) & ~15;
104 
105         buf = cast(ubyte*) realloc(buf,len);
106         if (!buf)
107             err_nomem();
108 
109         pend = buf + len;
110         p = buf + used;
111     }
112 
113 
114     // Write n zeros; return pointer to start of zeros
115     void *writezeros(size_t n)
116     {
117         reserve(n);
118         void *pstart = memset(p,0,n);
119         p += n;
120         return pstart;
121     }
122 
123     // Position buffer to accept the specified number of bytes at offset
124     void position(size_t offset, size_t nbytes)
125     {
126         if (offset + nbytes > pend - buf)
127         {
128             reserve(offset + nbytes - (p - buf));
129         }
130         p = buf + offset;
131 
132         debug assert(buf <= p);
133         debug assert(p <= pend);
134         debug assert(p + nbytes <= pend);
135     }
136 
137     // Write an array to the buffer, no reserve check
138     void writen(const void *b, size_t len)
139     {
140         memcpy(p,b,len);
141         p += len;
142     }
143 
144     // Write an array to the buffer.
145     extern (D)
146     void write(const(void)[] b)
147     {
148         reserve(b.length);
149         memcpy(p, b.ptr, b.length);
150         p += b.length;
151     }
152 
153     void write(const(void)* b, size_t len)
154     {
155         write(b[0 .. len]);
156     }
157 
158     /**
159      * Writes an 8 bit byte, no reserve check.
160      */
161     void writeByten(ubyte v)
162     {
163         *p++ = v;
164     }
165 
166     /**
167      * Writes an 8 bit byte.
168      */
169     void writeByte(int v)
170     {
171         reserve(1);
172         *p++ = cast(ubyte)v;
173     }
174 
175     /**
176      * Writes a 16 bit value, no reserve check.
177      */
178     void write16n(int v)
179     {
180         *(cast(ushort *) p) = cast(ushort)v;
181         p += 2;
182     }
183 
184 
185     /**
186      * Writes a 16 bit value.
187      */
188     void write16(int v)
189     {
190         reserve(2);
191         write16n(v);
192     }
193 
194     /**
195      * Writes a 32 bit int.
196      */
197     void write32(int v)
198     {
199         reserve(4);
200         *cast(int *)p = v;
201         p += 4;
202     }
203 
204     /**
205      * Writes a 64 bit long.
206      */
207     void write64(long v)
208     {
209         reserve(8);
210         *cast(long *)p = v;
211         p += 8;
212     }
213 
214 
215     /**
216      * Writes a 32 bit float.
217      */
218     void writeFloat(float v)
219     {
220         reserve(float.sizeof);
221         *cast(float *)p = v;
222         p += float.sizeof;
223     }
224 
225     /**
226      * Writes a 64 bit double.
227      */
228     void writeDouble(double v)
229     {
230         reserve(double.sizeof);
231         *cast(double *)p = v;
232         p += double.sizeof;
233     }
234 
235     /**
236      * Writes a String as a sequence of bytes.
237      */
238     void write(const(char)* s)
239     {
240         write(s[0 .. strlen(s)]);
241     }
242 
243     /**
244      * Writes a 0 terminated String
245      */
246     void writeString(const(char)* s)
247     {
248         write(s[0 .. strlen(s)+1]);
249     }
250 
251     /// Ditto
252     extern(D) void writeString(const(char)[] s)
253     {
254         write(s);
255         writeByte(0);
256     }
257 
258     /// Disembiguation for `string`
259     extern(D) void writeString(string s)
260     {
261         writeString(cast(const(char)[])(s));
262     }
263 
264     /**
265      * Inserts string at beginning of buffer.
266      */
267     void prependBytes(const(char)* s)
268     {
269         prepend(s, strlen(s));
270     }
271 
272     /**
273      * Inserts bytes at beginning of buffer.
274      */
275     void prepend(const(void)* b, size_t len)
276     {
277         reserve(len);
278         memmove(buf + len,buf,p - buf);
279         memcpy(buf,b,len);
280         p += len;
281     }
282 
283     /**
284      * Bracket buffer contents with c1 and c2.
285      */
286     void bracket(char c1,char c2)
287     {
288         reserve(2);
289         memmove(buf + 1,buf,p - buf);
290         buf[0] = c1;
291         p[1] = c2;
292         p += 2;
293     }
294 
295     /**
296      * Returns the number of bytes written.
297      */
298     size_t length() const @safe pure nothrow @nogc
299     {
300         return p - buf;
301     }
302 
303     /**
304      * Set current size of buffer.
305      */
306 
307     void setsize(size_t size)
308     {
309         p = buf + size;
310         //debug assert(buf <= p);
311         //debug assert(p <= pend);
312     }
313 
314     void writesLEB128(int value)
315     {
316         while (1)
317         {
318             ubyte b = value & 0x7F;
319 
320             value >>= 7;            // arithmetic right shift
321             if (value == 0 && !(b & 0x40) ||
322                 value == -1 && (b & 0x40))
323             {
324                  writeByte(b);
325                  break;
326             }
327             writeByte(b | 0x80);
328         }
329     }
330 
331     void writeuLEB128(uint value)
332     {
333         do
334         {
335             ubyte b = value & 0x7F;
336 
337             value >>= 7;
338             if (value)
339                 b |= 0x80;
340             writeByte(b);
341         } while (value);
342     }
343 }