Mercurial > projects > ldc
diff lphobos/std/outbuffer.d @ 473:373489eeaf90
Applied downs' lphobos update
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Mon, 04 Aug 2008 19:28:49 +0200 |
parents | |
children | 88e23f8c2354 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lphobos/std/outbuffer.d Mon Aug 04 19:28:49 2008 +0200 @@ -0,0 +1,368 @@ +// outbuffer.d + +/** + * Boilerplate: + * $(std_boilerplate.html) + * Macros: + * WIKI = Phobos/StdOutbuffer + * Copyright: + * Copyright (c) 2001-2005 by Digital Mars + * All Rights Reserved + * www.digitalmars.com + */ + + +// Written by Walter Bright + +/* NOTE: This file has been patched from the original DMD distribution to + work with the GDC compiler. + + Modified by David Friedman, September 2004 +*/ + +module std.outbuffer; + +private +{ + import std.string; + import std.gc; + import std.c.stdio; + import std.c.stdlib; + import std.c.stdarg; +} + +/********************************************* + * OutBuffer provides a way to build up an array of bytes out + * of raw data. It is useful for things like preparing an + * array of bytes to write out to a file. + * OutBuffer's byte order is the format native to the computer. + * To control the byte order (endianness), use a class derived + * from OutBuffer. + */ + +class OutBuffer +{ + ubyte data[]; + size_t offset; + + invariant + { + //printf("this = %p, offset = %x, data.length = %u\n", this, offset, data.length); + assert(offset <= data.length); + assert(data.length <= std.gc.capacity(data.ptr)); + } + + this() + { + //printf("in OutBuffer constructor\n"); + } + + /********************************* + * Convert to array of bytes. + */ + + ubyte[] toBytes() { return data[0 .. offset]; } + + /*********************************** + * Preallocate nbytes more to the size of the internal buffer. + * + * This is a + * speed optimization, a good guess at the maximum size of the resulting + * buffer will improve performance by eliminating reallocations and copying. + */ + + + void reserve(size_t nbytes) + in + { + assert(offset + nbytes >= offset); + } + out + { + assert(offset + nbytes <= data.length); + assert(data.length <= std.gc.capacity(data.ptr)); + } + body + { + if (data.length < offset + nbytes) + { + //std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, offset = %d, nbytes = %d, capacity = %d\n", data.ptr, data.length, offset, nbytes, std.gc.capacity(data.ptr)); + data.length = (offset + nbytes) * 2; + //std.c.stdio.printf("OutBuffer.reserve: ptr = %p, length = %d, capacity = %d\n", data.ptr, data.length, std.gc.capacity(data.ptr)); + std.gc.hasPointers(data.ptr); + } + } + + /************************************* + * Append data to the internal buffer. + */ + + void write(ubyte[] bytes) + { + reserve(bytes.length); + data[offset .. offset + bytes.length] = bytes; + offset += bytes.length; + } + + void write(ubyte b) /// ditto + { + reserve(ubyte.sizeof); + this.data[offset] = b; + offset += ubyte.sizeof; + } + + void write(byte b) { write(cast(ubyte)b); } /// ditto + void write(char c) { write(cast(ubyte)c); } /// ditto + + void write(ushort w) /// ditto + { + reserve(ushort.sizeof); + *cast(ushort *)&data[offset] = w; + offset += ushort.sizeof; + } + + void write(short s) { write(cast(ushort)s); } /// ditto + + void write(wchar c) /// ditto + { + reserve(wchar.sizeof); + *cast(wchar *)&data[offset] = c; + offset += wchar.sizeof; + } + + void write(uint w) /// ditto + { + reserve(uint.sizeof); + *cast(uint *)&data[offset] = w; + offset += uint.sizeof; + } + + void write(int i) { write(cast(uint)i); } /// ditto + + void write(ulong l) /// ditto + { + reserve(ulong.sizeof); + *cast(ulong *)&data[offset] = l; + offset += ulong.sizeof; + } + + void write(long l) { write(cast(ulong)l); } /// ditto + + void write(float f) /// ditto + { + reserve(float.sizeof); + *cast(float *)&data[offset] = f; + offset += float.sizeof; + } + + void write(double f) /// ditto + { + reserve(double.sizeof); + *cast(double *)&data[offset] = f; + offset += double.sizeof; + } + + void write(real f) /// ditto + { + reserve(real.sizeof); + *cast(real *)&data[offset] = f; + offset += real.sizeof; + } + + void write(char[] s) /// ditto + { + write(cast(ubyte[])s); + } + + void write(OutBuffer buf) /// ditto + { + write(buf.toBytes()); + } + + /**************************************** + * Append nbytes of 0 to the internal buffer. + */ + + void fill0(uint nbytes) + { + reserve(nbytes); + data[offset .. offset + nbytes] = 0; + offset += nbytes; + } + + /********************************** + * 0-fill to align on power of 2 boundary. + */ + + void alignSize(size_t alignsize) + in + { + assert(alignsize && (alignsize & (alignsize - 1)) == 0); + } + out + { + assert((offset & (alignsize - 1)) == 0); + } + body + { size_t nbytes; + + nbytes = offset & (alignsize - 1); + if (nbytes) + fill0(alignsize - nbytes); + } + + /**************************************** + * Optimize common special case alignSize(2) + */ + + void align2() + { + if (offset & 1) + write(cast(byte)0); + } + + /**************************************** + * Optimize common special case alignSize(4) + */ + + void align4() + { + if (offset & 3) + { size_t nbytes = (4 - offset) & 3; + fill0(nbytes); + } + } + + /************************************** + * Convert internal buffer to array of chars. + */ + + char[] toString() + { + //printf("OutBuffer.toString()\n"); + return cast(char[])data[0 .. offset]; + } + + /***************************************** + * Append output of C's vprintf() to internal buffer. + */ + + void vprintf(char[] format, va_list args) + { + char[128] buffer; + char* p; + char* f; + uint psize; + int count; + va_list args_copy; + + f = toStringz(format); + p = buffer.ptr; + psize = buffer.length; + for (;;) + { + va_copy(args_copy, args); + version(Win32) + { + count = _vsnprintf(p,psize,f,args_copy); + if (count != -1) + break; + psize *= 2; + p = cast(char *) alloca(psize); // buffer too small, try again with larger size + } + else version(GNU) { + count = vsnprintf(p,psize,f,args_copy); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; + p = cast(char *) alloca(psize); // buffer too small, try again with larger size + } + else version(linux) + { + count = vsnprintf(p,psize,f,args_copy); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; + /+ + if (p != buffer) + c.stdlib.free(p); + p = (char *) c.stdlib.malloc(psize); // buffer too small, try again with larger size + +/ + p = cast(char *) alloca(psize); // buffer too small, try again with larger size + } + } + write(p[0 .. count]); + /+ + version (linux) + { + if (p != buffer) + c.stdlib.free(p); + } + +/ + } + + /***************************************** + * Append output of C's printf() to internal buffer. + */ + + void printf(char[] format, ...) + { + version (GNU) + { + vprintf(format, _argptr); + } + else + { + va_list ap; + ap = cast(va_list)&format; + ap += format.sizeof; + vprintf(format, ap); + } + } + + /***************************************** + * At offset index into buffer, create nbytes of space by shifting upwards + * all data past index. + */ + + void spread(size_t index, size_t nbytes) + in + { + assert(index <= offset); + } + body + { + reserve(nbytes); + + // This is an overlapping copy - should use memmove() + for (size_t i = offset; i > index; ) + { + --i; + data[i + nbytes] = data[i]; + } + offset += nbytes; + } +} + +unittest +{ + //printf("Starting OutBuffer test\n"); + + OutBuffer buf = new OutBuffer(); + + //printf("buf = %p\n", buf); + //printf("buf.offset = %x\n", buf.offset); + assert(buf.offset == 0); + buf.write("hello"); + buf.write(cast(byte)0x20); + buf.write("world"); + buf.printf(" %d", 6); + //printf("buf = '%.*s'\n", buf.toString()); + assert(cmp(buf.toString(), "hello world 6") == 0); +}