1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include "CSRA1_Alignment.h"
28
29 typedef struct BAM_Alignment BAM_Alignment;
30 #define NGS_ALIGNMENT void
31
32 #include "NGS_Alignment.h"
33
34 #include "NGS_ReadCollection.h"
35
36 #include <sysalloc.h>
37
38 #include <vdb/cursor.h>
39 #include <vdb/vdb-priv.h>
40
41 #include <klib/printf.h>
42 #include <klib/rc.h>
43
44 #include <kfc/ctx.h>
45 #include <kfc/rsrc.h>
46 #include <kfc/except.h>
47 #include <kfc/xc.h>
48
49 #include "NGS_Refcount.h"
50 #include "NGS_String.h"
51
52 #include <string.h>
53 #include <limits.h>
54
55 #include "BAM_Record.h"
56
57 struct BAM_Alignment {
58 NGS_Alignment super;
59 struct BAM_Record *(*provider_f)(struct NGS_ReadCollection *, ctx_t);
60 struct NGS_ReadCollection *provider;
61 BAM_Record *cur;
62 bool primary;
63 bool secondary;
64 };
65
BAM_AlignmentWhack(void * const vp,ctx_t ctx)66 static void BAM_AlignmentWhack(void * const vp, ctx_t ctx)
67 {
68 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
69 BAM_Alignment *const self = (BAM_Alignment *)vp;
70
71 free(self->cur);
72 NGS_RefcountRelease(&self->provider->dad, ctx);
73 }
74
BAM_AlignmentAlignmentId(void * const vp,ctx_t ctx)75 static NGS_String *BAM_AlignmentAlignmentId(void *const vp, ctx_t ctx)
76 {
77 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
78 BAM_Alignment *const self = (BAM_Alignment *)vp;
79
80 (void)self;
81 UNIMPLEMENTED();
82 return NULL;
83 }
84
BAM_AlignmentReferenceSpec(void * const vp,ctx_t ctx)85 static NGS_String * BAM_AlignmentReferenceSpec(void *const vp, ctx_t ctx)
86 {
87 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
88 BAM_Alignment *const self = (BAM_Alignment *)vp;
89
90 if (self->cur)
91 return NGS_StringMake(ctx, self->cur->RNAME, strlen(self->cur->RNAME));
92
93 USER_ERROR(xcRowNotFound, "no current row");
94 return NULL;
95 }
96
97
BAM_AlignmentMappingQuality(void * const vp,ctx_t ctx)98 static int BAM_AlignmentMappingQuality(void *const vp, ctx_t ctx)
99 {
100 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
101 BAM_Alignment *const self = (BAM_Alignment *)vp;
102
103 if (self->cur)
104 return self->cur->MAPQ;
105
106 USER_ERROR(xcRowNotFound, "no current row");
107 return 0;
108 }
109
110
BAM_AlignmentReferenceBases(void * const vp,ctx_t ctx)111 static NGS_String * BAM_AlignmentReferenceBases(void *const vp, ctx_t ctx)
112 {
113 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
114 BAM_Alignment *const self = (BAM_Alignment *)vp;
115
116 (void)self;
117 UNIMPLEMENTED();
118 return NULL;
119 }
120
121
FindRG(void * const vp,ctx_t ctx,unsigned const ord,BAM_Record_Extra_Field const * const fld)122 static bool FindRG(void *const vp, ctx_t ctx, unsigned const ord, BAM_Record_Extra_Field const *const fld)
123 {
124 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
125
126 if (fld->tag[0] == 'R' && fld->tag[1] == 'G' && fld->val_type == 'Z') {
127 NGS_String **const prslt = vp;
128
129 *prslt = NGS_StringMakeCopy(ctx, fld->value->string, fld->elemcount);
130 return false; /* done */
131 }
132 return true; /* keep going */
133 }
134
BAM_AlignmentReadGroup(void * const vp,ctx_t ctx)135 static NGS_String * BAM_AlignmentReadGroup(void *const vp, ctx_t ctx)
136 {
137 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
138 BAM_Alignment *const self = (BAM_Alignment *)vp;
139
140 if (self->cur) {
141 NGS_String *rslt = NULL;
142
143 BAM_Record_ForEachExtra(self->cur, ctx, FindRG, &rslt);
144 return rslt;
145 }
146 USER_ERROR(xcRowNotFound, "no current row");
147 return NULL;
148 }
149
150
BAM_AlignmentReadId(void * const vp,ctx_t ctx)151 static NGS_String * BAM_AlignmentReadId(void *const vp, ctx_t ctx)
152 {
153 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
154 BAM_Alignment *const self = (BAM_Alignment *)vp;
155
156 if (self->cur)
157 return self->cur->QNAME ? NGS_StringMake(ctx, self->cur->QNAME, strlen(self->cur->QNAME)) : NULL;
158
159 USER_ERROR(xcRowNotFound, "no current row");
160 return NULL;
161 }
162
163
164 typedef struct {
165 unsigned start;
166 unsigned length;
167 } clipped_t;
168
get_clipping(BAM_Record const * rec)169 static clipped_t const get_clipping(BAM_Record const *rec)
170 {
171 clipped_t rslt = { 0, rec->seqlen };
172
173 if (rec->ncigar > 0 && (rec->cigar[0] & 0x0F) == 4) {
174 unsigned const length = rec->cigar[0] >> 4;
175
176 rslt.start += length;
177 rslt.length -= length;
178 }
179 if (rec->ncigar > 1 && (rec->cigar[rec->ncigar - 1] & 0x0F) == 4) {
180 unsigned const length = rec->cigar[rec->ncigar - 1] >> 4;
181
182 rslt.length -= length;
183 }
184 return rslt;
185 }
186
BAM_AlignmentClippedFragmentBases(void * const vp,ctx_t ctx)187 static NGS_String * BAM_AlignmentClippedFragmentBases(void *const vp, ctx_t ctx)
188 {
189 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
190 BAM_Alignment *const self = (BAM_Alignment *)vp;
191
192 if (self->cur) {
193 if (self->cur->seqlen) {
194 clipped_t const clipping = get_clipping(self->cur);
195 return NGS_StringMake(ctx, self->cur->SEQ + clipping.start, clipping.length);
196 }
197 return NULL;
198 }
199 USER_ERROR(xcRowNotFound, "no current row");
200 return NULL;
201 }
202
203
BAM_AlignmentClippedFragmentQualities(void * const vp,ctx_t ctx)204 static NGS_String * BAM_AlignmentClippedFragmentQualities(void *const vp, ctx_t ctx)
205 {
206 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
207 BAM_Alignment *const self = (BAM_Alignment *)vp;
208
209 if (self->cur) {
210 if (self->cur->seqlen && self->cur->QUAL[0] != -1) {
211 clipped_t const clipping = get_clipping(self->cur);
212 return NGS_StringMake(ctx, self->cur->QUAL + clipping.start, clipping.length);
213 }
214 return NULL;
215 }
216 USER_ERROR(xcRowNotFound, "no current row");
217 return NULL;
218 }
219
220
BAM_AlignmentIsPrimary(void * const vp,ctx_t ctx)221 static bool BAM_AlignmentIsPrimary(void *const vp, ctx_t ctx)
222 {
223 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
224 BAM_Alignment *const self = (BAM_Alignment *)vp;
225
226 if (self->cur)
227 return (self->cur->FLAG & 0x0900) == 0 ? true : false;
228
229 USER_ERROR(xcRowNotFound, "no current row");
230 return false;
231 }
232
233
BAM_AlignmentAlignmentPosition(void * const vp,ctx_t ctx)234 static int64_t BAM_AlignmentAlignmentPosition(void *const vp, ctx_t ctx)
235 {
236 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
237 BAM_Alignment *const self = (BAM_Alignment *)vp;
238
239 if (self->cur)
240 return self->cur->POS - 1;
241
242 USER_ERROR(xcRowNotFound, "no current row");
243 return -1;
244 }
245
246
ComputeRefLen(size_t const count,uint32_t const cigar[])247 static unsigned ComputeRefLen(size_t const count, uint32_t const cigar[])
248 {
249 unsigned rslt = 0;
250 unsigned i;
251
252 for (i = 0; i < count; ++i) {
253 uint32_t const op = cigar[i];
254 unsigned const len = op >> 4;
255 int const code = op & 0x0F;
256
257 switch (code) {
258 case 0: /* M */
259 case 2: /* D */
260 case 3: /* N */
261 case 7: /* = */
262 case 8: /* X */
263 rslt += len;
264 break;
265 }
266 }
267 return rslt;
268 }
269
BAM_AlignmentAlignmentLength(void * const vp,ctx_t ctx)270 static uint64_t BAM_AlignmentAlignmentLength(void *const vp, ctx_t ctx)
271 {
272 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
273 BAM_Alignment *const self = (BAM_Alignment *)vp;
274
275 if (self->cur)
276 return ComputeRefLen(self->cur->ncigar, self->cur->cigar);
277
278 USER_ERROR(xcRowNotFound, "no current row");
279 return 0;
280 }
281
282
BAM_AlignmentIsReversedOrientation(void * const vp,ctx_t ctx)283 static bool BAM_AlignmentIsReversedOrientation(void *const vp, ctx_t ctx)
284 {
285 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
286 BAM_Alignment *const self = (BAM_Alignment *)vp;
287
288 if (self->cur)
289 return (self->cur->FLAG & 0x0010) == 0 ? false : true;
290
291 USER_ERROR(xcRowNotFound, "no current row");
292 return false;
293 }
294
295
BAM_AlignmentSoftClip(void * const vp,ctx_t ctx,bool left)296 static int BAM_AlignmentSoftClip(void *const vp, ctx_t ctx, bool left)
297 {
298 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
299 BAM_Alignment *const self = (BAM_Alignment *)vp;
300
301 if (self->cur) {
302 unsigned const end = left ? 0 : (self->cur->ncigar - 1);
303 uint32_t const op = self->cur->cigar[end];
304 int const code = op & 0x0F;
305 int const len = op >> 4;
306
307 return code == 4 ? len : 0;
308 }
309 USER_ERROR(xcRowNotFound, "no current row");
310 return false;
311 }
312
313
BAM_AlignmentTemplateLength(void * const vp,ctx_t ctx)314 static uint64_t BAM_AlignmentTemplateLength(void *const vp, ctx_t ctx)
315 {
316 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
317 BAM_Alignment *const self = (BAM_Alignment *)vp;
318
319 if (self->cur)
320 return self->cur->TLEN;
321
322 USER_ERROR(xcRowNotFound, "no current row");
323 return 0;
324 }
325
326
FormatCIGAR(char * dst,char const OPCODE[],size_t const count,uint32_t const cigar[])327 static char const *FormatCIGAR(char *dst, char const OPCODE[], size_t const count, uint32_t const cigar[])
328 {
329 uint32_t const *src = cigar + count;
330 unsigned i;
331 char *last_out;
332 char last_code = 0;
333 uint32_t last_len = 0;
334
335 last_out = dst;
336 for (i = 0; i < count; ++i) {
337 uint32_t const op = *--src;
338 char const code = OPCODE[op & 0x0F];
339 uint32_t const len1 = op >> 4;
340 uint32_t len = code == last_code ? ((dst = last_out), last_len + len1) : len1;
341
342 last_len = len;
343 last_code = code;
344 last_out = dst;
345 *--dst = code;
346 for ( ; ; ) {
347 *--dst = len % 10 + '0';
348 if ((len /= 10) == 0)
349 break;
350 }
351 }
352 return dst;
353 }
354
CIGAR(ctx_t ctx,char const OPCODE[],size_t const count,uint32_t const cigar[])355 static NGS_String *CIGAR(ctx_t ctx, char const OPCODE[], size_t const count, uint32_t const cigar[])
356 {
357 size_t const max = 10 * count;
358 #if DEBUG
359 char buffer[max + 1];
360 buffer[max] = '\0';
361 #else
362 char buffer[max];
363 #endif
364 char *const endp = buffer + max;
365 char const *const rslt = FormatCIGAR(endp, OPCODE, count, cigar);
366 size_t const len = endp - rslt;
367
368 return NGS_StringMakeCopy(ctx, rslt, len);
369 }
370
CIGAR_clipped(ctx_t ctx,char const OPCODE[],bool const clipped,size_t const count,uint32_t const cigar[])371 static NGS_String *CIGAR_clipped(ctx_t ctx, char const OPCODE[], bool const clipped, size_t const count, uint32_t const cigar[])
372 {
373 if (!clipped)
374 return CIGAR(ctx, OPCODE, count, cigar);
375 else {
376 char const first = cigar[0] & 0x0F;
377 char const last = cigar[count - 1] & 0x0F;
378 unsigned const cfirst = (first == 4 || first == 5) ? 1 : 0;
379 unsigned const clast = (last == 4 || last == 5) ? 1 : 0;
380
381 return CIGAR(ctx, OPCODE, count - cfirst - clast, &cigar[cfirst]);
382 }
383 }
384
BAM_AlignmentShortCigar(void * const vp,ctx_t ctx,bool clipped)385 static NGS_String * BAM_AlignmentShortCigar(void *const vp, ctx_t ctx, bool clipped)
386 {
387 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
388 BAM_Alignment *const self = (BAM_Alignment *)vp;
389
390 if (self->cur)
391 return CIGAR_clipped(ctx, "MIDNSHPMM???????", clipped, self->cur->ncigar, self->cur->cigar);
392
393 USER_ERROR(xcRowNotFound, "no current row");
394 return NULL;
395 }
396
397
BAM_AlignmentLongCigar(void * const vp,ctx_t ctx,bool clipped)398 static NGS_String * BAM_AlignmentLongCigar(void *const vp, ctx_t ctx, bool clipped)
399 {
400 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
401 BAM_Alignment *const self = (BAM_Alignment *)vp;
402
403 if (self->cur)
404 return CIGAR_clipped(ctx, "MIDNSHP=X???????", clipped, self->cur->ncigar, self->cur->cigar);
405
406 USER_ERROR(xcRowNotFound, "no current row");
407 return NULL;
408 }
409
410
BAM_AlignmentHasMate(void * const vp,ctx_t ctx)411 static bool BAM_AlignmentHasMate(void *const vp, ctx_t ctx)
412 {
413 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
414 BAM_Alignment *const self = (BAM_Alignment *)vp;
415
416 if (self->cur)
417 return (self->cur->FLAG & 0x0001) == 0 ? false : true;
418
419 USER_ERROR(xcRowNotFound, "no current row");
420 return false;
421 }
422
423
BAM_AlignmentMateAlignmentId(void * const vp,ctx_t ctx)424 static NGS_String * BAM_AlignmentMateAlignmentId(void *const vp, ctx_t ctx)
425 {
426 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
427 BAM_Alignment *const self = (BAM_Alignment *)vp;
428
429 (void)self;
430 UNIMPLEMENTED();
431 return 0;
432 }
433
434
BAM_AlignmentMateAlignment(void * const vp,ctx_t ctx)435 static void * BAM_AlignmentMateAlignment(void *const vp, ctx_t ctx)
436 {
437 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
438 BAM_Alignment *const self = (BAM_Alignment *)vp;
439
440 (void)self;
441 UNIMPLEMENTED();
442 return NULL;
443 }
444
445
BAM_AlignmentMateReferenceSpec(void * const vp,ctx_t ctx)446 static NGS_String * BAM_AlignmentMateReferenceSpec(void *const vp, ctx_t ctx)
447 {
448 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
449 BAM_Alignment *const self = (BAM_Alignment *)vp;
450
451 if (self->cur)
452 return self->cur->RNEXT ? NGS_StringMake(ctx, self->cur->RNEXT, strlen(self->cur->RNEXT)) : NULL;
453
454 USER_ERROR(xcRowNotFound, "no current row");
455 return NULL;
456 }
457
458
BAM_AlignmentMateIsReversedOrientation(void * const vp,ctx_t ctx)459 static bool BAM_AlignmentMateIsReversedOrientation(void *const vp, ctx_t ctx)
460 {
461 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
462 BAM_Alignment *const self = (BAM_Alignment *)vp;
463
464 if (self->cur)
465 return (self->cur->FLAG & 0x0020) == 0 ? false : true;
466
467 USER_ERROR(xcRowNotFound, "no current row");
468 return false;
469 }
470
BAM_AlignmentIsFirst(void * const vp,ctx_t ctx)471 static bool BAM_AlignmentIsFirst(void *const vp, ctx_t ctx)
472 {
473 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
474 BAM_Alignment *const self = (BAM_Alignment *)vp;
475
476 if (self->cur) {
477 bool const isMated = (self->cur->FLAG & 0x001) == 0 ? false : true;
478 bool const isFirst = (self->cur->FLAG & 0x040) == 0 ? false : true;
479 bool const isLast = (self->cur->FLAG & 0x080) == 0 ? false : true;
480 return (isMated && isFirst && !isLast);
481 }
482 USER_ERROR(xcRowNotFound, "no current row");
483 return false;
484 }
485
486
487 /*--------------------------------------------------------------------------
488 * NGS_AlignmentIterator
489 */
490
ShouldSkip(BAM_Alignment const * const self)491 static bool ShouldSkip(BAM_Alignment const *const self)
492 {
493 if (!self->cur->RNAME) /* not aligned */
494 return true;
495
496 if ((self->cur->FLAG & 0x0900) == 0 && !self->primary) /* is primary and don't want primary */
497 return true;
498
499 if ((self->cur->FLAG & 0x0900) != 0 && !self->secondary) /* is secondary and don't want secondary */
500 return true;
501
502 return false;
503 }
504
BAM_AlignmentIteratorNext(void * const vp,ctx_t ctx)505 static bool BAM_AlignmentIteratorNext(void *const vp, ctx_t ctx)
506 {
507 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
508 BAM_Alignment *const self = (BAM_Alignment *)vp;
509
510 do {
511 if (self->cur)
512 free(self->cur);
513 self->cur = self->provider_f(self->provider, ctx);
514 if (FAILED() || !self->cur)
515 break;
516 } while (ShouldSkip(self));
517
518 return self->cur != NULL;
519 }
520
521
BAM_AlignmentFragmentGetId(void * const vp,ctx_t ctx)522 static NGS_String * BAM_AlignmentFragmentGetId(void *const vp, ctx_t ctx)
523 {
524 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
525 BAM_Alignment *const self = (BAM_Alignment *)vp;
526
527 if (self->cur) {
528 return self->cur->QNAME ? NGS_StringMake(ctx, self->cur->QNAME, strlen(self->cur->QNAME)) : NGS_StringMake(ctx, "", 0);
529 }
530 USER_ERROR(xcRowNotFound, "no current row");
531 return NULL;
532 }
533
534
BAM_AlignmentFragmentGetBases(void * const vp,ctx_t ctx,uint64_t offset,uint64_t length)535 static NGS_String * BAM_AlignmentFragmentGetBases(void *const vp, ctx_t ctx,
536 uint64_t offset, uint64_t length)
537 {
538 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
539 BAM_Alignment *const self = (BAM_Alignment *)vp;
540
541 if (self->cur) {
542 if (offset + length < self->cur->seqlen) {
543 return NGS_StringMake(ctx, self->cur->SEQ + offset, length);
544 }
545 USER_ERROR(xcRowNotFound, "invalid offset or length");
546 return NULL;
547 }
548 USER_ERROR(xcRowNotFound, "no current row");
549 return NULL;
550 }
551
552
BAM_AlignmentFragmentGetQualities(void * const vp,ctx_t ctx,uint64_t offset,uint64_t length)553 static NGS_String * BAM_AlignmentFragmentGetQualities(void *const vp, ctx_t ctx,
554 uint64_t offset, uint64_t length)
555 {
556 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
557 BAM_Alignment *const self = (BAM_Alignment *)vp;
558
559 if (self->cur) {
560 if (offset + length < self->cur->seqlen) {
561 return NGS_StringMake(ctx, self->cur->QUAL + offset, length);
562 }
563 USER_ERROR(xcRowNotFound, "invalid offset or length");
564 return NULL;
565 }
566 USER_ERROR(xcRowNotFound, "no current row");
567 return NULL;
568 }
569
570
BAM_AlignmentFragmentNext(void * const vp,ctx_t ctx)571 static bool BAM_AlignmentFragmentNext(void *const vp, ctx_t ctx)
572 {
573 FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
574 BAM_Alignment *const self = (BAM_Alignment *)vp;
575
576 (void)self;
577 UNIMPLEMENTED();
578 return NULL;
579 }
580
581
582
583 static NGS_Alignment_vt const vt =
584 {
585 {
586 {
587 /* NGS_Refcount */
588 BAM_AlignmentWhack
589 },
590
591 /* NGS_Fragment */
592 BAM_AlignmentFragmentGetId,
593 BAM_AlignmentFragmentGetBases,
594 BAM_AlignmentFragmentGetQualities,
595 BAM_AlignmentFragmentNext
596 },
597
598 BAM_AlignmentAlignmentId,
599 BAM_AlignmentReferenceSpec,
600 BAM_AlignmentMappingQuality,
601 BAM_AlignmentReferenceBases,
602 BAM_AlignmentReadGroup,
603 BAM_AlignmentReadId,
604 BAM_AlignmentClippedFragmentBases,
605 BAM_AlignmentClippedFragmentQualities,
606 NULL,
607 BAM_AlignmentIsPrimary,
608 BAM_AlignmentAlignmentPosition,
609 BAM_AlignmentAlignmentLength,
610 BAM_AlignmentIsReversedOrientation,
611 BAM_AlignmentSoftClip,
612 BAM_AlignmentTemplateLength,
613 BAM_AlignmentShortCigar,
614 BAM_AlignmentLongCigar,
615 BAM_AlignmentHasMate,
616 BAM_AlignmentMateAlignmentId,
617 BAM_AlignmentMateAlignment,
618 BAM_AlignmentMateReferenceSpec,
619 BAM_AlignmentMateIsReversedOrientation,
620 BAM_AlignmentIsFirst,
621
622 /* Iterator */
623 BAM_AlignmentIteratorNext
624 };
625
BAM_AlignmentInit(BAM_Alignment * const self,ctx_t ctx,bool const primary,bool const secondary,struct BAM_Record * (* const provider_f)(struct NGS_ReadCollection *,ctx_t),struct NGS_ReadCollection * const provider)626 static void BAM_AlignmentInit(BAM_Alignment *const self, ctx_t ctx, bool const primary, bool const secondary,
627 struct BAM_Record *(*const provider_f)(struct NGS_ReadCollection *, ctx_t),
628 struct NGS_ReadCollection *const provider)
629 {
630 self->provider = provider;
631 self->provider_f = provider_f;
632 self->primary = primary;
633 self->secondary = secondary;
634 }
635
BAM_AlignmentMake(ctx_t ctx,bool const primary,bool const secondary,struct BAM_Record * (* const provider_f)(struct NGS_ReadCollection *,ctx_t),struct NGS_ReadCollection * const provider,char const name[])636 struct NGS_Alignment *BAM_AlignmentMake(ctx_t ctx, bool const primary, bool const secondary,
637 struct BAM_Record *(*const provider_f)(struct NGS_ReadCollection *, ctx_t),
638 struct NGS_ReadCollection *const provider,
639 char const name[])
640 {
641 FUNC_ENTRY(ctx, rcSRA, rcFile, rcReading);
642 void *self = calloc(1, sizeof(BAM_Alignment));
643 if (self) {
644 NGS_Alignment *const super = &((BAM_Alignment *)self)->super;
645
646 TRY(NGS_AlignmentInit(ctx, super, &vt, "BAM_Alignment", name)) {
647 TRY(BAM_AlignmentInit(self, ctx, primary, secondary, provider_f, provider)) {
648 return self;
649 }
650 }
651 free(self);
652 }
653 else {
654 SYSTEM_ABORT(xcNoMemory, "allocating BAM_Alignment ( '%s' )", name);
655 }
656 return NULL;
657 }
658