]> git.donarmstrong.com Git - bamtools.git/blob - src/api/internal/BamMultiMerger_p.h
Fix: unmapped reads now pushed to end of coordinate-sorted BAM
[bamtools.git] / src / api / internal / BamMultiMerger_p.h
1 // ***************************************************************************
2 // BamMultiMerger_p.h (c) 2010 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // ---------------------------------------------------------------------------
5 // Last modified: 28 September 2011 (DB)
6 // ---------------------------------------------------------------------------
7 // Provides merging functionality for BamMultiReader.  At this point, supports
8 // sorting results by (refId, position) or by read name.
9 // ***************************************************************************
10
11 #ifndef BAMMULTIMERGER_P_H
12 #define BAMMULTIMERGER_P_H
13
14 //  -------------
15 //  W A R N I N G
16 //  -------------
17 //
18 // This file is not part of the BamTools API.  It exists purely as an
19 // implementation detail. This header file may change from version to version
20 // without notice, or even be removed.
21 //
22 // We mean it.
23
24 #include <api/BamAlignment.h>
25 #include <api/BamReader.h>
26 #include <map>
27 #include <queue>
28 #include <string>
29 #include <utility>
30
31 namespace BamTools {
32 namespace Internal {
33
34 typedef std::pair<BamReader*, BamAlignment*> ReaderAlignment;
35
36 // generic MultiMerger interface
37 class IBamMultiMerger {
38
39     public:
40         IBamMultiMerger(void) { }
41         virtual ~IBamMultiMerger(void) { }
42
43     public:
44         virtual void Add(ReaderAlignment value) =0;
45         virtual void Clear(void) =0;
46         virtual const ReaderAlignment& First(void) const =0;
47         virtual bool IsEmpty(void) const =0;
48         virtual void Remove(BamReader* reader) =0;
49         virtual int Size(void) const =0;
50         virtual ReaderAlignment TakeFirst(void) =0;
51 };
52
53 // IBamMultiMerger implementation - sorted on BamAlignment: (RefId, Position)
54 class PositionMultiMerger : public IBamMultiMerger {
55
56     public:
57         PositionMultiMerger(void) : IBamMultiMerger() { }
58         ~PositionMultiMerger(void) { }
59
60     public:
61         void Add(ReaderAlignment value);
62         void Clear(void);
63         const ReaderAlignment& First(void) const;
64         bool IsEmpty(void) const;
65         void Remove(BamReader* reader);
66         int Size(void) const;
67         ReaderAlignment TakeFirst(void);
68
69     private:
70         typedef std::pair<int, int>           KeyType;
71         typedef ReaderAlignment               ValueType;
72         typedef std::pair<KeyType, ValueType> ElementType;
73
74         struct SortLessThanPosition {
75             bool operator() (const KeyType& lhs, const KeyType& rhs) {
76
77                 // force unmapped alignments to end
78                 if ( lhs.first == -1 ) return false;
79                 if ( rhs.first == -1 ) return true;
80
81                 // sort first on RefID, then by Position
82                 if ( lhs.first != rhs.first )
83                     return lhs.first < rhs.first;
84                 else
85                     return lhs.second < rhs.second;
86             }
87         };
88
89         typedef SortLessThanPosition Compare;
90
91         typedef std::multimap<KeyType, ValueType, Compare> ContainerType;
92         typedef ContainerType::iterator           DataIterator;
93         typedef ContainerType::const_iterator     DataConstIterator;
94
95         ContainerType m_data;
96 };
97
98 // IBamMultiMerger implementation - sorted on BamAlignment: Name
99 class ReadNameMultiMerger : public IBamMultiMerger {
100
101     public:
102         ReadNameMultiMerger(void) : IBamMultiMerger() { }
103         ~ReadNameMultiMerger(void) { }
104
105     public:
106         void Add(ReaderAlignment value);
107         void Clear(void);
108         const ReaderAlignment& First(void) const;
109         bool IsEmpty(void) const;
110         void Remove(BamReader* reader);
111         int Size(void) const;
112         ReaderAlignment TakeFirst(void);
113
114     private:
115         typedef std::string                   KeyType;
116         typedef ReaderAlignment               ValueType;
117         typedef std::pair<KeyType, ValueType> ElementType;
118
119         typedef std::multimap<KeyType, ValueType> ContainerType;
120         typedef ContainerType::iterator           DataIterator;
121         typedef ContainerType::const_iterator     DataConstIterator;
122
123         ContainerType m_data;
124 };
125
126 // IBamMultiMerger implementation - unsorted BAM file(s)
127 class UnsortedMultiMerger : public IBamMultiMerger {
128
129     public:
130         UnsortedMultiMerger(void) : IBamMultiMerger() { }
131         ~UnsortedMultiMerger(void) { }
132
133     public:
134         void Add(ReaderAlignment value);
135         void Clear(void);
136         const ReaderAlignment& First(void) const;
137         bool IsEmpty(void) const;
138         void Remove(BamReader* reader);
139         int Size(void) const;
140         ReaderAlignment TakeFirst(void);
141
142     private:
143         typedef ReaderAlignment ElementType;
144         typedef std::vector<ReaderAlignment>  ContainerType;
145         typedef ContainerType::iterator       DataIterator;
146         typedef ContainerType::const_iterator DataConstIterator;
147
148         ContainerType m_data;
149 };
150
151 // ------------------------------------------
152 // PositionMultiMerger implementation
153
154 inline void PositionMultiMerger::Add(ReaderAlignment value) {
155     const KeyType key( value.second->RefID, value.second->Position );
156     m_data.insert( ElementType(key, value) );
157 }
158
159 inline void PositionMultiMerger::Clear(void) {
160     m_data.clear();
161 }
162
163 inline const ReaderAlignment& PositionMultiMerger::First(void) const {
164     const ElementType& entry = (*m_data.begin());
165     return entry.second;
166 }
167
168 inline bool PositionMultiMerger::IsEmpty(void) const {
169     return m_data.empty();
170 }
171
172 inline void PositionMultiMerger::Remove(BamReader* reader) {
173
174     if ( reader == 0 ) return;
175     const std::string filenameToRemove = reader->GetFilename();
176
177     // iterate over readers in cache
178     DataIterator dataIter = m_data.begin();
179     DataIterator dataEnd  = m_data.end();
180     for ( ; dataIter != dataEnd; ++dataIter ) {
181         const ValueType& entry = (*dataIter).second;
182         const BamReader* entryReader = entry.first;
183         if ( entryReader == 0 ) continue;
184
185         // remove iterator on match
186         if ( entryReader->GetFilename() == filenameToRemove ) {
187             m_data.erase(dataIter);
188             return;
189         }
190     }
191 }
192
193 inline int PositionMultiMerger::Size(void) const {
194     return m_data.size();
195 }
196
197 inline ReaderAlignment PositionMultiMerger::TakeFirst(void) {
198     DataIterator first = m_data.begin();
199     ReaderAlignment next = (*first).second;
200     m_data.erase(first);
201     return next;
202 }
203
204 // ------------------------------------------
205 // ReadNameMultiMerger implementation
206
207 inline void ReadNameMultiMerger::Add(ReaderAlignment value) {
208     BamAlignment* al = value.second;
209     if ( al->BuildCharData() ) {
210         const KeyType key(al->Name);
211         m_data.insert( ElementType(key, value) );
212     }
213 }
214
215 inline void ReadNameMultiMerger::Clear(void) {
216     m_data.clear();
217 }
218
219 inline const ReaderAlignment& ReadNameMultiMerger::First(void) const {
220     const ElementType& entry = (*m_data.begin());
221     return entry.second;
222 }
223
224 inline bool ReadNameMultiMerger::IsEmpty(void) const {
225     return m_data.empty();
226 }
227
228 inline void ReadNameMultiMerger::Remove(BamReader* reader) {
229
230     if ( reader == 0 ) return;
231     const std::string filenameToRemove = reader->GetFilename();
232
233     // iterate over readers in cache
234     DataIterator dataIter = m_data.begin();
235     DataIterator dataEnd  = m_data.end();
236     for ( ; dataIter != dataEnd; ++dataIter ) {
237         const ValueType& entry = (*dataIter).second;
238         const BamReader* entryReader = entry.first;
239         if ( entryReader == 0 ) continue;
240
241         // remove iterator on match
242         if ( entryReader->GetFilename() == filenameToRemove ) {
243             m_data.erase(dataIter);
244             return;
245         }
246     }
247
248 }
249
250 inline int ReadNameMultiMerger::Size(void) const {
251     return m_data.size();
252 }
253
254 inline ReaderAlignment ReadNameMultiMerger::TakeFirst(void) {
255     DataIterator first = m_data.begin();
256     ReaderAlignment next = (*first).second;
257     m_data.erase(first);
258     return next;
259 }
260
261 // ------------------------------------------
262 // UnsortedMultiMerger implementation
263
264 inline void UnsortedMultiMerger::Add(ReaderAlignment value) {
265     m_data.push_back(value);
266 }
267
268 inline void UnsortedMultiMerger::Clear(void) {
269     for (size_t i = 0; i < m_data.size(); ++i )
270         m_data.pop_back();
271 }
272
273 inline const ReaderAlignment& UnsortedMultiMerger::First(void) const {
274     return m_data.front();
275 }
276
277 inline bool UnsortedMultiMerger::IsEmpty(void) const {
278     return m_data.empty();
279 }
280
281 inline void UnsortedMultiMerger::Remove(BamReader* reader) {
282
283     if ( reader == 0 ) return;
284     const std::string filenameToRemove = reader->GetFilename();
285
286     // iterate over readers in cache
287     DataIterator dataIter = m_data.begin();
288     DataIterator dataEnd  = m_data.end();
289     for ( ; dataIter != dataEnd; ++dataIter ) {
290         const BamReader* entryReader = (*dataIter).first;
291         if ( entryReader == 0 ) continue;
292
293         // remove iterator on match
294         if ( entryReader->GetFilename() == filenameToRemove ) {
295             m_data.erase(dataIter);
296             return;
297         }
298     }
299 }
300
301 inline int UnsortedMultiMerger::Size(void) const {
302     return m_data.size();
303 }
304
305 inline ReaderAlignment UnsortedMultiMerger::TakeFirst(void) {
306     ReaderAlignment first = m_data.front();
307     m_data.erase( m_data.begin() );
308     return first;
309 }
310
311 } // namespace Internal
312 } // namespace BamTools
313
314 #endif // BAMMULTIMERGER_P_H