www.digitalmars.com

D Programming Language 2.0





std.buffer.scopebuffer

struct ScopeBuffer(T) if (isAssignable!T && !hasElaborateDestructor!T && !hasElaborateCopyConstructor!T && !hasElaborateAssign!T);
ScopeBuffer encapsulates using a local array as a temporary buffer. It is initialized with the local array that should be large enough for most uses. If the need exceeds the size, ScopeBuffer will resize it using malloc() and friends.

ScopeBuffer cannot contain more than (uint.max-16)/2 elements.

ScopeBuffer is an OutputRange.

Since ScopeBuffer potentially stores elements of type T in malloc'd memory, those elements are not scanned when the GC collects. This can cause memory corruption. Do not use ScopeBuffer when elements of type T point to the GC heap.

Example:
import core.stdc.stdio;
import std.buffer.scopebuffer;
void main()
{
    char[2] buf = void;
    auto textbuf = ScopeBuffer!char(buf);
    scope(exit) textbuf.free(); // necessary for cleanup

    // Put characters and strings into textbuf, verify they got there
    textbuf.put('a');
    textbuf.put('x');
    textbuf.put("abc");
    assert(textbuf.length == 5);
    assert(textbuf[1..3] == "xa");
    assert(textbuf[3] == 'b');

    // Can shrink it
    textbuf.length = 3;
    assert(textbuf[0..textbuf.length] == "axa");
    assert(textbuf[textbuf.length - 1] == 'a');
    assert(textbuf[1..3] == "xa");

    textbuf.put('z');
    assert(textbuf[] == "axaz");

    // Can shrink it to 0 size, and reuse same memory
    textbuf.length = 0;
}
It is invalid to access ScopeBuffer's contents when ScopeBuffer goes out of scope. Hence, copying the contents are necessary to keep them around:
import std.buffer.scopebuffer;
string cat(string s1, string s2)
{
    char[10] tmpbuf = void;
    auto textbuf = ScopeBuffer!char(tmpbuf);
    scope(exit) textbuf.free();
    textbuf.put(s1);
    textbuf.put(s2);
    textbuf.put("even more");
    return textbuf[].idup;
}
ScopeBuffer is intended for high performance usages in @system and @trusted code. It is designed to fit into two 64 bit registers, again for high performance use. If used incorrectly, memory leaks and corruption can result. Be sure to use scope(exit) textbuf.free(); for proper cleanup, and do not refer to a ScopeBuffer instance's contents after ScopeBuffer.free() has been called.

this(T[] buf);
Initialize with buf to use as scratch buffer space.

Parameters:
T[] buf Scratch buffer space, must have length that is even

Example:
ubyte[10] tmpbuf = void;
auto sbuf = ScopeBuffer!ubyte(tmpbuf);

void free();
Releases any memory used. This will invalidate any references returned by the [] operator. A destructor is not used, because that would make it not POD (Plain Old Data) and it could not be placed in registers.

void put(T c);
Append element c to the buffer. This member function makes ScopeBuffer an OutputRange.

void put(const(T)[] s);
Append array s to the buffer.

T[] opSlice(size_t lower, size_t upper);
T[] opSlice();
Retrieve a slice into the result.

Returns:
A slice into the temporary buffer that is only valid until the next put() or ScopeBuffer goes out of scope.

T opIndex(size_t i);
Returns:
the element at index i.

size_t length();
Returns:
the number of elements in the ScopeBuffer

void length(size_t i);
Used to shrink the length of the buffer, typically to 0 so the buffer can be reused. Cannot be used to extend the length of the buffer.

auto scopeBuffer(T)(T[] tmpbuf);
This is a slightly simpler way to create a ScopeBuffer instance that uses type deduction.

Parameters:
T[] tmpbuf the initial buffer to use

Returns:
an instance of ScopeBuffer

Example:
ubyte[10] tmpbuf = void;
auto sb = scopeBuffer(tmpbuf);
scope(exit) sp.free();