1 module ut.unique_array; 2 3 import ut; 4 import automem.unique_array; 5 6 mixin TestUtils; 7 8 @("default TestAllocator") 9 @system unittest { 10 defaultTest!TestAllocator; 11 } 12 13 14 @("default Mallocator") 15 @system unittest { 16 import stdx.allocator.mallocator: Mallocator; 17 defaultTest!Mallocator; 18 } 19 20 /// 21 @("@nogc") 22 @system @nogc unittest { 23 24 import stdx.allocator.mallocator: Mallocator; 25 26 auto arr = UniqueArray!(NoGcStruct, Mallocator)(2); 27 assert(arr.length == 2); 28 29 arr[0] = NoGcStruct(1); 30 arr[1] = NoGcStruct(3); 31 32 { 33 NoGcStruct[2] expected = [NoGcStruct(1), NoGcStruct(3)]; 34 assert(arr[] == expected[]); 35 } 36 37 auto arr2 = UniqueArray!(NoGcStruct, Mallocator)(1); 38 arr ~= arr2.unique; 39 40 { 41 NoGcStruct[3] expected = [NoGcStruct(1), NoGcStruct(3), NoGcStruct()]; 42 assert(arr[] == expected[]); 43 } 44 } 45 46 @("@nogc @safe") 47 @safe @nogc unittest { 48 auto allocator = SafeAllocator(); 49 auto arr = UniqueArray!(NoGcStruct, SafeAllocator)(SafeAllocator(), 6); 50 assert(arr.length == 6); 51 } 52 53 54 @("init TestAllocator") 55 @system unittest { 56 auto allocator = TestAllocator(); 57 auto arr = UniqueArray!(Struct, TestAllocator*)(&allocator, 2, Struct(7)); 58 arr[].shouldEqual([Struct(7), Struct(7)]); 59 } 60 61 @("init Mallocator") 62 @system unittest { 63 import stdx.allocator.mallocator: Mallocator; 64 alias allocator = Mallocator.instance; 65 auto arr = UniqueArray!(Struct, Mallocator)(2, Struct(7)); 66 arr[].shouldEqual([Struct(7), Struct(7)]); 67 } 68 69 70 @("range TestAllocator") 71 @system unittest { 72 auto allocator = TestAllocator(); 73 auto arr = UniqueArray!(Struct, TestAllocator*)(&allocator, [Struct(1), Struct(2)]); 74 arr[].shouldEqual([Struct(1), Struct(2)]); 75 } 76 77 @("range Mallocator") 78 @system unittest { 79 import stdx.allocator.mallocator: Mallocator; 80 auto arr = UniqueArray!(Struct, Mallocator)([Struct(1), Struct(2)]); 81 arr[].shouldEqual([Struct(1), Struct(2)]); 82 } 83 84 85 @("theAllocator") 86 @system unittest { 87 with(theTestAllocator) { 88 auto arr = UniqueArray!Struct(2); 89 arr[].shouldEqual([Struct(), Struct()]); 90 } 91 } 92 93 @("issue 1 array") 94 @system unittest { 95 import stdx.allocator.mallocator; 96 UniqueArray!(int, Mallocator) a; 97 a ~= [0, 1]; 98 } 99 100 @("issue 1 value") 101 @system unittest { 102 import stdx.allocator.mallocator; 103 UniqueArray!(int, Mallocator) a; 104 a ~= 7; 105 } 106 107 @("issue 1 UniqueArray") 108 @system unittest { 109 import stdx.allocator.mallocator; 110 UniqueArray!(int, Mallocator) a; 111 a ~= UniqueArray!(int, Mallocator)([1, 2, 3]); 112 } 113 114 @("dereference") 115 unittest { 116 import stdx.allocator.mallocator; 117 UniqueArray!(int, Mallocator) a; 118 a ~= [0, 1]; 119 (*a).shouldEqual([0, 1]); 120 } 121 122 @("reserve from nothing") 123 @system unittest { 124 auto allocator = TestAllocator(); 125 auto a = UniqueArray!(int, TestAllocator*)(&allocator); 126 a.reserve(10); //allocates here 127 a ~= [1, 2, 3]; // should not allocate 128 a ~= [4, 5, 6, 7, 8, 9]; //should not allocate 129 a[].shouldEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); 130 allocator.numAllocations.shouldEqual(1); 131 } 132 133 @("reserve from existing expand") 134 @system unittest { 135 auto allocator = TestAllocator(); 136 auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2]); //allocates here 137 a.reserve(10); //allocates here 138 a ~= [3, 4]; // should not allocate 139 a ~= [5, 6, 7, 8, 9]; //should not allocate 140 a[].shouldEqual([1, 2, 3, 4, 5, 6, 7, 8, 9]); 141 allocator.numAllocations.shouldEqual(2); 142 } 143 144 @("reserve from existing reduce") 145 @system unittest { 146 auto allocator = TestAllocator(); 147 auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]); //allocates here 148 a.reserve(2); // should not allocate, changes length to 2 149 a ~= [5, 6]; // should not allocate 150 a[].shouldEqual([1, 2, 5, 6]); 151 allocator.numAllocations.shouldEqual(1); 152 } 153 154 @("Append 2 arrays") 155 @system unittest { 156 auto allocator = TestAllocator(); 157 auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3]) ~ 158 UniqueArray!(int, TestAllocator*)(&allocator, [4, 5]); 159 a[].shouldEqual([1, 2, 3, 4, 5]); 160 } 161 162 @("ptr") 163 @system unittest { 164 auto allocator = TestAllocator(); 165 auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]); 166 auto ptr = a.ptr; 167 ++ptr; 168 (*ptr).shouldEqual(2); 169 } 170 171 @("dup TestAllocator") 172 @system unittest { 173 auto allocator = TestAllocator(); 174 auto a = UniqueArray!(int, TestAllocator*)(&allocator, [1, 2, 3, 4, 5]); 175 auto b = a.dup; 176 allocator.numAllocations.shouldEqual(2); 177 b[].shouldEqual([1, 2, 3, 4, 5]); 178 } 179 180 @("dup Mallocator") 181 @system unittest { 182 import stdx.allocator.mallocator: Mallocator; 183 auto a = UniqueArray!(int, Mallocator)([1, 2, 3, 4, 5]); 184 auto b = a.dup; 185 b[].shouldEqual([1, 2, 3, 4, 5]); 186 } 187 188 @("dup TestAllocator indirections") 189 @system unittest { 190 auto allocator = TestAllocator(); 191 struct String { string s; } 192 auto a = UniqueArray!(String, TestAllocator*)(&allocator, [String("foo"), String("bar")]); 193 auto b = a.dup; 194 a[0] = String("quux"); 195 a[1] = String("toto"); 196 allocator.numAllocations.shouldEqual(2); 197 a[].shouldEqual([String("quux"), String("toto")]); 198 b[].shouldEqual([String("foo"), String("bar")]); 199 } 200 201 @("Set length to the same length") 202 unittest { 203 auto allocator = TestAllocator(); 204 auto a = UniqueArray!(Struct, TestAllocator*)(&allocator, [Struct(2), Struct(3)]); 205 a.length = 2; 206 } 207 208 209 void defaultTest(T)() { 210 import std.algorithm: move; 211 212 mixin AllocatorAlias!T; 213 214 auto ptr = makeUniqueArray!(Struct, Allocator)(allocator, 3); 215 ptr.length.shouldEqual(3); 216 217 ptr[2].twice.shouldEqual(0); 218 ptr[2] = Struct(5); 219 ptr[2].twice.shouldEqual(10); 220 221 ptr[1..$].shouldEqual([Struct(), Struct(5)]); 222 223 typeof(ptr) ptr2 = ptr.move; 224 225 ptr.length.shouldEqual(0); 226 (cast(bool)ptr).shouldBeFalse; 227 ptr2.length.shouldEqual(3); 228 (cast(bool)ptr2).shouldBeTrue; 229 230 // not copyable 231 static assert(!__traits(compiles, ptr2 = ptr1)); 232 233 auto ptr3 = ptr2.unique; 234 ptr3.length.shouldEqual(3); 235 ptr3[].shouldEqual([Struct(), Struct(), Struct(5)]); 236 (*ptr3).shouldEqual([Struct(), Struct(), Struct(5)]); 237 238 ptr3 ~= Struct(10); 239 ptr3[].shouldEqual([Struct(), Struct(), Struct(5), Struct(10)]); 240 241 ptr3 ~= [Struct(11), Struct(12)]; 242 ptr3[].shouldEqual([Struct(), Struct(), Struct(5), Struct(10), Struct(11), Struct(12)]); 243 244 ptr3.length = 3; 245 ptr3[].shouldEqual([Struct(), Struct(), Struct(5)]); 246 247 ptr3.length = 4; 248 ptr3[].shouldEqual([Struct(), Struct(), Struct(5), Struct()]); 249 250 ptr3.length = 1; 251 252 ptr3 ~= makeUniqueArray!(Struct, Allocator)(allocator, 1); 253 254 ptr3[].shouldEqual([Struct(), Struct()]); 255 256 auto ptr4 = makeUniqueArray!(Struct, Allocator)(allocator, 1); 257 258 ptr3 ~= ptr4.unique; 259 ptr3[].shouldEqual([Struct(), Struct(), Struct()]); 260 261 ptr3 = [Struct(7), Struct(9)]; 262 ptr3[].shouldEqual([Struct(7), Struct(9)]); 263 } 264 265 mixin template AllocatorAlias(T) { 266 import std.traits: hasMember; 267 268 enum isGlobal = hasMember!(T, "instance"); 269 270 static if(isGlobal) { 271 alias allocator = T.instance; 272 alias Allocator = T; 273 } else { 274 auto allocator = T(); 275 alias Allocator = T*; 276 } 277 } 278 279 280 auto makeUniqueArray(T, A1, A2, Args...)(ref A2 allocator, Args args) { 281 282 import std.traits: isPointer, hasMember; 283 284 enum isGlobal = hasMember!(A1, "instance"); 285 286 static if(isGlobal) 287 return UniqueArray!(T, A1)(args); 288 else static if(isPointer!A1) 289 return UniqueArray!(T, A1)(&allocator, args); 290 else 291 return UniqueArray!(T, A1)(allocator, args); 292 }