1 /** 2 This package contains methods to handle the proprietary binary data 3 container for `PileUp`s. 4 5 Copyright: © 2018 Arne Ludwig <arne.ludwig@posteo.de> 6 License: Subject to the terms of the MIT license, as written in the 7 included LICENSE file. 8 Authors: Arne Ludwig <arne.ludwig@posteo.de> 9 */ 10 module dentist.common.binio.pileupdb; 11 12 import core.exception : AssertError; 13 import dentist.common.alignments : 14 AlignmentChain, 15 AlignmentLocationSeed, 16 coord_t, 17 diff_t, 18 id_t, 19 PileUp, 20 ReadAlignment, 21 SeededAlignment, 22 trace_point_t; 23 import dentist.common.binio._base : 24 ArrayStorage, 25 DbIndex, 26 lockIfPossible, 27 readRecord, 28 readRecordAt, 29 readRecords; 30 import std.array : minimallyInitializedArray; 31 import std.conv : to; 32 import std.exception : assertThrown, enforce, ErrnoException; 33 import std.format : format; 34 import std.typecons : tuple, Tuple; 35 import std.stdio : File; 36 37 version (unittest) import dentist.common.binio._testdata : 38 getPileUpsTestData, 39 numLocalAlignments, 40 numPileUps, 41 numReadAlignments, 42 numSeededAlignments, 43 numTracePoints; 44 45 class PileUpDbException : Exception 46 { 47 pure nothrow @nogc @safe this(string msg, string file = __FILE__, 48 size_t line = __LINE__, Throwable nextInChain = null) 49 { 50 super(msg, file, line, nextInChain); 51 } 52 } 53 54 struct PileUpDb 55 { 56 private alias LocalAlignment = AlignmentChain.LocalAlignment; 57 private alias TracePoint = LocalAlignment.TracePoint; 58 private alias DbSlices = Tuple!( 59 ArrayStorage!(StorageType!PileUp), "pileUps", 60 ArrayStorage!(StorageType!ReadAlignment), "readAlignments", 61 ArrayStorage!(StorageType!SeededAlignment), "seededAlignments", 62 ArrayStorage!(StorageType!LocalAlignment), "localAlignments", 63 ArrayStorage!(StorageType!TracePoint), "tracePoints", 64 ); 65 66 private File pileUpDb; 67 private PileUpDbIndex dbIndex; 68 private DbSlices dbSlices; 69 70 @property auto pileUps() const pure nothrow 71 { 72 return dbIndex.pileUps; 73 } 74 @property auto readAlignments() const pure nothrow 75 { 76 return dbIndex.readAlignments; 77 } 78 @property auto seededAlignments() const pure nothrow 79 { 80 return dbIndex.seededAlignments; 81 } 82 @property auto localAlignments() const pure nothrow 83 { 84 return dbIndex.localAlignments; 85 } 86 @property auto tracePoints() const pure nothrow 87 { 88 return dbIndex.tracePoints; 89 } 90 91 static PileUpDb parse(in string dbFile) 92 { 93 auto pileUpDb = File(dbFile, "rb"); 94 lockIfPossible(pileUpDb); 95 96 auto db = PileUpDb(pileUpDb); 97 db.ensureDbIndex(); 98 99 return db; 100 } 101 102 void releaseDb() 103 { 104 pileUpDb.close(); 105 } 106 107 PileUp[] opIndex() 108 { 109 ensureDbIndex(); 110 111 return readSlice(0, length); 112 } 113 114 PileUp opIndex(size_t i) 115 { 116 ensureDbIndex(); 117 enforce!PileUpDbException( 118 i < length, 119 format!"cannot read block %d in `%s`: out of bounds [0, %d)"( 120 i, pileUpDb.name, length) 121 ); 122 123 return readSlice(i, i + 1)[0]; 124 } 125 126 PileUp[] opIndex(size_t[2] slice) 127 { 128 auto from = slice[0]; 129 auto to = slice[1]; 130 ensureDbIndex(); 131 enforce!PileUpDbException( 132 from <= to && to <= length, 133 format!"cannot read blocks %d-%d in `%s`: out of bounds [0, %d]"( 134 from, to, pileUpDb.name, length) 135 ); 136 137 return readSlice(from, to); 138 } 139 140 size_t[2] opSlice(size_t dim)(size_t from, size_t to) 141 if (dim == 0) 142 { 143 assert(from <= to, "invalid slice"); 144 145 return [from, to]; 146 } 147 148 @property size_t length() 149 { 150 ensureDbIndex(); 151 152 return dbIndex.pileUps.length; 153 } 154 155 alias opDollar = length; 156 157 private void ensureDbIndex() 158 { 159 if (dbIndex != dbIndex.init) 160 return; 161 162 dbIndex = pileUpDb.readRecord!PileUpDbIndex(); 163 } 164 165 private PileUp[] readSlice(size_t from, size_t to) 166 { 167 assert(from <= to && to <= length); 168 169 if (from == to) 170 return []; 171 172 // Step 1: determine memory requirements and DB slices 173 dbSlices = getDbSlices(from, to); 174 175 // Step 2: allocate minimally initialized memory for all blocks 176 auto pileUps = minimallyInitializedArray!(PileUp[])(dbSlices.pileUps.length); 177 auto readAlignments = minimallyInitializedArray!(ReadAlignment[])(dbSlices.readAlignments.length); 178 auto seededAlignments = minimallyInitializedArray!(SeededAlignment[])(dbSlices.seededAlignments.length); 179 auto localAlignments = minimallyInitializedArray!(LocalAlignment[])(dbSlices.localAlignments.length); 180 auto tracePoints = minimallyInitializedArray!(TracePoint[])(dbSlices.tracePoints.length); 181 182 // Step 3: parse each record for each block assigning already 183 // allocated array slices to the array fields 184 parse(pileUps, readAlignments); 185 parse(seededAlignments, localAlignments); 186 parse(readAlignments, seededAlignments); 187 parse(localAlignments, tracePoints); 188 parse(tracePoints); 189 190 return pileUps; 191 } 192 193 private DbSlices getDbSlices(size_t from, size_t to) 194 { 195 auto pileUps = dbIndex.pileUps[from .. to]; 196 auto firstPileUp = pileUpDb.readRecordAt!(StorageType!PileUp)(pileUps[0]); 197 auto lastPileUp = pileUpDb.readRecordAt!(StorageType!PileUp)(pileUps[$ - 1]); 198 199 auto readAlignments = ArrayStorage!(StorageType!ReadAlignment).fromPtrs( 200 firstPileUp[0], 201 lastPileUp[$], 202 ); 203 auto firstReadAlignment = pileUpDb.readRecordAt!(StorageType!ReadAlignment)(readAlignments[0]); 204 auto lastReadAlignment = pileUpDb.readRecordAt!(StorageType!ReadAlignment)(readAlignments[$ - 1]); 205 206 auto seededAlignments = ArrayStorage!(StorageType!SeededAlignment).fromPtrs( 207 firstReadAlignment[0], 208 lastReadAlignment[$], 209 ); 210 auto firstSeededAlignment = pileUpDb.readRecordAt!(StorageType!SeededAlignment)(seededAlignments[0]); 211 auto lastSeededAlignment = pileUpDb.readRecordAt!(StorageType!SeededAlignment)(seededAlignments[$ - 1]); 212 213 auto localAlignments = ArrayStorage!(StorageType!LocalAlignment).fromPtrs( 214 firstSeededAlignment.localAlignments[0], 215 lastSeededAlignment.localAlignments[$], 216 ); 217 auto firstLocalAlignment = pileUpDb.readRecordAt!(StorageType!LocalAlignment)(localAlignments[0]); 218 auto lastLocalAlignment = pileUpDb.readRecordAt!(StorageType!LocalAlignment)(localAlignments[$ - 1]); 219 220 auto tracePoints = ArrayStorage!(StorageType!TracePoint).fromPtrs( 221 firstLocalAlignment.tracePoints[0], 222 lastLocalAlignment.tracePoints[$], 223 ); 224 225 return DbSlices( 226 pileUps, 227 readAlignments, 228 seededAlignments, 229 localAlignments, 230 tracePoints, 231 ); 232 } 233 234 private void parse(ref PileUp[] pileUps, ReadAlignment[] readAlignments) 235 { 236 static assert(PileUp.sizeof == StorageType!PileUp.sizeof); 237 pileUpDb.seek(dbSlices.pileUps.ptr); 238 pileUps = pileUpDb.readRecords(pileUps); 239 240 size_t[2] pileUpSlice; 241 foreach (ref pileUp; pileUps) 242 { 243 auto pileUpStorage = *cast(StorageType!PileUp*) &pileUp; 244 pileUpSlice[0] = pileUpSlice[1]; 245 pileUpSlice[1] += pileUpStorage.length; 246 247 pileUp = readAlignments[pileUpSlice[0] .. pileUpSlice[1]]; 248 } 249 } 250 251 private void parse( 252 ref SeededAlignment[] seededAlignments, 253 AlignmentChain.LocalAlignment[] localAlignments 254 ) 255 { 256 // Parse `SeededAlignment`s 257 alias Contig = AlignmentChain.Contig; 258 pileUpDb.seek(dbSlices.seededAlignments.ptr); 259 260 size_t[2] seededAlignmentsSlice; 261 foreach (ref seededAlignment; seededAlignments) 262 { 263 auto seededAlignmentStorage = pileUpDb.readRecord!(StorageType!SeededAlignment); 264 265 seededAlignmentsSlice[0] = seededAlignmentsSlice[1]; 266 seededAlignmentsSlice[1] += seededAlignmentStorage.localAlignments.length; 267 268 seededAlignment = SeededAlignment( 269 AlignmentChain( 270 seededAlignmentStorage.id, 271 Contig( 272 seededAlignmentStorage.contigAId, 273 seededAlignmentStorage.contigALength, 274 ), 275 Contig( 276 seededAlignmentStorage.contigBId, 277 seededAlignmentStorage.contigBLength, 278 ), 279 seededAlignmentStorage.flags, 280 localAlignments[seededAlignmentsSlice[0] .. seededAlignmentsSlice[1]], 281 seededAlignmentStorage.tracePointDistance, 282 ), 283 seededAlignmentStorage.seed, 284 ); 285 } 286 } 287 288 private void parse(ref ReadAlignment[] readAlignments, SeededAlignment[] seededAlignments) 289 { 290 pileUpDb.seek(dbSlices.readAlignments.ptr); 291 292 size_t[2] readAlignmentsSlice; 293 foreach (ref readAlignment; readAlignments) 294 { 295 auto readAlignmentStorage = pileUpDb.readRecord!(StorageType!ReadAlignment); 296 297 readAlignmentsSlice[0] = readAlignmentsSlice[1]; 298 readAlignmentsSlice[1] += readAlignmentStorage.length; 299 300 readAlignment = ReadAlignment( 301 seededAlignments[readAlignmentsSlice[0] .. readAlignmentsSlice[1]] 302 ); 303 } 304 } 305 306 private void parse( 307 ref AlignmentChain.LocalAlignment[] localAlignments, 308 AlignmentChain.LocalAlignment.TracePoint[] tracePoints 309 ) 310 { 311 alias LocalAlignment = AlignmentChain.LocalAlignment; 312 alias Locus = LocalAlignment.Locus; 313 pileUpDb.seek(dbSlices.localAlignments.ptr); 314 315 size_t[2] localAlignmentsSlice; 316 foreach (ref localAlignment; localAlignments) 317 { 318 auto localAlignmentStorage = pileUpDb.readRecord!(StorageType!LocalAlignment); 319 320 localAlignmentsSlice[0] = localAlignmentsSlice[1]; 321 localAlignmentsSlice[1] += localAlignmentStorage.tracePoints.length; 322 323 localAlignment = LocalAlignment( 324 Locus( 325 localAlignmentStorage.contigABegin, 326 localAlignmentStorage.contigAEnd, 327 ), 328 Locus( 329 localAlignmentStorage.contigBBegin, 330 localAlignmentStorage.contigBEnd, 331 ), 332 localAlignmentStorage.numDiffs, 333 tracePoints[localAlignmentsSlice[0] .. localAlignmentsSlice[1]], 334 ); 335 } 336 } 337 338 private void parse(ref AlignmentChain.LocalAlignment.TracePoint[] tracePoints) 339 { 340 alias LocalAlignment = AlignmentChain.LocalAlignment; 341 alias TracePoint = LocalAlignment.TracePoint; 342 343 static assert(TracePoint.sizeof == StorageType!TracePoint.sizeof); 344 pileUpDb.seek(dbSlices.tracePoints.ptr); 345 tracePoints = pileUpDb.readRecords(tracePoints); 346 } 347 } 348 349 void writePileUpsDb(in PileUp[] pileUps, in string dbFile) 350 { 351 auto pileUpDb = File(dbFile, "wb"); 352 lockIfPossible(pileUpDb); 353 354 writePileUpsDb(pileUps, pileUpDb); 355 } 356 357 void writePileUpsDb(in PileUp[] pileUps, File pileUpDb) 358 { 359 alias LocalAlignment = AlignmentChain.LocalAlignment; 360 alias TracePoint = LocalAlignment.TracePoint; 361 362 PileUpDbIndex dbIndex = buildPileUpDbIndex(pileUps); 363 364 pileUpDb.rawWrite([dbIndex]); 365 366 writePileUpsDbBlock!PileUp(pileUpDb, pileUps, dbIndex); 367 writePileUpsDbBlock!ReadAlignment(pileUpDb, pileUps, dbIndex); 368 writePileUpsDbBlock!SeededAlignment(pileUpDb, pileUps, dbIndex); 369 writePileUpsDbBlock!LocalAlignment(pileUpDb, pileUps, dbIndex); 370 writePileUpsDbBlock!TracePoint(pileUpDb, pileUps, dbIndex); 371 } 372 373 unittest 374 { 375 import dentist.util.tempfile : mkstemp; 376 import std.file : remove; 377 378 alias LocalAlignment = AlignmentChain.LocalAlignment; 379 alias TracePoint = LocalAlignment.TracePoint; 380 381 auto pileUps = getPileUpsTestData(); 382 383 enum totalDbSize = 384 PileUpDbIndex.sizeof + 385 StorageType!PileUp.sizeof * numPileUps + 386 StorageType!ReadAlignment.sizeof * numReadAlignments + 387 StorageType!SeededAlignment.sizeof * numSeededAlignments + 388 StorageType!LocalAlignment.sizeof * numLocalAlignments + 389 StorageType!TracePoint.sizeof * numTracePoints; 390 391 auto tmpDb = mkstemp("./.unittest-XXXXXX"); 392 scope (exit) 393 { 394 tmpDb.file.close(); 395 remove(tmpDb.name); 396 } 397 398 writePileUpsDb(pileUps, tmpDb.file); 399 tmpDb.file.sync(); 400 401 assert(tmpDb.file.size == totalDbSize); 402 403 tmpDb.file.rewind(); 404 auto pileUpDb = PileUpDb(tmpDb.file); 405 406 assert(pileUpDb[] == pileUps); 407 } 408 409 private PileUpDbIndex buildPileUpDbIndex(in PileUp[] pileUps) nothrow pure 410 { 411 alias LocalAlignment = AlignmentChain.LocalAlignment; 412 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 413 414 PileUpDbIndex dbIndex; 415 416 dbIndex.beginPtr!PileUp = PileUpDbIndex.sizeof; 417 dbIndex.endPtr!PileUp = StorageType!PileUp.sizeof * pileUps.length; 418 foreach (ref pileUp; pileUps) 419 { 420 dbIndex.endPtr!ReadAlignment += StorageType!ReadAlignment.sizeof * pileUp.length; 421 foreach (ref readAlignment; pileUp) 422 { 423 dbIndex.endPtr!SeededAlignment += StorageType!SeededAlignment.sizeof * readAlignment.length; 424 foreach (ref seededAlignment; readAlignment[]) 425 { 426 dbIndex.endPtr!LocalAlignment += StorageType!LocalAlignment.sizeof * seededAlignment.localAlignments.length; 427 foreach (ref localAlignment; seededAlignment.localAlignments) 428 { 429 dbIndex.endPtr!TracePoint += StorageType!TracePoint.sizeof * localAlignment.tracePoints.length; 430 } 431 } 432 } 433 } 434 435 dbIndex.readAlignmentsPtr += dbIndex.pileUpsPtr; 436 dbIndex.seededAlignmentsPtr += dbIndex.readAlignmentsPtr; 437 dbIndex.localAlignmentsPtr += dbIndex.seededAlignmentsPtr; 438 dbIndex.tracePointsPtr += dbIndex.localAlignmentsPtr; 439 dbIndex.eofPtr += dbIndex.tracePointsPtr; 440 441 return dbIndex; 442 } 443 444 unittest 445 { 446 alias LocalAlignment = AlignmentChain.LocalAlignment; 447 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 448 449 auto pileUps = getPileUpsTestData(); 450 auto dbIndex = buildPileUpDbIndex(pileUps); 451 452 assert(dbIndex.pileUpsPtr == PileUpDbIndex.sizeof); 453 assert(dbIndex.readAlignmentsPtr == 454 dbIndex.pileUpsPtr + 455 StorageType!PileUp.sizeof * numPileUps); 456 assert(dbIndex.seededAlignmentsPtr == 457 dbIndex.readAlignmentsPtr + 458 StorageType!ReadAlignment.sizeof * numReadAlignments); 459 assert(dbIndex.localAlignmentsPtr == 460 dbIndex.seededAlignmentsPtr + 461 StorageType!SeededAlignment.sizeof * numSeededAlignments); 462 assert(dbIndex.tracePointsPtr == 463 dbIndex.localAlignmentsPtr + 464 StorageType!LocalAlignment.sizeof * numLocalAlignments); 465 assert(dbIndex.eofPtr == 466 dbIndex.tracePointsPtr + 467 StorageType!TracePoint.sizeof * numTracePoints); 468 } 469 470 void writePileUpsDbBlock(T)(ref File pileUpDb, in PileUp[] pileUps, in PileUpDbIndex dbIndex) 471 if (is(T == PileUp)) 472 { 473 auto readAlignments = ArrayStorage!(StorageType!ReadAlignment)(dbIndex.beginPtr!ReadAlignment); 474 475 version (assert) 476 { 477 auto storedPileUps = ArrayStorage!(StorageType!PileUp)(dbIndex.beginPtr!PileUp); 478 assert(storedPileUps.ptr == pileUpDb.tell()); 479 } 480 foreach (ref pileUp; pileUps) 481 { 482 readAlignments.length = pileUp.length; 483 484 pileUpDb.rawWrite([readAlignments]); 485 486 readAlignments.ptr = readAlignments[$]; 487 488 version (assert) 489 { 490 ++storedPileUps.length; 491 assert(storedPileUps[$] == pileUpDb.tell()); 492 } 493 } 494 } 495 496 void writePileUpsDbBlock(T)(ref File pileUpDb, in PileUp[] pileUps, in PileUpDbIndex dbIndex) 497 if (is(T == ReadAlignment)) 498 { 499 auto seededAlignments = ArrayStorage!(StorageType!SeededAlignment)(dbIndex.beginPtr!SeededAlignment); 500 501 version (assert) 502 { 503 auto readAlignments = ArrayStorage!(StorageType!ReadAlignment)(dbIndex.beginPtr!ReadAlignment); 504 assert(readAlignments.ptr == pileUpDb.tell()); 505 } 506 foreach (ref pileUp; pileUps) 507 { 508 foreach (ref readAlignment; pileUp) 509 { 510 seededAlignments.length = readAlignment.length; 511 512 pileUpDb.rawWrite([seededAlignments]); 513 514 seededAlignments.ptr = seededAlignments[$]; 515 516 version (assert) 517 { 518 ++readAlignments.length; 519 assert(readAlignments[$] == pileUpDb.tell()); 520 } 521 } 522 } 523 } 524 525 void writePileUpsDbBlock(T)(ref File pileUpDb, in PileUp[] pileUps, in PileUpDbIndex dbIndex) 526 if (is(T == SeededAlignment)) 527 { 528 alias LocalAlignment = AlignmentChain.LocalAlignment; 529 530 auto localAlignments = ArrayStorage!(StorageType!LocalAlignment)(dbIndex.beginPtr!LocalAlignment); 531 532 version (assert) 533 { 534 auto seededAlignments = ArrayStorage!(StorageType!SeededAlignment)(dbIndex.beginPtr!SeededAlignment); 535 assert(seededAlignments.ptr == pileUpDb.tell()); 536 } 537 foreach (ref pileUp; pileUps) 538 { 539 foreach (ref readAlignment; pileUp) 540 { 541 foreach (ref seededAlignment; readAlignment[]) 542 { 543 localAlignments.length = seededAlignment.localAlignments.length; 544 545 pileUpDb.rawWrite([StorageType!SeededAlignment( 546 seededAlignment.id, 547 seededAlignment.contigA.id, 548 seededAlignment.contigA.length, 549 seededAlignment.contigB.id, 550 seededAlignment.contigB.length, 551 seededAlignment.flags, 552 localAlignments, 553 seededAlignment.tracePointDistance, 554 seededAlignment.seed, 555 )]); 556 557 localAlignments.ptr = localAlignments[$]; 558 559 version (assert) 560 { 561 ++seededAlignments.length; 562 assert(seededAlignments[$] == pileUpDb.tell()); 563 } 564 } 565 } 566 } 567 } 568 569 void writePileUpsDbBlock(T)(ref File pileUpDb, in PileUp[] pileUps, in PileUpDbIndex dbIndex) 570 if (is(T == AlignmentChain.LocalAlignment)) 571 { 572 alias LocalAlignment = AlignmentChain.LocalAlignment; 573 alias TracePoint = LocalAlignment.TracePoint; 574 575 auto tracePoints = ArrayStorage!(StorageType!TracePoint)(dbIndex.beginPtr!TracePoint); 576 577 version (assert) 578 { 579 auto localAlignments = ArrayStorage!(StorageType!LocalAlignment)(dbIndex.beginPtr!LocalAlignment); 580 assert(localAlignments.ptr == pileUpDb.tell()); 581 } 582 foreach (ref pileUp; pileUps) 583 { 584 foreach (ref readAlignment; pileUp) 585 { 586 foreach (ref seededAlignment; readAlignment[]) 587 { 588 foreach (ref localAlignment; seededAlignment.localAlignments) 589 { 590 tracePoints.length = localAlignment.tracePoints.length; 591 592 pileUpDb.rawWrite([StorageType!LocalAlignment( 593 localAlignment.contigA.begin, 594 localAlignment.contigA.end, 595 localAlignment.contigB.begin, 596 localAlignment.contigB.end, 597 localAlignment.numDiffs, 598 tracePoints, 599 )]); 600 601 tracePoints.ptr = tracePoints[$]; 602 603 version (assert) 604 { 605 ++localAlignments.length; 606 assert(localAlignments[$] == pileUpDb.tell()); 607 } 608 } 609 } 610 } 611 } 612 } 613 614 void writePileUpsDbBlock(T)(ref File pileUpDb, in PileUp[] pileUps, in PileUpDbIndex dbIndex) 615 if (is(T == AlignmentChain.LocalAlignment.TracePoint)) 616 { 617 alias LocalAlignment = AlignmentChain.LocalAlignment; 618 alias TracePoint = LocalAlignment.TracePoint; 619 620 version (assert) 621 { 622 auto tracePoints = ArrayStorage!(StorageType!TracePoint)(dbIndex.beginPtr!TracePoint); 623 assert(tracePoints.ptr == pileUpDb.tell()); 624 } 625 foreach (ref pileUp; pileUps) 626 { 627 foreach (ref readAlignment; pileUp) 628 { 629 foreach (ref seededAlignment; readAlignment[]) 630 { 631 foreach (ref localAlignment; seededAlignment.localAlignments) 632 { 633 pileUpDb.rawWrite(cast(const(StorageType!TracePoint[])) localAlignment.tracePoints); 634 635 version (assert) 636 { 637 tracePoints.length += localAlignment.tracePoints.length; 638 assert(tracePoints[$] == pileUpDb.tell()); 639 } 640 } 641 } 642 } 643 } 644 } 645 646 private struct PileUpDbIndex 647 { 648 mixin DbIndex; 649 650 private static template NextType(T) 651 { 652 static if (is(T == PileUp)) 653 alias NextType = ReadAlignment; 654 else static if (is(T == ReadAlignment)) 655 alias NextType = SeededAlignment; 656 else static if (is(T == SeededAlignment)) 657 alias NextType = AlignmentChain.LocalAlignment; 658 else static if (is(T == AlignmentChain.LocalAlignment)) 659 alias NextType = AlignmentChain.LocalAlignment.TracePoint; 660 else static if (is(T == AlignmentChain.LocalAlignment.TracePoint)) 661 alias NextType = EOF; 662 } 663 664 private static template fieldPtr(T) 665 { 666 static if (is(T == PileUp)) 667 alias fieldPtr = pileUpsPtr; 668 else static if (is(T == ReadAlignment)) 669 alias fieldPtr = readAlignmentsPtr; 670 else static if (is(T == SeededAlignment)) 671 alias fieldPtr = seededAlignmentsPtr; 672 else static if (is(T == AlignmentChain.LocalAlignment)) 673 alias fieldPtr = localAlignmentsPtr; 674 else static if (is(T == AlignmentChain.LocalAlignment.TracePoint)) 675 alias fieldPtr = tracePointsPtr; 676 else static if (is(T == EOF)) 677 alias fieldPtr = eofPtr; 678 } 679 680 size_t pileUpsPtr; 681 size_t readAlignmentsPtr; 682 size_t seededAlignmentsPtr; 683 size_t localAlignmentsPtr; 684 size_t tracePointsPtr; 685 size_t eofPtr; 686 687 @property alias pileUps = arrayStorage!PileUp; 688 @property alias readAlignments = arrayStorage!ReadAlignment; 689 @property alias seededAlignments = arrayStorage!SeededAlignment; 690 @property alias localAlignments = arrayStorage!(AlignmentChain.LocalAlignment); 691 @property alias tracePoints = arrayStorage!(AlignmentChain.LocalAlignment.TracePoint); 692 } 693 694 unittest 695 { 696 alias LocalAlignment = AlignmentChain.LocalAlignment; 697 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 698 enum begin = 1; 699 enum end = 2; 700 enum modified = 3; 701 702 703 { 704 PileUpDbIndex dbIndex; 705 706 dbIndex.pileUpsPtr = begin; 707 dbIndex.readAlignmentsPtr = end; 708 709 assert(dbIndex.beginPtr!PileUp == begin); 710 assert(dbIndex.endPtr!PileUp == end); 711 712 dbIndex.beginPtr!PileUp = modified; 713 dbIndex.endPtr!PileUp = modified; 714 715 assert(dbIndex.pileUpsPtr == modified); 716 assert(dbIndex.readAlignmentsPtr == modified); 717 } 718 { 719 PileUpDbIndex dbIndex; 720 721 dbIndex.readAlignmentsPtr = begin; 722 dbIndex.seededAlignmentsPtr = end; 723 724 assert(dbIndex.beginPtr!ReadAlignment == begin); 725 assert(dbIndex.endPtr!ReadAlignment == end); 726 727 dbIndex.beginPtr!ReadAlignment = modified; 728 dbIndex.endPtr!ReadAlignment = modified; 729 730 assert(dbIndex.readAlignmentsPtr == modified); 731 assert(dbIndex.seededAlignmentsPtr == modified); 732 } 733 { 734 PileUpDbIndex dbIndex; 735 736 dbIndex.seededAlignmentsPtr = begin; 737 dbIndex.localAlignmentsPtr = end; 738 739 assert(dbIndex.beginPtr!SeededAlignment == begin); 740 assert(dbIndex.endPtr!SeededAlignment == end); 741 742 dbIndex.beginPtr!SeededAlignment = modified; 743 dbIndex.endPtr!SeededAlignment = modified; 744 745 assert(dbIndex.seededAlignmentsPtr == modified); 746 assert(dbIndex.localAlignmentsPtr == modified); 747 } 748 { 749 PileUpDbIndex dbIndex; 750 751 dbIndex.localAlignmentsPtr = begin; 752 dbIndex.tracePointsPtr = end; 753 754 assert(dbIndex.beginPtr!LocalAlignment == begin); 755 assert(dbIndex.endPtr!LocalAlignment == end); 756 757 dbIndex.beginPtr!LocalAlignment = modified; 758 dbIndex.endPtr!LocalAlignment = modified; 759 760 assert(dbIndex.localAlignmentsPtr == modified); 761 assert(dbIndex.tracePointsPtr == modified); 762 } 763 { 764 PileUpDbIndex dbIndex; 765 766 dbIndex.tracePointsPtr = begin; 767 dbIndex.eofPtr = end; 768 769 assert(dbIndex.beginPtr!TracePoint == begin); 770 assert(dbIndex.endPtr!TracePoint == end); 771 772 dbIndex.beginPtr!TracePoint = modified; 773 dbIndex.endPtr!TracePoint = modified; 774 775 assert(dbIndex.tracePointsPtr == modified); 776 assert(dbIndex.eofPtr == modified); 777 } 778 } 779 780 private template StorageType(T) 781 { 782 static if (is(T == PileUp)) 783 alias StorageType = ArrayStorage!(StorageType!ReadAlignment); 784 else static if (is(T == ReadAlignment)) 785 alias StorageType = ArrayStorage!(StorageType!SeededAlignment); 786 else static if (is(T == SeededAlignment)) 787 alias StorageType = SeededAlignmentStorage; 788 else static if (is(T == AlignmentChain.LocalAlignment[])) 789 alias StorageType = ArrayStorage!(StorageType!(AlignmentChain.LocalAlignment)); 790 else static if (is(T == AlignmentChain.LocalAlignment)) 791 alias StorageType = LocalAlignmentStorage; 792 else static if (is(T == AlignmentChain.LocalAlignment.TracePoint[])) 793 alias StorageType = ArrayStorage!(StorageType!(AlignmentChain.LocalAlignment.TracePoint)); 794 else static if (is(T == AlignmentChain.LocalAlignment.TracePoint)) 795 alias StorageType = TracePointStorage; 796 } 797 798 private struct SeededAlignmentStorage 799 { 800 alias LocalAlignment = AlignmentChain.LocalAlignment; 801 802 id_t id; 803 id_t contigAId; 804 coord_t contigALength; 805 id_t contigBId; 806 coord_t contigBLength; 807 AlignmentChain.Flags flags; 808 StorageType!(LocalAlignment[]) localAlignments; 809 trace_point_t tracePointDistance; 810 AlignmentLocationSeed seed; 811 } 812 813 private struct LocalAlignmentStorage 814 { 815 alias TracePoint = AlignmentChain.LocalAlignment.TracePoint; 816 817 coord_t contigABegin; 818 coord_t contigAEnd; 819 coord_t contigBBegin; 820 coord_t contigBEnd; 821 diff_t numDiffs; 822 StorageType!(TracePoint[]) tracePoints; 823 } 824 825 private struct TracePointStorage 826 { 827 trace_point_t numDiffs; 828 trace_point_t numBasePairs; 829 }