]> git.donarmstrong.com Git - bamtools.git/blob - src/api/SamProgramChain.cpp
8213402f99bb2d2fc31d1e9e68042897310ad715
[bamtools.git] / src / api / SamProgramChain.cpp
1 // ***************************************************************************
2 // SamProgramChain.cpp (c) 2011 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // ---------------------------------------------------------------------------
5 // Last modified: 10 October 2011 (DB)
6 // ---------------------------------------------------------------------------
7 // Provides methods for operating on a SamProgram record "chain"
8 // ***************************************************************************
9
10 #include <api/SamProgramChain.h>
11 using namespace BamTools;
12
13 #include <algorithm>
14 #include <iostream>
15 #include <cstdlib>
16 using namespace std;
17
18 /*! \class BamTools::SamProgramChain
19     \brief Sorted container "chain" of SamProgram records.
20
21     Provides methods for operating on a collection of SamProgram records.
22
23     \note Underlying container is *NOT* ordered by linkage, but by order of
24     appearance in SamHeader and subsequent Add() calls. Using the current
25     iterators will not allow you to step through the header's program history.
26     Instead use First()/Last() to access oldest/newest records, respectively.
27 */
28
29 /*! \fn SamProgramChain::SamProgramChain(void)
30     \brief constructor
31 */
32 SamProgramChain::SamProgramChain(void) { }
33
34 /*! \fn SamProgramChain::SamProgramChain(const SamProgramChain& other)
35     \brief copy constructor
36 */
37 SamProgramChain::SamProgramChain(const SamProgramChain& other)
38     : m_data(other.m_data)
39 { }
40
41 /*! \fn SamProgramChain::~SamProgramChain(void)
42     \brief destructor
43 */
44 SamProgramChain::~SamProgramChain(void) { }
45
46 /*! \fn void SamProgramChain::Add(SamProgram& program)
47     \brief Appends a program to program chain.
48
49     Duplicate entries are silently discarded.
50
51     \note Underlying container is *NOT* ordered by linkage, but by order of
52     appearance in SamHeader and subsequent Add() calls. Using the current
53     iterators will not allow you to step through the header's program history.
54     Instead use First()/Last() to access oldest/newest records, respectively.
55
56     \param[in] program entry to be appended
57 */
58 void SamProgramChain::Add(SamProgram& program) {
59
60     // ignore duplicated records
61     if ( Contains(program) )
62         return;
63
64     // if other programs already in chain, try to find the "next" record
65     // tries to match another record's PPID with @program's ID
66     if ( !IsEmpty() )
67         program.NextProgramID = NextIdFor(program.ID);
68
69     // store program record
70     m_data.push_back(program);
71 }
72
73 /*! \fn void SamProgramChain::Add(std::vector<SamProgram>& programs)
74     \brief Appends a batch of programs to the end of the chain.
75
76     This is an overloaded function.
77
78     \param[in] programs batch of program records to append
79     \sa Add()
80 */
81 void SamProgramChain::Add(std::vector<SamProgram>& programs) {
82     vector<SamProgram>::iterator pgIter = programs.begin();
83     vector<SamProgram>::iterator pgEnd  = programs.end();
84     for ( ; pgIter != pgEnd; ++pgIter )
85         Add(*pgIter);
86 }
87
88 /*! \fn SamProgramIterator SamProgramChain::Begin(void)
89     \return an STL iterator pointing to the first (oldest) program record
90     \sa ConstBegin(), End(), First()
91 */
92 SamProgramIterator SamProgramChain::Begin(void) {
93     return m_data.begin();
94 }
95
96 /*! \fn SamProgramConstIterator SamProgramChain::Begin(void) const
97     \return an STL const_iterator pointing to the first (oldest) program record
98
99     This is an overloaded function.
100
101     \sa ConstBegin(), End(), First()
102 */
103 SamProgramConstIterator SamProgramChain::Begin(void) const {
104     return m_data.begin();
105 }
106
107 /*! \fn void SamProgramChain::Clear(void)
108     \brief Clears all program records.
109 */
110 void SamProgramChain::Clear(void) {
111     m_data.clear();
112 }
113
114 /*! \fn SamProgramConstIterator SamProgramChain::ConstBegin(void) const
115     \return an STL const_iterator pointing to the first (oldest) program record
116     \sa Begin(), ConstEnd(), First()
117 */
118 SamProgramConstIterator SamProgramChain::ConstBegin(void) const {
119     return m_data.begin();
120 }
121
122 /*! \fn SamProgramConstIterator SamProgramChain::ConstEnd(void) const
123     \return an STL const_iterator pointing to the imaginary entry after the last (newest) program record
124     \sa ConstBegin(), End(), Last()
125 */
126 SamProgramConstIterator SamProgramChain::ConstEnd(void) const {
127     return m_data.end();
128 }
129
130 /*! \fn bool SamProgramChain::Contains(const SamProgram& program) const
131     \brief Returns true if chains has this program record (matching on ID).
132
133     This is an overloaded function.
134
135     \param[in] program SamProgram to search for
136     \return \c true if chain contains program (matching on ID)
137 */
138 bool SamProgramChain::Contains(const SamProgram& program) const {
139     return Contains(program.ID);
140 }
141
142 /*! \fn bool SamProgramChain::Contains(const std::string& programId) const
143     \brief Returns true if chains has a program record with this ID
144
145     \param[in] programId search for program matching this ID
146     \return \c true if chain contains a program record with this ID
147 */
148 bool SamProgramChain::Contains(const std::string& programId) const {
149     return ( IndexOf(programId) != (int)m_data.size() );
150 }
151
152 /*! \fn SamProgramIterator SamProgramChain::End(void)
153     \return an STL iterator pointing to the imaginary entry after the last (newest) program record
154     \sa Begin(), ConstEnd(), Last()
155 */
156 SamProgramIterator SamProgramChain::End(void) {
157     return m_data.end();
158 }
159
160 /*! \fn SamProgramConstIterator SamProgramChain::End(void) const
161     \return an STL const_iterator pointing to the imaginary entry after the last (newest) program record
162
163     This is an overloaded function.
164
165     \sa Begin(), ConstEnd(), Last()
166 */
167 SamProgramConstIterator SamProgramChain::End(void) const {
168     return m_data.end();
169 }
170
171 /*! \fn SamProgram& SamProgramChain::First(void)
172     \brief Fetches first (oldest) record in the chain.
173
174     \warning This function will fail if the chain is empty. If this is possible,
175     check the result of IsEmpty() before calling this function.
176
177     \return a modifiable reference to the first (oldest) program entry
178     \sa Begin(), Last()
179 */
180 SamProgram& SamProgramChain::First(void) {
181
182     // find first record in container that has no PreviousProgramID entry
183     SamProgramIterator iter = Begin();
184     SamProgramIterator end  = End();
185     for ( ; iter != end; ++iter ) {
186         SamProgram& current = (*iter);
187         if ( !current.HasPreviousProgramID() )
188             return current;
189     }
190
191     // otherwise error
192     cerr << "SamProgramChain::First: could not find any record without a PP tag" << endl;
193     exit(1);
194 }
195
196 /*! \fn const SamProgram& SamProgramChain::First(void) const
197     \brief Fetches first (oldest) record in the chain.
198
199     This is an overloaded function.
200
201     \warning This function will fail if the chain is empty. If this is possible,
202     check the result of IsEmpty() before calling this function.
203
204     \return a read-only reference to the first (oldest) program entry
205     \sa Begin(), ConstBegin(), Last()
206 */
207 const SamProgram& SamProgramChain::First(void) const {
208
209     // find first record in container that has no PreviousProgramID entry
210     SamProgramConstIterator iter = ConstBegin();
211     SamProgramConstIterator end  = ConstEnd();
212     for ( ; iter != end; ++iter ) {
213         const SamProgram& current = (*iter);
214         if ( !current.HasPreviousProgramID() )
215             return current;
216     }
217
218     // otherwise error
219     cerr << "SamProgramChain::First: could not find any record without a PP tag" << endl;
220     exit(1);
221 }
222
223 /*! \fn int SamProgramChain::IndexOf(const std::string& programId) const
224     \internal
225     \return index of program record if found.
226     Otherwise, returns vector::size() (invalid index).
227 */
228 int SamProgramChain::IndexOf(const std::string& programId) const {
229     SamProgramConstIterator begin = ConstBegin();
230     SamProgramConstIterator iter  = begin;
231     SamProgramConstIterator end   = ConstEnd();
232     for ( ; iter != end; ++iter ) {
233         const SamProgram& current = (*iter);
234         if ( current.ID == programId )
235             break;
236     }
237     return distance( begin, iter );
238 }
239
240 /*! \fn bool SamProgramChain::IsEmpty(void) const
241     \brief Returns \c true if chain contains no records
242     \sa Size()
243 */
244 bool SamProgramChain::IsEmpty(void) const {
245     return m_data.empty();
246 }
247
248 /*! \fn SamProgram& SamProgramChain::Last(void)
249     \brief Fetches last (newest) record in the chain.
250
251     \warning This function will fail if the chain is empty. If this is possible,
252     check the result of IsEmpty() before calling this function.
253
254     \return a modifiable reference to the last (newest) program entry
255     \sa End(), First()
256 */
257 SamProgram& SamProgramChain::Last(void) {
258     // find first record in container that has no NextProgramID entry
259     SamProgramIterator iter = Begin();
260     SamProgramIterator end  = End();
261     for ( ; iter != end; ++iter ) {
262         SamProgram& current = (*iter);
263         if ( !current.HasNextProgramID() )
264             return current;
265     }
266
267     // otherwise error
268     cerr << "SamProgramChain::Last: could not determine last record" << endl;
269     exit(1);
270 }
271
272 /*! \fn const SamProgram& SamProgramChain::Last(void) const
273     \brief Fetches last (newest) record in the chain.
274
275     This is an overloaded function.
276
277     \warning This function will fail if the chain is empty. If this is possible,
278     check the result of IsEmpty() before calling this function.
279
280     \return a read-only reference to the last (newest) program entry
281     \sa End(), ConstEnd(), First()
282 */
283 const SamProgram& SamProgramChain::Last(void) const {
284     // find first record in container that has no NextProgramID entry
285     SamProgramConstIterator iter = ConstBegin();
286     SamProgramConstIterator end  = ConstEnd();
287     for ( ; iter != end; ++iter ) {
288         const SamProgram& current = (*iter);
289         if ( !current.HasNextProgramID() )
290             return current;
291     }
292
293     // otherwise error
294     cerr << "SamProgramChain::Last: could not determine last record" << endl;
295     exit(1);
296 }
297
298 /*! \fn const std::string SamProgramChain::NextIdFor(const std::string& programId) const
299     \internal
300
301     \return ID of program record, whose PreviousProgramID matches \a programId.
302     Otherwise, returns empty string if none found.
303 */
304 const std::string SamProgramChain::NextIdFor(const std::string& programId) const {
305
306     // find first record in container whose PreviousProgramID matches @programId
307     SamProgramConstIterator iter = ConstBegin();
308     SamProgramConstIterator end  = ConstEnd();
309     for ( ; iter != end; ++iter ) {
310         const SamProgram& current = (*iter);
311         if ( !current.HasPreviousProgramID() &&
312               current.PreviousProgramID == programId
313            )
314         {
315             return current.ID;
316         }
317     }
318
319     // none found
320     return string();
321 }
322
323 /*! \fn int SamProgramChain::Size(void) const
324     \brief Returns number of program records in the chain.
325     \sa IsEmpty()
326 */
327 int SamProgramChain::Size(void) const {
328     return m_data.size();
329 }
330
331 /*! \fn SamProgram& SamProgramChain::operator[](const std::string& programId)
332     \brief Retrieves the modifiable SamProgram record that matches \a programId.
333
334     \warning If the chain contains no read group matching this ID, this function will
335     print an error and terminate. Check the return value of Contains() if this may be
336     possible.
337
338     \param[in] programId ID of program record to retrieve
339     \return a modifiable reference to the SamProgram associated with the ID
340 */
341 SamProgram& SamProgramChain::operator[](const std::string& programId) {
342
343     // look up program record matching this ID
344     int index = IndexOf(programId);
345
346     // if record not found
347     if ( index == (int)m_data.size() ) {
348         cerr << "SamProgramChain::operator[] - unknown programId: " << programId << endl;
349         exit(1);
350     }
351
352     // otherwise return program record at index
353     return m_data.at(index);
354 }