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