]> git.donarmstrong.com Git - bamtools.git/blobdiff - src/api/SamReadGroupDictionary.cpp
Merge branch 'master' of https://github.com/pezmaster31/bamtools
[bamtools.git] / src / api / SamReadGroupDictionary.cpp
index e6f8a056bec3e4ea72c6c26465c318aeb6f99108..007221a7cd030e0fd2a1d68e8086340d95a7e8e0 100644 (file)
@@ -1,17 +1,15 @@
 // ***************************************************************************
 // SamReadGroupDictionary.cpp (c) 2010 Derek Barnett
 // Marth Lab, Department of Biology, Boston College
-// All rights reserved.
 // ---------------------------------------------------------------------------
-// Last modified: 4 March 2011 (DB)
+// Last modified: 16 October 2011 (DB)
 // ---------------------------------------------------------------------------
 // Provides methods for operating on a collection of SamReadGroup entries.
 // ***************************************************************************
 
-#include <api/SamReadGroupDictionary.h>
+#include "api/SamReadGroupDictionary.h"
 using namespace BamTools;
 
-#include <algorithm>
 #include <iostream>
 using namespace std;
 
@@ -31,6 +29,7 @@ SamReadGroupDictionary::SamReadGroupDictionary(void) { }
 */
 SamReadGroupDictionary::SamReadGroupDictionary(const SamReadGroupDictionary& other)
     : m_data(other.m_data)
+    , m_lookupData(other.m_lookupData)
 { }
 
 /*! \fn SamReadGroupDictionary::~SamReadGroupDictionary(void)
@@ -39,35 +38,52 @@ SamReadGroupDictionary::SamReadGroupDictionary(const SamReadGroupDictionary& oth
 SamReadGroupDictionary::~SamReadGroupDictionary(void) { }
 
 /*! \fn void SamReadGroupDictionary::Add(const SamReadGroup& readGroup)
-    \brief Adds a read group to the dictionary.
+    \brief Appends a read group to the dictionary.
 
-    Duplicate entries are discarded.
+    Duplicate entries are silently discarded.
 
-    \param readGroup entry to be added
+    \param[in] readGroup entry to be added
 */
 void SamReadGroupDictionary::Add(const SamReadGroup& readGroup) {
-    if ( IsEmpty() || !Contains(readGroup) )
+    if ( IsEmpty() || !Contains(readGroup) ) {
         m_data.push_back(readGroup);
+        m_lookupData[readGroup.ID] = m_data.size() - 1;
+    }
 }
 
 /*! \fn void SamReadGroupDictionary::Add(const std::string& readGroupId)
-    \brief Adds a read group to the dictionary.
+    \brief Appends a read group to the dictionary.
 
     This is an overloaded function.
 
-    \param readGroupId ID of read group to be added
+    \param[in] readGroupId ID of read group to be added
     \sa Add()
 */
 void SamReadGroupDictionary::Add(const std::string& readGroupId) {
     Add( SamReadGroup(readGroupId) );
 }
 
+/*! \fn void SamReadGroupDictionary::Add(const SamReadGroupDictionary& readGroups)
+    \brief Appends another read group dictionary to this one.
+
+    This is an overloaded function.
+
+    \param[in] readGroups entries to be added
+    \sa Add()
+*/
+void SamReadGroupDictionary::Add(const SamReadGroupDictionary& readGroups) {
+    SamReadGroupConstIterator rgIter = readGroups.ConstBegin();
+    SamReadGroupConstIterator rgEnd  = readGroups.ConstEnd();
+    for ( ; rgIter != rgEnd; ++rgIter )
+        Add(*rgIter);
+}
+
 /*! \fn void SamReadGroupDictionary::Add(const std::vector<SamReadGroup>& readGroups)
-    \brief Adds multiple read groups to the dictionary.
+    \brief Appends multiple read groups to the dictionary.
 
     This is an overloaded function.
 
-    \param readGroups entries to be added
+    \param[in] readGroups entries to be added
     \sa Add()
 */
 void SamReadGroupDictionary::Add(const std::vector<SamReadGroup>& readGroups) {
@@ -78,11 +94,11 @@ void SamReadGroupDictionary::Add(const std::vector<SamReadGroup>& readGroups) {
 }
 
 /*! \fn void SamReadGroupDictionary::Add(const std::vector<std::string>& readGroupIds)
-    \brief Adds multiple read groups to the dictionary.
+    \brief Appends multiple read groups to the dictionary.
 
     This is an overloaded function.
 
-    \param readGroupIds IDs of read groups to be added
+    \param[in] readGroupIds IDs of read groups to be added
     \sa Add()
 */
 void SamReadGroupDictionary::Add(const std::vector<std::string>& readGroupIds) {
@@ -101,10 +117,10 @@ SamReadGroupIterator SamReadGroupDictionary::Begin(void) {
 }
 
 /*! \fn SamReadGroupConstIterator SamReadGroupDictionary::Begin(void) const
+    \return an STL const_iterator pointing to the first read group
 
     This is an overloaded function.
 
-    \return a const STL iterator pointing to the first read group
     \sa ConstBegin(), End()
 */
 SamReadGroupConstIterator SamReadGroupDictionary::Begin(void) const {
@@ -116,10 +132,11 @@ SamReadGroupConstIterator SamReadGroupDictionary::Begin(void) const {
 */
 void SamReadGroupDictionary::Clear(void) {
     m_data.clear();
+    m_lookupData.clear();
 }
 
 /*! \fn SamReadGroupConstIterator SamReadGroupDictionary::ConstBegin(void) const
-    \return a const STL iterator pointing to the first read group
+    \return an STL const_iterator pointing to the first read group
     \sa Begin(), ConstEnd()
 */
 SamReadGroupConstIterator SamReadGroupDictionary::ConstBegin(void) const {
@@ -127,7 +144,7 @@ SamReadGroupConstIterator SamReadGroupDictionary::ConstBegin(void) const {
 }
 
 /*! \fn SamReadGroupConstIterator SamReadGroupDictionary::ConstEnd(void) const
-    \return a const STL iterator pointing to the imaginary entry after the last read group
+    \return an STL const_iterator pointing to the imaginary entry after the last read group
     \sa ConstBegin(), End()
 */
 SamReadGroupConstIterator SamReadGroupDictionary::ConstEnd(void) const {
@@ -137,22 +154,23 @@ SamReadGroupConstIterator SamReadGroupDictionary::ConstEnd(void) const {
 /*! \fn bool SamReadGroupDictionary::Contains(const std::string& readGroupId) const
     \brief Returns true if dictionary contains read group.
 
-    This is an overloaded function.
-
-    \param readGroupId search for read group matching this ID
+    \param[in] readGroupId search for read group matching this ID
     \return \c true if dictionary contains a read group with this ID
 */
 bool SamReadGroupDictionary::Contains(const std::string& readGroupId) const {
-    return Contains( SamReadGroup(readGroupId) );
+    return ( m_lookupData.find(readGroupId) != m_lookupData.end() );
 }
 
 /*! \fn bool SamReadGroupDictionary::Contains(const SamReadGroup& readGroup) const
-    \brief Returns true if dictionary contains read group.
-    \param readGroup search for this read group
-    \return \c true if dictionary contains read group
+    \brief Returns true if dictionary contains read group (matching on ID).
+
+    This is an overloaded function.
+
+    \param[in] readGroup search for this read group
+    \return \c true if dictionary contains read group (matching on ID).
 */
 bool SamReadGroupDictionary::Contains(const SamReadGroup& readGroup) const {
-    return ( IndexOf(readGroup) != (int)m_data.size() );
+    return Contains(readGroup.ID);
 }
 
 /*! \fn SamReadGroupIterator SamReadGroupDictionary::End(void)
@@ -164,31 +182,16 @@ SamReadGroupIterator SamReadGroupDictionary::End(void) {
 }
 
 /*! \fn SamReadGroupConstIterator SamReadGroupDictionary::End(void) const
+    \return an STL const_iterator pointing to the imaginary entry after the last read group
 
     This is an overloaded function.
 
-    \return a const STL iterator pointing to the imaginary entry after the last read group
     \sa Begin(), ConstEnd()
 */
 SamReadGroupConstIterator SamReadGroupDictionary::End(void) const {
     return m_data.end();
 }
 
-/*! \fn int SamReadGroupDictionary::IndexOf(const SamReadGroup& readGroup) const
-    \internal
-    \return index of read group if found.  Otherwise, returns vector::size() (invalid index).
-*/
-int SamReadGroupDictionary::IndexOf(const SamReadGroup& readGroup) const {
-    SamReadGroupConstIterator begin = ConstBegin();
-    SamReadGroupConstIterator iter  = begin;
-    SamReadGroupConstIterator end   = ConstEnd();
-    for ( ; iter != end; ++iter ) {
-        if ( *iter == readGroup )
-            break;
-    }
-    return distance( begin, iter );
-}
-
 /*! \fn bool SamReadGroupDictionary::IsEmpty(void) const
     \brief Returns \c true if dictionary contains no read groups
     \sa Size()
@@ -198,32 +201,47 @@ bool SamReadGroupDictionary::IsEmpty(void) const {
 }
 
 /*! \fn void SamReadGroupDictionary::Remove(const SamReadGroup& readGroup)
-    \brief Removes read group from dictionary, if found.
-    \param readGroup read group to remove
+    \brief Removes read group from dictionary, if found (matching on ID).
+
+    This is an overloaded function.
+
+    \param[in] readGroup read group to remove (matches on ID)
 */
 void SamReadGroupDictionary::Remove(const SamReadGroup& readGroup) {
-    if ( Contains(readGroup) )
-        m_data.erase( m_data.begin() + IndexOf(readGroup) );
+    Remove(readGroup.ID);
 }
 
 /*! \fn void SamReadGroupDictionary::Remove(const std::string& readGroupId)
     \brief Removes read group from dictionary, if found.
 
-    This is an overloaded function.
-
-    \param readGroupId ID of read group to remove
+    \param[in] readGroupId ID of read group to remove
     \sa Remove()
 */
 void SamReadGroupDictionary::Remove(const std::string& readGroupId) {
-    Remove( SamReadGroup(readGroupId) );
+
+    // skip if empty dictionary or if ID unknown
+    if ( IsEmpty() || !Contains(readGroupId) )
+        return;
+
+    // update 'lookup index' for every entry after @readGroupId
+    const size_t indexToRemove = m_lookupData[readGroupId];
+    const size_t numEntries = m_data.size();
+    for ( size_t i = indexToRemove+1; i < numEntries; ++i ) {
+        const SamReadGroup& rg = m_data.at(i);
+        --m_lookupData[rg.ID];
+    }
+
+    // erase entry from containers
+    m_data.erase( Begin() + indexToRemove );
+    m_lookupData.erase(readGroupId);
 }
 
 /*! \fn void SamReadGroupDictionary::Remove(const std::vector<SamReadGroup>& readGroups)
-    \brief Removes multiple read groups from dictionary.
+    \brief Removes multiple read groups from dictionary (matching on ID).
 
     This is an overloaded function.
 
-    \param readGroups read groups to remove
+    \param[in] readGroups read groups to remove
     \sa Remove()
 */
 void SamReadGroupDictionary::Remove(const std::vector<SamReadGroup>& readGroups) {
@@ -238,7 +256,7 @@ void SamReadGroupDictionary::Remove(const std::vector<SamReadGroup>& readGroups)
 
     This is an overloaded function.
 
-    \param readGroupIds IDs of the read groups to remove
+    \param[in] readGroupIds IDs of the read groups to remove
     \sa Remove()
 */
 void SamReadGroupDictionary::Remove(const std::vector<std::string>& readGroupIds) {
@@ -259,28 +277,21 @@ int SamReadGroupDictionary::Size(void) const {
 /*! \fn SamReadGroup& SamReadGroupDictionary::operator[](const std::string& readGroupId)
     \brief Retrieves the modifiable SamReadGroup that matches \a readGroupId.
 
-    NOTE - If the dictionary contains no read group matching this ID, this function inserts
-    a new one with this ID, and returns a reference to it.
+    \note If the dictionary contains no read group matching this ID, this function inserts
+    a new one with this ID, and returns a reference to it. If you want to avoid this insertion
+    behavior, check the result of Contains() before using this operator.
 
-    If you want to avoid this insertion behavior, check the result of Contains() before
-    using this operator.
-
-    \param readGroupId ID of read group to retrieve
+    \param[in] readGroupId ID of read group to retrieve
     \return a modifiable reference to the SamReadGroup associated with the ID
 */
 SamReadGroup& SamReadGroupDictionary::operator[](const std::string& readGroupId) {
 
-    // look up read group ID
-    int index = IndexOf( SamReadGroup(readGroupId) );
-
-    // if found, return read group at index
-    if ( index != (int)m_data.size() )
-        return m_data[index];
-
-    // otherwise, append new read group and return reference
-    else {
+    if ( !Contains(readGroupId) ) {
         SamReadGroup rg(readGroupId);
         m_data.push_back(rg);
-        return m_data.back();
+        m_lookupData[readGroupId] = m_data.size() - 1;
     }
+
+    const size_t index = m_lookupData[readGroupId];
+    return m_data.at(index);
 }