]> git.donarmstrong.com Git - bamtools.git/blobdiff - src/api/SamSequenceDictionary.cpp
Added explicit merge order to BamMultiReader
[bamtools.git] / src / api / SamSequenceDictionary.cpp
index c023a39d21e313970c5d5113215b0db3eb2fca1f..5d2ab642651d41be80de7ffda8626d82e47541bb 100644 (file)
-#include <api/SamSequenceDictionary.h>
+// ***************************************************************************
+// SamSequenceDictionary.cpp (c) 2010 Derek Barnett
+// Marth Lab, Department of Biology, Boston College
+// ---------------------------------------------------------------------------
+// Last modified: 16 October 2011 (DB)
+// ---------------------------------------------------------------------------
+// Provides methods for operating on a collection of SamSequence entries.
+// *************************************************************************
+
+#include "api/SamSequenceDictionary.h"
 using namespace BamTools;
 
 #include <iostream>
 using namespace std;
 
-// ctor
+/*! \class BamTools::SamSequenceDictionary
+    \brief Container of SamSequence entries.
+
+    Provides methods for operating on a collection of SamSequence entries.
+*/
+
+/*! \fn SamSequenceDictionary::SamSequenceDictionary(void)
+    \brief constructor
+*/
 SamSequenceDictionary::SamSequenceDictionary(void) { }
 
-// dtor
-SamSequenceDictionary::~SamSequenceDictionary(void) {
-    m_data.clear();
-}
+/*! \fn SamSequenceDictionary::SamSequenceDictionary(const SamSequenceDictionary& other)
+    \brief copy constructor
+*/
+SamSequenceDictionary::SamSequenceDictionary(const SamSequenceDictionary& other)
+    : m_data(other.m_data)
+    , m_lookupData(other.m_lookupData)
+{ }
+
+/*! \fn SamSequenceDictionary::~SamSequenceDictionary(void)
+    \brief destructor
+*/
+SamSequenceDictionary::~SamSequenceDictionary(void) { }
+
+/*! \fn void SamSequenceDictionary::Add(const SamSequence& sequence)
+    \brief Appends a sequence to the dictionary.
 
-// adds sequence if not already in container
+    Duplicate entries are silently discarded.
+
+    \param[in] sequence entry to be added
+*/
 void SamSequenceDictionary::Add(const SamSequence& sequence) {
-    if ( IsEmpty() || !Contains(sequence) )
+    if ( IsEmpty() || !Contains(sequence) ) {
         m_data.push_back(sequence);
+        m_lookupData[sequence.Name] = m_data.size() - 1;
+    }
 }
 
-// overload to support std::string
-void SamSequenceDictionary::Add(const string& sequenceName) {
-    Add( SamSequence(sequenceName) );
+/*! \fn void SamSequenceDictionary::Add(const std::string& name, const int& length)
+    \brief Appends a sequence to the dictionary.
+
+    This is an overloaded function.
+
+    \param[in] name name of sequence entry to be added
+    \param[in] length length of sequence entry to be added
+    \sa Add()
+*/
+void SamSequenceDictionary::Add(const std::string& name, const int& length) {
+    Add( SamSequence(name, length) );
 }
 
-// add multiple sequences
-void SamSequenceDictionary::Add(const vector<SamSequence>& sequences) {
-    vector<SamSequence>::const_iterator rgIter = sequences.begin();
-    vector<SamSequence>::const_iterator rgEnd  = sequences.end();
-    for ( ; rgIter!= rgEnd; ++rgIter )
-        Add(*rgIter);
+/*! \fn void SamSequenceDictionary::Add(const SamSequenceDictionary& sequences)
+    \brief Appends another sequence dictionary to this one
+
+    This is an overloaded function.
+
+    \param[in] sequences sequence dictionary to be appended
+    \sa Add()
+*/
+void SamSequenceDictionary::Add(const SamSequenceDictionary& sequences) {
+    SamSequenceConstIterator seqIter = sequences.ConstBegin();
+    SamSequenceConstIterator seqEnd  = sequences.ConstEnd();
+    for ( ; seqIter != seqEnd; ++seqIter )
+        Add(*seqIter);
 }
 
-// overload to support std::string
-void SamSequenceDictionary::Add(const vector<string>& sequenceNames) {
-    vector<string>::const_iterator rgIter = sequenceNames.begin();
-    vector<string>::const_iterator rgEnd  = sequenceNames.end();
-    for ( ; rgIter!= rgEnd; ++rgIter )
-        Add(*rgIter);
+/*! \fn void SamSequenceDictionary::Add(const std::vector<SamSequence>& sequences)
+    \brief Appends multiple sequences to the dictionary.
+
+    This is an overloaded function.
+
+    \param[in] sequences entries to be added
+    \sa Add()
+*/
+void SamSequenceDictionary::Add(const std::vector<SamSequence>& sequences) {
+    vector<SamSequence>::const_iterator seqIter = sequences.begin();
+    vector<SamSequence>::const_iterator seqEnd  = sequences.end();
+    for ( ; seqIter!= seqEnd; ++seqIter )
+        Add(*seqIter);
+}
+
+/*! \fn void SamSequenceDictionary::Add(const std::map<std::string, int>& sequenceMap)
+    \brief Appends multiple sequences to the dictionary.
+
+    This is an overloaded function.
+
+    \param[in] sequenceMap map of sequence entries (name => length) to be added
+    \sa Add()
+*/
+void SamSequenceDictionary::Add(const std::map<std::string, int>& sequenceMap) {
+    map<string, int>::const_iterator seqIter = sequenceMap.begin();
+    map<string, int>::const_iterator seqEnd  = sequenceMap.end();
+    for ( ; seqIter != seqEnd; ++seqIter ) {
+        const string& name = (*seqIter).first;
+        const int& length = (*seqIter).second;
+        Add( SamSequence(name, length) );
+    }
 }
 
-// returns iterator to container begin
+/*! \fn SamSequenceIterator SamSequenceDictionary::Begin(void)
+    \return an STL iterator pointing to the first sequence
+    \sa ConstBegin(), End()
+*/
 SamSequenceIterator SamSequenceDictionary::Begin(void) {
     return m_data.begin();
 }
 
-// returns const_iterator to container begin
+/*! \fn SamSequenceConstIterator SamSequenceDictionary::Begin(void) const
+    \return an STL const_iterator pointing to the first sequence
+
+    This is an overloaded function.
+
+    \sa ConstBegin(), End()
+*/
 SamSequenceConstIterator SamSequenceDictionary::Begin(void) const {
     return m_data.begin();
 }
 
-// clear sequence container
+/*! \fn void SamSequenceDictionary::Clear(void)
+    \brief Clears all sequence entries.
+*/
 void SamSequenceDictionary::Clear(void) {
     m_data.clear();
+    m_lookupData.clear();
 }
 
-// explicit request for const_iterator to container begin
+/*! \fn SamSequenceConstIterator SamSequenceDictionary::ConstBegin(void) const
+    \return an STL const_iterator pointing to the first sequence
+    \sa Begin(), ConstEnd()
+*/
 SamSequenceConstIterator SamSequenceDictionary::ConstBegin(void) const {
     return m_data.begin();
 }
 
-// explicit request for const_iterator to container end
+/*! \fn SamSequenceConstIterator SamSequenceDictionary::ConstEnd(void) const
+    \return an STL const_iterator pointing to the imaginary entry after the last sequence
+    \sa End(), ConstBegin()
+*/
 SamSequenceConstIterator SamSequenceDictionary::ConstEnd(void) const {
     return m_data.end();
 }
 
-// returns true if container contains a sequence with this ID tag
-bool SamSequenceDictionary::Contains(const string& sequenceName) const {
-    return ( IndexOf(sequenceName) != (int)m_data.size() );
+/*! \fn bool SamSequenceDictionary::Contains(const std::string& sequenceName) const
+    \brief Returns true if dictionary contains sequence.
+
+    \param[in] sequenceName search for sequence matching this name
+    \return \c true if dictionary contains a sequence with this name
+*/
+bool SamSequenceDictionary::Contains(const std::string& sequenceName) const {
+    return ( m_lookupData.find(sequenceName) != m_lookupData.end() );
 }
 
-bool SamSequenceDictionary::Contains(const SamSequence& seq) const {
-    return ( IndexOf(seq) != (int)m_data.size() );
+/*! \fn bool SamSequenceDictionary::Contains(const SamSequence& sequence) const
+    \brief Returns true if dictionary contains sequence (matches on name).
+
+    This is an overloaded function.
+
+    \param[in] sequence search for this sequence
+    \return \c true if dictionary contains sequence (matching on name)
+*/
+bool SamSequenceDictionary::Contains(const SamSequence& sequence) const {
+    return Contains(sequence.Name);
 }
 
-// returns iterator to container end
+/*! \fn SamSequenceIterator SamSequenceDictionary::End(void)
+    \return an STL iterator pointing to the imaginary entry after the last sequence
+    \sa Begin(), ConstEnd()
+*/
 SamSequenceIterator SamSequenceDictionary::End(void) {
     return m_data.end();
 }
 
-// returns const_iterator to container begin
-SamSequenceConstIterator SamSequenceDictionary::End(void) const {
-    return m_data.end();
-}
+/*! \fn SamSequenceConstIterator SamSequenceDictionary::End(void) const
+    \return an STL const_iterator pointing to the imaginary entry after the last sequence
 
-// returns vector index of sequence if found
-// returns vector::size() (invalid index) if not found
-int SamSequenceDictionary::IndexOf(const SamSequence& sequence) const {
-    SamSequenceConstIterator begin = ConstBegin();
-    SamSequenceConstIterator iter  = begin;
-    SamSequenceConstIterator end   = ConstEnd();
-    for ( ; iter != end; ++iter )
-        if ( *iter == sequence ) break;
-    return distance( begin, iter );
-}
+    This is an overloaded function.
 
-// overload to support std::string
-int SamSequenceDictionary::IndexOf(const string& sequenceName) const {
-    return IndexOf( SamSequence(sequenceName) );
+    \sa Begin(), ConstEnd()
+*/
+SamSequenceConstIterator SamSequenceDictionary::End(void) const {
+    return m_data.end();
 }
 
-// returns true if container is empty
+/*! \fn bool SamSequenceDictionary::IsEmpty(void) const
+    \brief Returns \c true if dictionary contains no sequences
+    \sa Size()
+*/
 bool SamSequenceDictionary::IsEmpty(void) const {
     return m_data.empty();
 }
 
-// removes sequence (if it exists)
+/*! \fn void SamSequenceDictionary::Remove(const SamSequence& sequence)
+    \brief Removes sequence from dictionary, if found (matches on name).
+
+    This is an overloaded function.
+
+    \param[in] sequence SamSequence to remove (matching on name)
+*/
 void SamSequenceDictionary::Remove(const SamSequence& sequence) {
-    if ( Contains(sequence) )
-        m_data.erase( m_data.begin() + IndexOf(sequence) );
+    Remove(sequence.Name);
 }
 
-// overlaod to support std::string
-void SamSequenceDictionary::Remove(const string& sequenceName) {
-    Remove( SamSequence(sequenceName) );
+/*! \fn void SamSequenceDictionary::Remove(const std::string& sequenceName)
+    \brief Removes sequence from dictionary, if found.
+
+    \param[in] sequenceName name of sequence to remove
+    \sa Remove()
+*/
+void SamSequenceDictionary::Remove(const std::string& sequenceName) {
+
+    // skip if empty dictionary or if name unknown
+    if ( IsEmpty() || !Contains(sequenceName) )
+        return;
+
+    // update 'lookup index' for every entry after @sequenceName
+    const size_t indexToRemove = m_lookupData[sequenceName];
+    const size_t numEntries = m_data.size();
+    for ( size_t i = indexToRemove+1; i < numEntries; ++i ) {
+        const SamSequence& sq = m_data.at(i);
+        --m_lookupData[sq.Name];
+    }
+
+    // erase entry from containers
+    m_data.erase( Begin() + indexToRemove );
+    m_lookupData.erase(sequenceName);
 }
 
-// remove multiple sequences
-void SamSequenceDictionary::Remove(const vector<SamSequence>& sequences) {
+/*! \fn void SamSequenceDictionary::Remove(const std::vector<SamSequence>& sequences)
+    \brief Removes multiple sequences from dictionary.
+
+    This is an overloaded function.
+
+    \param[in] sequences sequences to remove
+    \sa Remove()
+*/
+void SamSequenceDictionary::Remove(const std::vector<SamSequence>& sequences) {
     vector<SamSequence>::const_iterator rgIter = sequences.begin();
     vector<SamSequence>::const_iterator rgEnd  = sequences.end();
     for ( ; rgIter!= rgEnd; ++rgIter )
         Remove(*rgIter);
 }
 
-// overload to support std::string
-void SamSequenceDictionary::Remove(const vector<string>& sequenceNames) {
+/*! \fn void SamSequenceDictionary::Remove(const std::vector<std::string>& sequenceNames)
+    \brief Removes multiple sequences from dictionary.
+
+    This is an overloaded function.
+
+    \param[in] sequenceNames names of the sequences to remove
+    \sa Remove()
+*/
+void SamSequenceDictionary::Remove(const std::vector<std::string>& sequenceNames) {
     vector<string>::const_iterator rgIter = sequenceNames.begin();
     vector<string>::const_iterator rgEnd  = sequenceNames.end();
     for ( ; rgIter!= rgEnd; ++rgIter )
         Remove(*rgIter);
 }
 
-// returns size of container (number of current sequences)
+/*! \fn int SamSequenceDictionary::Size(void) const
+    \brief Returns number of sequences in dictionary.
+    \sa IsEmpty()
+*/
 int SamSequenceDictionary::Size(void) const {
     return m_data.size();
 }
 
-// retrieves the SamSequence object associated with this name
-// if sequenceName is unknown, a new SamSequence is created with this name (and invalid length 0)
-// and a reference to this new sequence entry is returned (like std::map)
-SamSequence& SamSequenceDictionary::operator[](const std::string& sequenceName) {
+/*! \fn SamSequence& SamSequenceDictionary::operator[](const std::string& sequenceName)
+    \brief Retrieves the modifiable SamSequence that matches \a sequenceName.
 
-    // look up sequence ID
-    int index = IndexOf(sequenceName);
+    \note If the dictionary contains no sequence matching this name, this function inserts
+    a new one with this name (length:0), and returns a reference to it. If you want to avoid
+    this insertion behavior, check the result of Contains() before using this operator.
 
-    // if found, return sequence at index
-    if ( index != (int)m_data.size() )
-        return m_data[index];
+    \param[in] sequenceName name of sequence to retrieve
+    \return a modifiable reference to the SamSequence associated with the name
+*/
+SamSequence& SamSequenceDictionary::operator[](const std::string& sequenceName) {
 
-    // otherwise, append new sequence and return reference
-    else {
-        SamSequence seq(sequenceName);
-        seq.Length = "0";
+    if ( !Contains(sequenceName) ) {
+        SamSequence seq(sequenceName, 0);
         m_data.push_back(seq);
-        return m_data.back();
+        m_lookupData[sequenceName] = m_data.size() - 1;
     }
-}
 
+    const size_t index = m_lookupData[sequenceName];
+    return m_data.at(index);
+}