digitalmars.D - Small-size-optimized Appender
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (47/47) Oct 16 2020 Would appreciated feedback on this small-size-optimized Appender
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (4/5) Oct 16 2020 Perhaps this could be integrated into
- Paul Backus (19/42) Oct 16 2020 This will call a @system postblit or copy constructor in @safe
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (5/6) Oct 16 2020 Should I use
- Paul Backus (4/10) Oct 16 2020 Just remove the @trusted annotation from the function and wrap
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (2/5) Oct 16 2020 Thanks. Will that be inlined by default or only in release mode?
- Paul Backus (3/8) Oct 16 2020 Immediately-called lambdas are always inlined, even by DMD in
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (6/8) Oct 16 2020 Nice. Thanks. I still believe
Would appreciated feedback on this small-size-optimized Appender /** Small-Size-Optimized (SSO) `Appender`. */ struct SSOAppender(T, size_t smallCapacity) if (smallCapacity >= 1) { import std.array : Appender; import fixed_array : FixedArray; void put(T x) trusted { if (_isLarge) _large.put(x); else if (_small.full) { import std.algorithm.mutation : moveEmplaceAll; T[smallCapacity] tmp = void; moveEmplaceAll(_small[], tmp[0 .. _small.length]); import core.lifetime : emplace; emplace!Large(&_large); _large.put(tmp[]); _large.put(x); _isLarge = 1; } else _small.put(x); } inout(T)[] data() inout return scope { if (_isLarge) return _large.data[]; else return _small[]; } private: alias Small = FixedArray!(T, smallCapacity); alias Large = Appender!(T[]); union { Small _small; Large _large; } bool _isLarge; } I can inline `FixedArray` into a static array if wanted. It's basically a static array with a length that provides a put API. Source: https://github.com/nordlow/phobos-next/blob/e914975613e9a5153313acf29b1b183326823ca3/src/nxt/sso_appender.d
Oct 16 2020
On Friday, 16 October 2020 at 19:06:33 UTC, Per Nordlöw wrote:Would appreciated feedback on this small-size-optimized AppenderPerhaps this could be integrated into Appender(A, size_t smallCapacity) that behaves like existing `Appender` when smallCapacity is 0.
Oct 16 2020
On Friday, 16 October 2020 at 19:06:33 UTC, Per Nordlöw wrote:Would appreciated feedback on this small-size-optimized Appender /** Small-Size-Optimized (SSO) `Appender`. */ struct SSOAppender(T, size_t smallCapacity) if (smallCapacity >= 1) { import std.array : Appender; import fixed_array : FixedArray; void put(T x) trusted { if (_isLarge) _large.put(x);This will call a system postblit or copy constructor in safe code. [...]union { Small _small; Large _large; } bool _isLarge; }If you're using a union, you need to define a copy constructor and a destructor, because the compiler will not automatically insert calls to these functions for your union members. You could also use a library like sumtype or taggedalgebraic that handles these details for you, which would be my recommended approach.I can inline `FixedArray` into a static array if wanted. It's basically a static array with a length that provides a put API. Source: https://github.com/nordlow/phobos-next/blob/e914975613e9a5153313acf29b1b183326823ca3/src/nxt/sso_appender.dFixedArray [1] suffers from the safety issue explained here: https://gist.github.com/pbackus/39b13e8a2c6aea0e090e4b1fe8046df5#example-short-string The short version is: because the compiler does not consider an integer to be an unsafe type, it will freely allow safe code to corrupt the _length variable, so you must include bounds-checking in all of your trusted code (that is, you must use _store[i] instead of _store.ptr[i]). [1] https://github.com/nordlow/phobos-next/blob/e914975613e9a5153313acf29b1b183326823ca3/src/nxt/fixed_array.d#L101
Oct 16 2020
On Friday, 16 October 2020 at 20:32:43 UTC, Paul Backus wrote:Should I use import core.lifetime : move; _large.put(x.move); instead?_large.put(x);
Oct 16 2020
On Friday, 16 October 2020 at 20:36:57 UTC, Per Nordlöw wrote:On Friday, 16 October 2020 at 20:32:43 UTC, Paul Backus wrote:Just remove the trusted annotation from the function and wrap the calls to system functions in trusted lambdas. Attribute inference will take care of the rest.Should I use import core.lifetime : move; _large.put(x.move); instead?_large.put(x);
Oct 16 2020
On Friday, 16 October 2020 at 20:45:24 UTC, Paul Backus wrote:Just remove the trusted annotation from the function and wrap the calls to system functions in trusted lambdas. Attribute inference will take care of the rest.Thanks. Will that be inlined by default or only in release mode?
Oct 16 2020
On Friday, 16 October 2020 at 20:52:48 UTC, Per Nordlöw wrote:On Friday, 16 October 2020 at 20:45:24 UTC, Paul Backus wrote:Immediately-called lambdas are always inlined, even by DMD in non-release mode.Just remove the trusted annotation from the function and wrap the calls to system functions in trusted lambdas. Attribute inference will take care of the rest.Thanks. Will that be inlined by default or only in release mode?
Oct 16 2020
On Friday, 16 October 2020 at 20:55:07 UTC, Paul Backus wrote:Immediately-called lambdas are always inlined, even by DMD in non-release mode.Nice. Thanks. I still believe trusted { ... } would be more appreciated, though. I always forget the syntax for inline lambdas and I've been using D since 2013. Has there been any objections against adding something similar?
Oct 16 2020