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 }