On Sat, 18 Oct 2014 00:32:09 +0000 Lucas Burson via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com> wrote:
> On Friday, 17 October 2014 at 17:40:09 UTC, ketmar via > Digitalmars-d-learn wrote: > > > i developed a habit of making such buffers one byte bigger than > > necessary and just setting the last byte to 0 before > > converting. this > > way it's guaranteed to be 0-terminated. > > Perfect, great idea. Below is my utility method to pull strings > out of a buffer. > > > /** > * Get a string from buffer where the string spans [offset_start, > offset_end). > * Params: > * buffer = Buffer with an ASCII string to obtain. > * offset_start = Beginning byte offset within the buffer > where the string starts. > * offset_end = Ending byte offset which is not included in > the string. > */ > string bufferGetString(ubyte[] buffer, ulong offset_start, ulong > offset_end) > in > { > assert(buffer != null); > assert(offset_start < offset_end); > assert(offset_end <= buffer.length); > } > body > { > ulong bufflen = offset_end - offset_start; > > // add one to the lenth for null-termination > ubyte[] temp = new ubyte[bufflen+1]; > temp[0..bufflen] = buffer[offset_start..offset_end]; > temp[bufflen] = '\0'; > > return strip(to!string(cast(const char*) temp.ptr)); > } > > unittest > { > ubyte[] no_null = [' ', 'A', 'B', 'C', ' ']; > assert("ABC" == bufferGetString(no_null, 0, no_null.length)); > assert("ABC" == bufferGetString(no_null, 1, no_null.length-1)); > assert("A" == bufferGetString(no_null, 1, 2)); > } note that you can make your code slightly simplier (and more correct): size_t bufflen = offset_end-offset_start; // add one to the lenth for null-termination auto temp = new ubyte[bufflen+1]; // compiler knows the type ;-) temp[0..$-1] = buffer[offset_start..offset_end]; // this is not necessary, as 'temp' is initialized with zeroes //temp[$-1] = '\0'; return strip(to!string(cast(const char*) temp.ptr)); also note that this allocates like crazy. ;-) this can be tolerable, but good to remember anyway. besides, slices rocks, so you can just pass a slice there. so: string bufferGetString (const(ubyte)[] buffer) { import std.conv : to; import std.string : strip; if (buffer.length == 0) return null; // or "" if (buffer[$-1] == 0) return to!string(cast(char*)buffer.ptr).strip; auto temp = new ubyte[](buffer.length+1); temp[0..$-1] = buffer[]; return to!string(cast(char*)temp.ptr).strip; } unittest { ubyte[] no_null = [' ', 'A', 'B', 'C', ' ']; immutable ubyte[] no_nullI = [' ', 'A', 'B', 'C', ' ']; assert("ABC" == bufferGetString(no_null[0..$])); assert("ABC" == bufferGetString(no_null[1..$-1])); // look, we can use const/immutable buffers too! assert("A" == bufferGetString(no_nullI[1..2])); } slices are cheap, and you'll get range checking at the call site.
signature.asc
Description: PGP signature