October 18, 2014
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.


October 18, 2014
On Sat, 18 Oct 2014 00:32:09 +0000
Lucas Burson via Digitalmars-d-learn
<digitalmars-d-learn@puremagic.com> wrote:

p.s. it's ok to take '.length' from 'null' array. compiler is smart enough.


October 18, 2014
On Saturday, 18 October 2014 at 00:53:57 UTC, ketmar via Digitalmars-d-learn wrote:
> On Sat, 18 Oct 2014 00:32:09 +0000
> Lucas Burson via Digitalmars-d-learn
> <digitalmars-d-learn@puremagic.com> wrote:
>


Wow, your changes made it much simpler. Thank you for the suggestions and expertise ketmar :)
October 18, 2014
On Sat, 18 Oct 2014 16:56:09 +0000
Lucas Burson via Digitalmars-d-learn
<digitalmars-d-learn@puremagic.com> wrote:

> Wow, your changes made it much simpler. Thank you for the suggestions and expertise ketmar :)
you're welcome.


1 2
Next ›   Last »