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 <ngs/itf/ReferenceItf.hpp> 28 #include <ngs/itf/PileupItf.hpp> 29 #include <ngs/itf/AlignmentItf.hpp> 30 #include <ngs/itf/StringItf.hpp> 31 #include <ngs/itf/ErrBlock.hpp> 32 #include <ngs/itf/VTable.hpp> 33 34 #include <ngs/itf/ReferenceItf.h> 35 36 #include <ngs/Alignment.hpp> 37 38 namespace ngs 39 { 40 /*---------------------------------------------------------------------- 41 * metadata 42 */ 43 extern ItfTok NGS_Refcount_v1_tok; 44 ItfTok NGS_Reference_v1_tok ( "NGS_Reference_v1", NGS_Refcount_v1_tok ); 45 46 47 /*---------------------------------------------------------------------- 48 * create NGS_ReferenceAlignFlags from Alignment bits 49 */ make_flags(uint32_t categories,uint32_t filters)50 static uint32_t make_flags ( uint32_t categories, uint32_t filters ) 51 { 52 static bool tested_bits; 53 if ( ! tested_bits ) 54 { 55 assert ( ( int ) Alignment :: primaryAlignment == ( int ) NGS_ReferenceAlignFlags_wants_primary ); 56 assert ( ( int ) Alignment :: secondaryAlignment == ( int ) NGS_ReferenceAlignFlags_wants_secondary ); 57 assert ( ( int ) Alignment :: passFailed << 2 == ( int ) NGS_ReferenceAlignFlags_pass_bad ); 58 assert ( ( int ) Alignment :: passDuplicates << 2 == ( int ) NGS_ReferenceAlignFlags_pass_dups ); 59 assert ( ( int ) Alignment :: minMapQuality << 2 == ( int ) NGS_ReferenceAlignFlags_min_map_qual ); 60 assert ( ( int ) Alignment :: maxMapQuality << 2 == ( int ) NGS_ReferenceAlignFlags_max_map_qual ); 61 assert ( ( int ) Alignment :: noWraparound << 2 == ( int ) NGS_ReferenceAlignFlags_no_wraparound ); 62 assert ( ( int ) Alignment :: startWithinSlice << 2 == ( int ) NGS_ReferenceAlignFlags_start_within_window ); 63 tested_bits = true; 64 } 65 return ( categories & 0x03 ) | ( filters << 2 ); 66 } 67 68 69 /*---------------------------------------------------------------------- 70 * access vtable 71 */ 72 static inline Access(const NGS_VTable * vt)73 const NGS_Reference_v1_vt * Access ( const NGS_VTable * vt ) 74 { 75 const NGS_Reference_v1_vt * out = static_cast < const NGS_Reference_v1_vt* > 76 ( Cast ( vt, NGS_Reference_v1_tok ) ); 77 if ( out == 0 ) 78 throw ErrorMsg ( "object is not of type NGS_Reference_v1" ); 79 return out; 80 } 81 82 83 /*---------------------------------------------------------------------- 84 * ReferenceItf 85 */ 86 getCommonName() const87 StringItf * ReferenceItf :: getCommonName () const 88 NGS_THROWS ( ErrorMsg ) 89 { 90 // the object is really from C 91 const NGS_Reference_v1 * self = Test (); 92 93 // cast vtable to our level 94 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 95 96 // call through C vtable 97 ErrBlock err; 98 assert ( vt -> get_cmn_name != 0 ); 99 NGS_String_v1 * ret = ( * vt -> get_cmn_name ) ( self, & err ); 100 101 // check for errors 102 err . Check (); 103 104 return StringItf :: Cast ( ret ); 105 } 106 getCanonicalName() const107 StringItf * ReferenceItf :: getCanonicalName () const 108 NGS_THROWS ( ErrorMsg ) 109 { 110 // the object is really from C 111 const NGS_Reference_v1 * self = Test (); 112 113 // cast vtable to our level 114 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 115 116 // call through C vtable 117 ErrBlock err; 118 assert ( vt -> get_canon_name != 0 ); 119 NGS_String_v1 * ret = ( * vt -> get_canon_name ) ( self, & err ); 120 121 // check for errors 122 err . Check (); 123 124 return StringItf :: Cast ( ret ); 125 } 126 getIsCircular() const127 bool ReferenceItf :: getIsCircular () const 128 NGS_THROWS ( ErrorMsg ) 129 { 130 // the object is really from C 131 const NGS_Reference_v1 * self = Test (); 132 133 // cast vtable to our level 134 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 135 136 // call through C vtable 137 ErrBlock err; 138 assert ( vt -> is_circular != 0 ); 139 bool ret = ( * vt -> is_circular ) ( self, & err ); 140 141 // check for errors 142 err . Check (); 143 144 return ret; 145 } 146 getIsLocal() const147 bool ReferenceItf :: getIsLocal () const 148 NGS_THROWS ( ErrorMsg ) 149 { 150 // the object is really from C 151 const NGS_Reference_v1 * self = Test (); 152 153 // cast vtable to our level 154 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 155 156 // test for v1.2 157 if ( vt -> dad . minor_version < 4 ) 158 throw ErrorMsg ( "the Reference interface provided by this NGS engine is too old to support this message" ); 159 160 // call through C vtable 161 ErrBlock err; 162 assert ( vt -> is_local != 0 ); 163 bool ret = ( * vt -> is_local ) ( self, & err ); 164 165 // check for errors 166 err . Check (); 167 168 return ret; 169 } 170 getLength() const171 uint64_t ReferenceItf :: getLength () const 172 NGS_THROWS ( ErrorMsg ) 173 { 174 // the object is really from C 175 const NGS_Reference_v1 * self = Test (); 176 177 // cast vtable to our level 178 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 179 180 // call through C vtable 181 ErrBlock err; 182 assert ( vt -> get_length != 0 ); 183 uint64_t ret = ( * vt -> get_length ) ( self, & err ); 184 185 // check for errors 186 err . Check (); 187 188 return ret; 189 } 190 getReferenceBases(uint64_t offset) const191 StringItf * ReferenceItf :: getReferenceBases ( uint64_t offset ) const 192 NGS_THROWS ( ErrorMsg ) 193 { 194 return this -> getReferenceBases ( offset, -1 ); 195 } 196 getReferenceBases(uint64_t offset,uint64_t length) const197 StringItf * ReferenceItf :: getReferenceBases ( uint64_t offset, uint64_t length ) const 198 NGS_THROWS ( ErrorMsg ) 199 { 200 // the object is really from C 201 const NGS_Reference_v1 * self = Test (); 202 203 // cast vtable to our level 204 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 205 206 // call through C vtable 207 ErrBlock err; 208 assert ( vt -> get_ref_bases != 0 ); 209 NGS_String_v1 * ret = ( * vt -> get_ref_bases ) ( self, & err, offset, length ); 210 211 // check for errors 212 err . Check (); 213 214 return StringItf :: Cast ( ret ); 215 } 216 getReferenceChunk(uint64_t offset) const217 StringItf * ReferenceItf :: getReferenceChunk ( uint64_t offset ) const 218 NGS_THROWS ( ErrorMsg ) 219 { 220 return this -> getReferenceChunk ( offset, -1 ); 221 } 222 getReferenceChunk(uint64_t offset,uint64_t length) const223 StringItf * ReferenceItf :: getReferenceChunk ( uint64_t offset, uint64_t length ) const 224 NGS_THROWS ( ErrorMsg ) 225 { 226 // the object is really from C 227 const NGS_Reference_v1 * self = Test (); 228 229 // cast vtable to our level 230 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 231 232 // call through C vtable 233 ErrBlock err; 234 assert ( vt -> get_ref_chunk != 0 ); 235 NGS_String_v1 * ret = ( * vt -> get_ref_chunk ) ( self, & err, offset, length ); 236 237 // check for errors 238 err . Check (); 239 240 return StringItf :: Cast ( ret ); 241 } 242 243 getAlignmentCount() const244 uint64_t ReferenceItf :: getAlignmentCount () const 245 NGS_THROWS ( ErrorMsg ) 246 { 247 return this -> getAlignmentCount ( Alignment :: all ); 248 } 249 250 getAlignmentCount(uint32_t categories) const251 uint64_t ReferenceItf :: getAlignmentCount ( uint32_t categories ) const 252 NGS_THROWS ( ErrorMsg ) 253 { 254 // the object is really from C 255 const NGS_Reference_v1 * self = Test (); 256 257 // cast vtable to our level 258 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 259 260 // test for v1.2 261 if ( vt -> dad . minor_version < 2 ) 262 throw ErrorMsg ( "the Reference interface provided by this NGS engine is too old to support this message" ); 263 264 // test for bad categories 265 // this should not be possible in C++, but it is possible from other bindings 266 if ( categories == 0 ) 267 categories = Alignment :: primaryAlignment; 268 269 // call through C vtable 270 ErrBlock err; 271 assert ( vt -> get_align_count != 0 ); 272 bool wants_primary = ( categories & Alignment :: primaryAlignment ) != 0; 273 bool wants_secondary = ( categories & Alignment :: secondaryAlignment ) != 0; 274 uint64_t ret = ( * vt -> get_align_count ) ( self, & err, wants_primary, wants_secondary ); 275 276 // check for errors 277 err . Check (); 278 279 return ret; 280 } 281 getAlignment(const char * alignmentId) const282 AlignmentItf * ReferenceItf :: getAlignment ( const char * alignmentId ) const 283 NGS_THROWS ( ErrorMsg ) 284 { 285 // the object is really from C 286 const NGS_Reference_v1 * self = Test (); 287 288 // cast vtable to our level 289 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 290 291 // call through C vtable 292 ErrBlock err; 293 assert ( vt -> get_alignment != 0 ); 294 NGS_Alignment_v1 * ret = ( * vt -> get_alignment ) ( self, & err, alignmentId ); 295 296 // check for errors 297 err . Check (); 298 299 return AlignmentItf :: Cast ( ret ); 300 } 301 getAlignments(uint32_t categories) const302 AlignmentItf * ReferenceItf :: getAlignments ( uint32_t categories ) const 303 NGS_THROWS ( ErrorMsg ) 304 { 305 // the object is really from C 306 const NGS_Reference_v1 * self = Test (); 307 308 // cast vtable to our level 309 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 310 311 // test for bad categories 312 // this should not be possible in C++, but it is possible from other bindings 313 if ( categories == 0 ) 314 categories = Alignment :: primaryAlignment; 315 316 // call through C vtable 317 ErrBlock err; 318 assert ( vt -> get_alignments != 0 ); 319 bool wants_primary = ( categories & Alignment :: primaryAlignment ) != 0; 320 bool wants_secondary = ( categories & Alignment :: secondaryAlignment ) != 0; 321 NGS_Alignment_v1 * ret = ( * vt -> get_alignments ) ( self, & err, wants_primary, wants_secondary ); 322 323 // check for errors 324 err . Check (); 325 326 return AlignmentItf :: Cast ( ret ); 327 } 328 329 getAlignmentSlice(int64_t start,uint64_t length) const330 AlignmentItf * ReferenceItf :: getAlignmentSlice ( int64_t start, uint64_t length ) const 331 NGS_THROWS ( ErrorMsg ) 332 { 333 return this -> getAlignmentSlice ( start, length, Alignment :: all ); 334 } 335 getAlignmentSlice(int64_t start,uint64_t length,uint32_t categories) const336 AlignmentItf * ReferenceItf :: getAlignmentSlice ( int64_t start, uint64_t length, uint32_t categories ) const 337 NGS_THROWS ( ErrorMsg ) 338 { 339 // the object is really from C 340 const NGS_Reference_v1 * self = Test (); 341 342 // cast vtable to our level 343 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 344 345 // test for bad categories 346 // this should not be possible in C++, but it is possible from other bindings 347 if ( categories == 0 ) 348 categories = Alignment :: primaryAlignment; 349 350 // call through C vtable 351 ErrBlock err; 352 assert ( vt -> get_align_slice != 0 ); 353 bool wants_primary = ( categories & Alignment :: primaryAlignment ) != 0; 354 bool wants_secondary = ( categories & Alignment :: secondaryAlignment ) != 0; 355 NGS_Alignment_v1 * ret = ( * vt -> get_align_slice ) ( self, & err, start, length, wants_primary, wants_secondary ); 356 357 // check for errors 358 err . Check (); 359 360 return AlignmentItf :: Cast ( ret ); 361 } 362 getFilteredAlignmentSlice(int64_t start,uint64_t length,uint32_t categories,uint32_t filters,int32_t mappingQuality) const363 AlignmentItf * ReferenceItf :: getFilteredAlignmentSlice ( int64_t start, uint64_t length, uint32_t categories, uint32_t filters, int32_t mappingQuality ) const 364 NGS_THROWS ( ErrorMsg ) 365 { 366 // the object is really from C 367 const NGS_Reference_v1 * self = Test (); 368 369 // test for conflicting filters 370 const uint32_t conflictingMapQuality = Alignment :: minMapQuality | Alignment :: maxMapQuality; 371 if ( ( filters & conflictingMapQuality ) == conflictingMapQuality ) 372 throw ErrorMsg ( "mapping quality can only be used as a minimum or maximum value, not both" ); 373 374 // cast vtable to our level 375 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 376 377 // test for bad categories 378 // this should not be possible in C++, but it is possible from other bindings 379 if ( categories == 0 ) 380 categories = Alignment :: primaryAlignment; 381 382 // test for v1.3 383 if ( vt -> dad . minor_version < 3 ) 384 throw ErrorMsg ( "the Reference interface provided by this NGS engine is too old to support this message" ); 385 386 // call through C vtable 387 ErrBlock err; 388 assert ( vt -> get_filtered_align_slice != 0 ); 389 uint32_t flags = make_flags ( categories, filters ); 390 NGS_Alignment_v1 * ret = ( * vt -> get_filtered_align_slice ) ( self, & err, start, length, flags, mappingQuality ); 391 392 // check for errors 393 err . Check (); 394 395 return AlignmentItf :: Cast ( ret ); 396 } 397 getPileups(uint32_t categories) const398 PileupItf * ReferenceItf :: getPileups ( uint32_t categories ) const 399 NGS_THROWS ( ErrorMsg ) 400 { 401 // the object is really from C 402 const NGS_Reference_v1 * self = Test (); 403 404 // cast vtable to our level 405 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 406 407 // test for bad categories 408 // this should not be possible in C++, but it is possible from other bindings 409 if ( categories == 0 ) 410 categories = Alignment :: primaryAlignment; 411 412 // call through C vtable 413 ErrBlock err; 414 assert ( vt -> get_pileups != 0 ); 415 bool wants_primary = ( categories & Alignment :: primaryAlignment ) != 0; 416 bool wants_secondary = ( categories & Alignment :: secondaryAlignment ) != 0; 417 NGS_Pileup_v1 * ret = ( * vt -> get_pileups ) ( self, & err, wants_primary, wants_secondary ); 418 419 // check for errors 420 err . Check (); 421 422 return PileupItf :: Cast ( ret ); 423 } 424 getFilteredPileups(uint32_t categories,uint32_t filters,int32_t mappingQuality) const425 PileupItf * ReferenceItf :: getFilteredPileups ( uint32_t categories, uint32_t filters, int32_t mappingQuality ) const 426 NGS_THROWS ( ErrorMsg ) 427 { 428 // the object is really from C 429 const NGS_Reference_v1 * self = Test (); 430 431 // test for conflicting filters 432 const uint32_t conflictingMapQuality = Alignment :: minMapQuality | Alignment :: maxMapQuality; 433 if ( ( filters & conflictingMapQuality ) == conflictingMapQuality ) 434 throw ErrorMsg ( "mapping quality can only be used as a minimum or maximum value, not both" ); 435 436 // cast vtable to our level 437 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 438 439 // test for v1.1 440 if ( vt -> dad . minor_version < 1 ) 441 throw ErrorMsg ( "the Reference interface provided by this NGS engine is too old to support this message" ); 442 443 // test for bad categories 444 // this should not be possible in C++, but it is possible from other bindings 445 if ( categories == 0 ) 446 categories = Alignment :: primaryAlignment; 447 448 // call through C vtable 449 ErrBlock err; 450 assert ( vt -> get_filtered_pileups != 0 ); 451 uint32_t flags = make_flags ( categories, filters ); 452 NGS_Pileup_v1 * ret = ( * vt -> get_filtered_pileups ) ( self, & err, flags, mappingQuality ); 453 454 // check for errors 455 err . Check (); 456 457 return PileupItf :: Cast ( ret ); 458 } 459 getPileupSlice(int64_t start,uint64_t length) const460 PileupItf * ReferenceItf :: getPileupSlice ( int64_t start, uint64_t length ) const 461 NGS_THROWS ( ErrorMsg ) 462 { 463 return this -> getPileupSlice ( start, length, Alignment :: all ); 464 } 465 getPileupSlice(int64_t start,uint64_t length,uint32_t categories) const466 PileupItf * ReferenceItf :: getPileupSlice ( int64_t start, uint64_t length, uint32_t categories ) const 467 NGS_THROWS ( ErrorMsg ) 468 { 469 // the object is really from C 470 const NGS_Reference_v1 * self = Test (); 471 472 // cast vtable to our level 473 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 474 475 // test for bad categories 476 // this should not be possible in C++, but it is possible from other bindings 477 if ( categories == 0 ) 478 categories = Alignment :: primaryAlignment; 479 480 // call through C vtable 481 ErrBlock err; 482 assert ( vt -> get_pileup_slice != 0 ); 483 bool wants_primary = ( categories & Alignment :: primaryAlignment ) != 0; 484 bool wants_secondary = ( categories & Alignment :: secondaryAlignment ) != 0; 485 NGS_Pileup_v1 * ret = ( * vt -> get_pileup_slice ) ( self, & err, start, length, wants_primary, wants_secondary ); 486 487 // check for errors 488 err . Check (); 489 490 return PileupItf :: Cast ( ret ); 491 } 492 getFilteredPileupSlice(int64_t start,uint64_t length,uint32_t categories,uint32_t filters,int32_t mappingQuality) const493 PileupItf * ReferenceItf :: getFilteredPileupSlice ( int64_t start, uint64_t length, uint32_t categories, uint32_t filters, int32_t mappingQuality ) const 494 NGS_THROWS ( ErrorMsg ) 495 { 496 // the object is really from C 497 const NGS_Reference_v1 * self = Test (); 498 499 // test for conflicting filters 500 const uint32_t conflictingMapQuality = Alignment :: minMapQuality | Alignment :: maxMapQuality; 501 if ( ( filters & conflictingMapQuality ) == conflictingMapQuality ) 502 throw ErrorMsg ( "mapping quality can only be used as a minimum or maximum value, not both" ); 503 504 // cast vtable to our level 505 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 506 507 // test for v1.1 508 if ( vt -> dad . minor_version < 1 ) 509 throw ErrorMsg ( "the Reference interface provided by this NGS engine is too old to support this message" ); 510 511 // test for bad categories 512 // this should not be possible in C++, but it is possible from other bindings 513 if ( categories == 0 ) 514 categories = Alignment :: primaryAlignment; 515 516 // call through C vtable 517 ErrBlock err; 518 assert ( vt -> get_filtered_pileup_slice != 0 ); 519 uint32_t flags = make_flags ( categories, filters ); 520 NGS_Pileup_v1 * ret = ( * vt -> get_filtered_pileup_slice ) ( self, & err, start, length, flags, mappingQuality ); 521 522 // check for errors 523 err . Check (); 524 525 return PileupItf :: Cast ( ret ); 526 } 527 nextReference()528 bool ReferenceItf :: nextReference () 529 NGS_THROWS ( ErrorMsg ) 530 { 531 // the object is really from C 532 NGS_Reference_v1 * self = Test (); 533 534 // cast vtable to our level 535 const NGS_Reference_v1_vt * vt = Access ( self -> vt ); 536 537 // call through C vtable 538 ErrBlock err; 539 assert ( vt -> next != 0 ); 540 bool ret = ( * vt -> next ) ( self, & err ); 541 542 // check for errors 543 err . Check (); 544 545 return ret; 546 } 547 } 548 549