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 }