1 module ut.ref_counted; 2 3 import ut; 4 import automem.ref_counted; 5 6 mixin TestUtils; 7 8 /// 9 @("struct test allocator no copies") 10 @system unittest { 11 auto allocator = TestAllocator(); 12 { 13 auto ptr = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 14 Struct.numStructs.shouldEqual(1); 15 } 16 Struct.numStructs.shouldEqual(0); 17 } 18 19 @("struct test allocator one lvalue assignment") 20 @system unittest { 21 auto allocator = TestAllocator(); 22 { 23 auto ptr1 = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 24 Struct.numStructs.shouldEqual(1); 25 26 RefCounted!(Struct, TestAllocator*) ptr2; 27 ptr2 = ptr1; 28 Struct.numStructs.shouldEqual(1); 29 } 30 Struct.numStructs.shouldEqual(0); 31 } 32 33 @("struct test allocator one lvalue assignment from T.init") 34 @system unittest { 35 36 auto allocator = TestAllocator(); 37 38 { 39 RefCounted!(Struct, TestAllocator*) ptr1; 40 Struct.numStructs.shouldEqual(0); 41 42 auto ptr2 = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 43 Struct.numStructs.shouldEqual(1); 44 45 ptr2 = ptr1; 46 Struct.numStructs.shouldEqual(0); 47 } 48 49 Struct.numStructs.shouldEqual(0); 50 } 51 52 @("struct test allocator one lvalue assignment both non-null") 53 @system unittest { 54 55 auto allocator = TestAllocator(); 56 57 { 58 auto ptr1 = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 59 Struct.numStructs.shouldEqual(1); 60 61 auto ptr2 = RefCounted!(Struct, TestAllocator*)(&allocator, 7); 62 Struct.numStructs.shouldEqual(2); 63 64 ptr2 = ptr1; 65 Struct.numStructs.shouldEqual(1); 66 } 67 68 Struct.numStructs.shouldEqual(0); 69 } 70 71 72 73 @("struct test allocator one rvalue assignment test allocator") 74 @system unittest { 75 auto allocator = TestAllocator(); 76 { 77 RefCounted!(Struct, TestAllocator*) ptr; 78 ptr = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 79 Struct.numStructs.shouldEqual(1); 80 } 81 Struct.numStructs.shouldEqual(0); 82 } 83 84 @("struct test allocator one rvalue assignment mallocator") 85 @system unittest { 86 import stdx.allocator.mallocator: Mallocator; 87 { 88 RefCounted!(Struct, Mallocator) ptr; 89 ptr = RefCounted!(Struct, Mallocator)(5); 90 Struct.numStructs.shouldEqual(1); 91 } 92 Struct.numStructs.shouldEqual(0); 93 } 94 95 96 @("struct test allocator one lvalue copy constructor") 97 @system unittest { 98 auto allocator = TestAllocator(); 99 { 100 auto ptr1 = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 101 Struct.numStructs.shouldEqual(1); 102 auto ptr2 = ptr1; 103 Struct.numStructs.shouldEqual(1); 104 105 ptr1.i.shouldEqual(5); 106 ptr2.i.shouldEqual(5); 107 } 108 Struct.numStructs.shouldEqual(0); 109 } 110 111 @("struct test allocator one rvalue copy constructor") 112 @system unittest { 113 auto allocator = TestAllocator(); 114 { 115 auto ptr = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 116 Struct.numStructs.shouldEqual(1); 117 } 118 Struct.numStructs.shouldEqual(0); 119 } 120 121 @("many copies made") 122 @system unittest { 123 auto allocator = TestAllocator(); 124 125 // helper function for intrusive testing, in case the implementation 126 // ever changes 127 size_t refCount(T)(ref T ptr) { 128 return ptr._impl._count; 129 } 130 131 { 132 auto ptr1 = RefCounted!(Struct, TestAllocator*)(&allocator, 5); 133 Struct.numStructs.shouldEqual(1); 134 135 auto ptr2 = ptr1; 136 Struct.numStructs.shouldEqual(1); 137 138 { 139 auto ptr3 = ptr2; 140 Struct.numStructs.shouldEqual(1); 141 142 refCount(ptr1).shouldEqual(3); 143 refCount(ptr2).shouldEqual(3); 144 refCount(ptr3).shouldEqual(3); 145 } 146 147 Struct.numStructs.shouldEqual(1); 148 refCount(ptr1).shouldEqual(2); 149 refCount(ptr2).shouldEqual(2); 150 151 auto produce() { 152 return RefCounted!(Struct, TestAllocator*)(&allocator, 3); 153 } 154 155 ptr1 = produce; 156 Struct.numStructs.shouldEqual(2); 157 refCount(ptr1).shouldEqual(1); 158 refCount(ptr2).shouldEqual(1); 159 160 ptr1.twice.shouldEqual(6); 161 ptr2.twice.shouldEqual(10); 162 } 163 164 Struct.numStructs.shouldEqual(0); 165 } 166 167 @("default allocator") 168 @system unittest { 169 { 170 auto ptr = RefCounted!Struct(5); 171 Struct.numStructs.shouldEqual(1); 172 } 173 Struct.numStructs.shouldEqual(0); 174 } 175 176 static if (__VERSION__ >= 2079) 177 @("default allocator (shared)") 178 @system unittest { 179 { 180 auto ptr = RefCounted!(shared SharedStruct)(5); 181 SharedStruct.numStructs.shouldEqual(1); 182 } 183 SharedStruct.numStructs.shouldEqual(0); 184 } 185 186 @("deref") 187 @system unittest { 188 auto allocator = TestAllocator(); 189 auto rc1 = RefCounted!(int, TestAllocator*)(&allocator, 5); 190 191 (*rc1).shouldEqual(5); 192 auto rc2 = rc1; 193 *rc2 = 42; 194 (*rc1).shouldEqual(42); 195 } 196 197 @("swap") 198 @system unittest { 199 import std.algorithm: swap; 200 RefCounted!(int, TestAllocator*) rc1, rc2; 201 swap(rc1, rc2); 202 } 203 204 @("phobos bug 6606") 205 @system unittest { 206 207 union U { 208 size_t i; 209 void* p; 210 } 211 212 struct S { 213 U u; 214 } 215 216 alias SRC = RefCounted!(S, TestAllocator*); 217 } 218 219 @("phobos bug 6436") 220 @system unittest 221 { 222 static struct S { 223 this(ref int val, string file = __FILE__, size_t line = __LINE__) { 224 val.shouldEqual(3, file, line); 225 ++val; 226 } 227 } 228 229 auto allocator = TestAllocator(); 230 int val = 3; 231 auto s = RefCounted!(S, TestAllocator*)(&allocator, val); 232 val.shouldEqual(4); 233 } 234 235 @("assign from T") 236 @system unittest { 237 import stdx.allocator.mallocator: Mallocator; 238 239 { 240 auto a = RefCounted!(Struct, Mallocator)(3); 241 Struct.numStructs.shouldEqual(1); 242 243 *a = Struct(5); 244 Struct.numStructs.shouldEqual(1); 245 (*a).shouldEqual(Struct(5)); 246 247 RefCounted!(Struct, Mallocator) b; 248 b = a; 249 (*b).shouldEqual(Struct(5)); 250 Struct.numStructs.shouldEqual(1); 251 } 252 253 Struct.numStructs.shouldEqual(0); 254 } 255 256 @("assign self") 257 @system unittest { 258 auto allocator = TestAllocator(); 259 { 260 auto a = RefCounted!(Struct, TestAllocator*)(&allocator, 1); 261 a = a; 262 Struct.numStructs.shouldEqual(1); 263 } 264 Struct.numStructs.shouldEqual(0); 265 } 266 267 static if (__VERSION__ >= 2079) 268 @("SharedStruct") 269 @system unittest { 270 auto allocator = TestAllocator(); 271 { 272 auto ptr = RefCounted!(shared SharedStruct, TestAllocator*)(&allocator, 5); 273 SharedStruct.numStructs.shouldEqual(1); 274 } 275 SharedStruct.numStructs.shouldEqual(0); 276 } 277 278 @("@nogc @safe") 279 @safe @nogc unittest { 280 281 auto allocator = SafeAllocator(); 282 283 { 284 const ptr = RefCounted!(NoGcStruct, SafeAllocator)(SafeAllocator(), 6); 285 assert(ptr.i == 6); 286 assert(NoGcStruct.numStructs == 1); 287 } 288 289 assert(NoGcStruct.numStructs == 0); 290 } 291 292 293 @("const object") 294 @system unittest { 295 auto allocator = TestAllocator(); 296 auto ptr1 = RefCounted!(const Struct, TestAllocator*)(&allocator, 5); 297 } 298 299 300 @("theAllocator") 301 @system unittest { 302 303 with(theTestAllocator) { 304 auto ptr = RefCounted!Struct(42); 305 (*ptr).shouldEqual(Struct(42)); 306 Struct.numStructs.shouldEqual(1); 307 } 308 309 Struct.numStructs.shouldEqual(0); 310 } 311 312 static if (__VERSION__ >= 2079) { 313 314 @("threads Mallocator") 315 @system unittest { 316 import stdx.allocator.mallocator: Mallocator; 317 static assert(__traits(compiles, sendRefCounted!Mallocator(7))); 318 } 319 320 @("threads SafeAllocator by value") 321 @system unittest { 322 // can't even use TestAllocator because it has indirections 323 // can't pass by pointer since it's an indirection 324 auto allocator = SafeAllocator(); 325 static assert(__traits(compiles, sendRefCounted!(SafeAllocator)(allocator, 7))); 326 } 327 328 @("threads SafeAllocator by shared pointer") 329 @system unittest { 330 // can't even use TestAllocator because it has indirections 331 // can't only pass by pointer if shared 332 auto allocator = shared SafeAllocator(); 333 static assert(__traits(compiles, sendRefCounted!(shared SafeAllocator*)(&allocator, 7))); 334 } 335 } 336 337 @("Construct RefCounted from Unique") 338 @system unittest { 339 import automem.unique: Unique; 340 auto allocator = TestAllocator(); 341 auto ptr = refCounted(Unique!(int, TestAllocator*)(&allocator, 42)); 342 (*ptr).shouldEqual(42); 343 } 344 345 @("RefCounted with class") 346 @system unittest { 347 auto allocator = TestAllocator(); 348 { 349 writelnUt("Creating ptr"); 350 auto ptr = RefCounted!(Class, TestAllocator*)(&allocator, 33); 351 (*ptr).i.shouldEqual(33); 352 Class.numClasses.shouldEqual(1); 353 } 354 Class.numClasses.shouldEqual(0); 355 } 356 357 @("@nogc class destructor") 358 @nogc unittest { 359 360 import automem: Unique; 361 362 auto allocator = SafeAllocator(); 363 364 { 365 const ptr = Unique!(NoGcClass, SafeAllocator)(SafeAllocator(), 6); 366 // shouldEqual isn't @nogc 367 assert(ptr.i == 6); 368 assert(NoGcClass.numClasses == 1); 369 } 370 371 assert(NoGcClass.numClasses == 0); 372 } 373 374 @("RefCounted opSlice and opIndex") 375 @system unittest { 376 import std.mmfile: MmFile; 377 auto file = RefCounted!MmFile(null, MmFile.Mode.readWriteNew, 120, null); 378 // The type of file[0] should be ubyte, not Impl. 379 static assert(is(typeof(file[0]) == typeof(MmFile.init[0]))); 380 // opSlice should result in void[] not Impl[]. 381 static assert(is(typeof(file[0 .. size_t.max]) == typeof(MmFile.init[0 .. size_t.max]))); 382 ubyte[] data = cast(ubyte[]) file[0 .. cast(size_t) file.length]; 383 immutable ubyte b = file[1]; 384 file[1] = cast(ubyte) (b + 1); 385 assert(data[1] == cast(ubyte) (b + 1)); 386 } 387 388 @("Construct RefCounted using global allocator for struct with zero-args ctor") 389 @system unittest { 390 struct S { 391 private ulong zeroArgsCtorTest = 3; 392 } 393 auto s = RefCounted!S.construct(); 394 static assert(is(typeof(s) == RefCounted!S)); 395 assert(s._impl !is null); 396 assert(s.zeroArgsCtorTest == 3); 397 } 398 399 400 401 void sendRefCounted(Allocator, Args...)(Args args) { 402 import std.concurrency: spawn, send; 403 404 auto tid = spawn(&threadFunc); 405 auto ptr = RefCounted!(shared SharedStruct, Allocator)(args); 406 407 tid.send(ptr); 408 } 409 410 void threadFunc() { 411 412 } 413 414 @("shared struct with indirection") 415 @system unittest { 416 auto s = RefCounted!(shared SharedStructWithIndirection)("foobar"); 417 }