1 module nxt.sso_appender; 2 3 /** Small-Size-Optimized (SSO) `Appender`. 4 * 5 * See_Also: https://forum.dlang.org/post/ifspcvfkwsnvyrdfngpw@forum.dlang.org 6 */ 7 struct SSOAppender(T, size_t smallCapacity) 8 if (smallCapacity >= 1) 9 { 10 import std.array : Appender; 11 import nxt.container.static_array : StaticArray; 12 static if (!__traits(isPOD, T)) 13 import core.lifetime : move; 14 15 void assureOneMoreCapacity() @trusted 16 { 17 if (!_isLarge && 18 _small.full) 19 { 20 import std.algorithm.mutation : moveEmplaceAll; 21 22 T[smallCapacity] tmp = void; 23 moveEmplaceAll(_small[], tmp[0 .. _small.length]); 24 25 import core.lifetime : emplace; 26 emplace!Large(&_large); 27 28 _large.put(tmp[]); 29 _isLarge = 1; 30 } 31 } 32 33 void put(T x) @trusted 34 { 35 assureOneMoreCapacity(); 36 if (_isLarge) 37 { 38 static if (__traits(isPOD, T)) 39 _large.put(x); 40 else 41 _large.put(x.move); 42 } 43 else 44 { 45 static if (__traits(isPOD, T)) 46 _small.put(x); 47 else 48 _small.put(x.move); 49 } 50 } 51 52 inout(T)[] data() inout return scope @trusted 53 { 54 if (_isLarge) 55 return _large.data[]; 56 else 57 return _small[]; 58 } 59 60 private: 61 alias Small = StaticArray!(T, smallCapacity); 62 alias Large = Appender!(T[]); 63 union 64 { 65 Small _small; 66 Large _large; 67 } 68 bool _isLarge; // TODO: pack this into _small 69 } 70 71 @safe pure nothrow unittest 72 { 73 alias A = SSOAppender!(int, 2); 74 A a; 75 a.put(11); 76 a.put(12); 77 assert(a.data[] == [11, 12]); 78 a.put(13); 79 assert(a.data[] == [11, 12, 13]); 80 static if (hasPreviewDIP1000) 81 { 82 auto f() @safe pure { 83 A a; 84 return a.data; // errors with -dip1000 85 } 86 static assert(!__traits(compiles, { 87 auto f() @safe pure { 88 auto x = SmallAppender!(char)("alphas"); 89 auto y = x[]; 90 return y; // errors with -dip1000 91 } 92 })); 93 } 94 } 95 96 version(unittest) 97 { 98 import nxt.dip_traits : hasPreviewDIP1000; 99 }