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 pure nothrow @safe unittest { 72 alias A = SSOAppender!(int, 2); 73 A a; 74 a.put(11); 75 a.put(12); 76 assert(a.data[] == [11, 12]); 77 a.put(13); 78 assert(a.data[] == [11, 12, 13]); 79 static if (hasPreviewDIP1000) 80 { 81 auto f() @safe pure { 82 A a; 83 return a.data; // errors with -dip1000 84 } 85 static assert(!__traits(compiles, { 86 auto f() @safe pure { 87 auto x = SmallAppender!(char)("alphas"); 88 auto y = x[]; 89 return y; // errors with -dip1000 90 } 91 })); 92 } 93 } 94 95 version (unittest) 96 { 97 import nxt.dip_traits : hasPreviewDIP1000; 98 }