From 5f27ab26c75ef93fee6bb297eaec0dd81b1292bd Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Fri, 25 Jul 2014 16:51:56 +0200 Subject: [PATCH] A gutted, @nogc version of Appender. --- source/dyaml/nogcutil.d | 124 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/source/dyaml/nogcutil.d b/source/dyaml/nogcutil.d index a6d8263..04e3376 100644 --- a/source/dyaml/nogcutil.d +++ b/source/dyaml/nogcutil.d @@ -63,3 +63,127 @@ body assert(!atStart, "Nothing to parse in parse()"); return v; } +/// Convenience function that returns an $(D AppenderNoGCFixed!A) using with $(D array) +/// for storage. +AppenderNoGCFixed!(E[]) appenderNoGC(A : E[], E)(A array) +{ + return AppenderNoGCFixed!(E[])(array); +} + +/// A gutted, NoGC version of std.array.appender. +/// +/// Works on a fixed-size buffer. +struct AppenderNoGCFixed(A : T[], T) +{ + import std.array; + import std.traits; + + private struct Data + { + size_t capacity; + Unqual!T[] arr; + bool canExtend = false; + } + + private Data _data; + + @nogc: + + /// Construct an appender that will work with given buffer. + /// + /// Data written to the appender will overwrite the buffer from the start. + this(T[] arr) @trusted pure nothrow + { + // initialize to a given array. + _data.arr = cast(Unqual!T[])arr[0 .. 0]; //trusted + + if (__ctfe) + return; + + _data.capacity = arr.length; + } + + /** + * Returns the capacity of the array (the maximum number of elements the + * managed array can accommodate before triggering a reallocation). If any + * appending will reallocate, $(D capacity) returns $(D 0). + */ + @property size_t capacity() const @safe pure nothrow + { + return _data.capacity; + } + + /** + * Returns the managed array. + */ + @property inout(T)[] data() inout @trusted pure nothrow + { + /* @trusted operation: + * casting Unqual!T[] to inout(T)[] + */ + return cast(typeof(return))(_data.arr); + } + + // ensure we can add nelems elements, resizing as necessary + private void ensureAddable(size_t nelems) @safe pure nothrow + { + assert(_data.capacity >= _data.arr.length + nelems, + "AppenderFixed ran out of space"); + } + + /** + * Appends one item to the managed array. + */ + void put(U)(U item) if (is(Unqual!U == T)) + { + ensureAddable(1); + immutable len = _data.arr.length; + + auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. len + 1];} + auto bigData = bigDataFun(); + + emplaceRef!T(bigData[len], item); + + //We do this at the end, in case of exceptions + _data.arr = bigData; + } + + void put(U)(U[] items) if (is(Unqual!U == T)) + { + // make sure we have enough space, then add the items + ensureAddable(items.length); + immutable len = _data.arr.length; + immutable newlen = len + items.length; + + auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. newlen];} + auto bigData = bigDataFun(); + + alias UT = Unqual!T; + + bigData[len .. newlen] = items[]; + + //We do this at the end, in case of exceptions + _data.arr = bigData; + } + + // only allow overwriting data on non-immutable and non-const data + static if (isMutable!T) + { + /** + * Clears the managed array. This allows the elements of the array to be reused + * for appending. + * + * Note that clear is disabled for immutable or const element types, due to the + * possibility that $(D AppenderNoGCFixed) might overwrite immutable data. + */ + void clear() @safe pure nothrow + { + _data.arr = ()@trusted{ return _data.arr.ptr[0 .. 0]; }(); + } + } + else + { + /// Clear is not available for const/immutable data. + @disable void clear(); + } +}