src/objects/seqloc/Seq_loc.cpp

Go to the documentation of this file.
00001 /* $Id: Seq_loc.cpp 170254 2009-09-10 16:01:23Z grichenk $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author:   Author:  Cliff Clausen, Eugene Vasilchenko
00027  *
00028  * File Description:
00029  *   .......
00030  *
00031  * Remark:
00032  *   This code was originally generated by application DATATOOL
00033  *   using specifications from the ASN data definition file
00034  *   'seqloc.asn'.
00035  *
00036  * ===========================================================================
00037  */
00038 
00039 #include <ncbi_pch.hpp>
00040 #include <serial/enumvalues.hpp>
00041 #include <objects/general/Int_fuzz.hpp>
00042 #include <objects/seqloc/Seq_point.hpp>
00043 #include <objects/seqloc/Packed_seqint.hpp>
00044 #include <objects/seqloc/Packed_seqpnt.hpp>
00045 #include <objects/seqloc/Seq_loc_mix.hpp>
00046 #include <objects/seqloc/Seq_loc_equiv.hpp>
00047 #include <objects/seqloc/Seq_loc.hpp>
00048 #include <objects/seqfeat/Feat_id.hpp>
00049 #include <objects/misc/error_codes.hpp>
00050 #include <util/range_coll.hpp>
00051 #include <objects/seq/seq_id_handle.hpp>
00052 #include <algorithm>
00053 
00054 
00055 #define NCBI_USE_ERRCODE_X   Objects_SeqLoc
00056 
00057 
00058 BEGIN_NCBI_SCOPE
00059 BEGIN_objects_SCOPE // namespace ncbi::objects::
00060 
00061 
00062 // constructors
00063 CSeq_loc::CSeq_loc(E_Choice index)
00064 {
00065     x_InvalidateCache();
00066     switch ( index ) {
00067     case e_Null:
00068         {
00069             SetNull();
00070             break;
00071         }
00072     case e_Empty:
00073         {
00074             SetEmpty();
00075             break;
00076         }
00077     case e_Whole:
00078         {
00079             SetWhole();
00080             break;
00081         }
00082     case e_Int:
00083         {
00084             SetInt();
00085             break;
00086         }
00087     case e_Packed_int:
00088         {
00089             SetPacked_int();
00090             break;
00091         }
00092     case e_Pnt:
00093         {
00094             SetPnt();
00095             break;
00096         }
00097     case e_Packed_pnt:
00098         {
00099             SetPacked_pnt();
00100             break;
00101         }
00102     case e_Mix:
00103         {
00104             SetMix();
00105             break;
00106         }
00107     case e_Equiv:
00108         {
00109             SetEquiv();
00110             break;
00111         }
00112     case e_Bond:
00113         {
00114             SetBond();
00115             break;
00116         }
00117     case e_Feat:
00118         {
00119             SetFeat();
00120             break;
00121         }
00122     case e_not_set:
00123     default:
00124         break;
00125     }
00126 }
00127 
00128 
00129 CSeq_loc::CSeq_loc(TId& id, TPoint point, TStrand strand)
00130 {
00131     x_InvalidateCache();
00132     SetPnt(*new CSeq_point(id, point, strand));
00133 }
00134 
00135 
00136 CSeq_loc::CSeq_loc(TId& id, const TPoints& points, TStrand strand)
00137 {
00138     x_InvalidateCache();
00139     if ( points.size() == 1 ) {
00140         SetPnt(*new CSeq_point(id, points.front(), strand));
00141     } else {
00142         SetPacked_pnt(*new CPacked_seqpnt(id, points, strand));
00143     }
00144 }
00145 
00146 
00147 CSeq_loc::CSeq_loc(TId& id, TPoint from, TPoint to, TStrand strand)
00148 {
00149     x_InvalidateCache();
00150     SetInt(*new CSeq_interval(id, from, to, strand));
00151 }
00152 
00153 
00154 CSeq_loc::CSeq_loc(TId& id, TRanges ranges, TStrand strand)
00155 {
00156     x_InvalidateCache();
00157     if ( ranges.size() == 1 ) {
00158         SetInt(*new CSeq_interval(id,
00159             ranges.front().GetFrom(), ranges.front().GetTo(), strand));
00160     } else {
00161         SetPacked_int(*new CPacked_seqint(id, ranges, strand));
00162     }
00163 }
00164 
00165 
00166 // destructor
00167 CSeq_loc::~CSeq_loc(void)
00168 {
00169 }
00170 
00171 
00172 inline
00173 void x_Assign(CInt_fuzz& dst, const CInt_fuzz& src)
00174 {
00175     switch ( src.Which() ) {
00176     case CInt_fuzz::e_not_set:
00177         dst.Reset();
00178         break;
00179     case CInt_fuzz::e_P_m:
00180         dst.SetP_m(src.GetP_m());
00181         break;
00182     case CInt_fuzz::e_Range:
00183         dst.SetRange().SetMin(src.GetRange().GetMin());
00184         dst.SetRange().SetMax(src.GetRange().GetMax());
00185         break;
00186     case CInt_fuzz::e_Pct:
00187         dst.SetPct(src.GetPct());
00188         break;
00189     case CInt_fuzz::e_Lim:
00190         dst.SetLim(src.GetLim());
00191         break;
00192     case CInt_fuzz::e_Alt:
00193         dst.SetAlt() = src.GetAlt();
00194         break;
00195     default:
00196         NCBI_THROW(CException, eUnknown,
00197             "Invalid Int-fuzz variant");
00198     }
00199 }
00200 
00201 
00202 inline
00203 void x_Assign(CSeq_interval& dst, const CSeq_interval& src)
00204 {
00205     dst.SetFrom(src.GetFrom());
00206     dst.SetTo(src.GetTo());
00207     if ( src.IsSetStrand() ) {
00208         dst.SetStrand(src.GetStrand());
00209     }
00210     else {
00211         dst.ResetStrand();
00212     }
00213     dst.SetId().Assign(src.GetId());
00214     if ( src.IsSetFuzz_from() ) {
00215         x_Assign(dst.SetFuzz_from(), src.GetFuzz_from());
00216     }
00217     else {
00218         dst.ResetFuzz_from();
00219     }
00220     if ( src.IsSetFuzz_to() ) {
00221         x_Assign(dst.SetFuzz_to(), src.GetFuzz_to());
00222     }
00223     else {
00224         dst.ResetFuzz_to();
00225     }
00226 }
00227 
00228 
00229 inline
00230 void x_Assign(CSeq_point& dst, const CSeq_point& src)
00231 {
00232     dst.SetPoint(src.GetPoint());
00233     if ( src.IsSetStrand() ) {
00234         dst.SetStrand(src.GetStrand());
00235     }
00236     else {
00237         dst.ResetStrand();
00238     }
00239     dst.SetId().Assign(src.GetId());
00240     if ( src.IsSetFuzz() ) {
00241         x_Assign(dst.SetFuzz(), src.GetFuzz());
00242     }
00243     else {
00244         dst.ResetFuzz();
00245     }
00246 }
00247 
00248 
00249 inline
00250 void x_Assign(CPacked_seqint& dst, const CPacked_seqint& src)
00251 {
00252     CPacked_seqint::Tdata& data = dst.Set();
00253     data.clear();
00254     ITERATE ( CPacked_seqint::Tdata, i, src.Get() ) {
00255         data.push_back(CRef<CSeq_interval>(new CSeq_interval));
00256         x_Assign(*data.back(), **i);
00257     }
00258 }
00259 
00260 
00261 inline
00262 void x_Assign(CPacked_seqpnt& dst, const CPacked_seqpnt& src)
00263 {
00264     if ( src.IsSetStrand() ) {
00265         dst.SetStrand(src.GetStrand());
00266     }
00267     else {
00268         dst.ResetStrand();
00269     }
00270     dst.SetId().Assign(src.GetId());
00271     if ( src.IsSetFuzz() ) {
00272         x_Assign(dst.SetFuzz(), src.GetFuzz());
00273     }
00274     else {
00275         dst.ResetFuzz();
00276     }
00277     dst.SetPoints() = src.GetPoints();
00278 }
00279 
00280 
00281 inline
00282 void x_Assign(CSeq_bond& dst, const CSeq_bond& src)
00283 {
00284     x_Assign(dst.SetA(), src.GetA());
00285     if ( src.IsSetB() ) {
00286         x_Assign(dst.SetB(), src.GetB());
00287     }
00288     else {
00289         dst.ResetB();
00290     }
00291 }
00292 
00293 
00294 inline
00295 void x_Assign(CSeq_loc_mix& dst, const CSeq_loc_mix& src)
00296 {
00297     CSeq_loc_mix::Tdata& data = dst.Set();
00298     data.clear();
00299     ITERATE ( CSeq_loc_mix::Tdata, i, src.Get() ) {
00300         data.push_back(CRef<CSeq_loc>(new CSeq_loc));
00301         data.back()->Assign(**i);
00302     }
00303 }
00304 
00305 
00306 inline
00307 void x_Assign(CSeq_loc_equiv& dst, const CSeq_loc_equiv& src)
00308 {
00309     CSeq_loc_equiv::Tdata& data = dst.Set();
00310     data.clear();
00311     ITERATE ( CSeq_loc_equiv::Tdata, i, src.Get() ) {
00312         data.push_back(CRef<CSeq_loc>(new CSeq_loc));
00313         data.back()->Assign(**i);
00314     }
00315 }
00316 
00317 
00318 void CSeq_loc::Assign(const CSerialObject& obj, ESerialRecursionMode how)
00319 {
00320     x_InvalidateCache();
00321     if ( GetTypeInfo() == obj.GetThisTypeInfo() ) {
00322         const CSeq_loc& loc = static_cast<const CSeq_loc&>(obj);
00323         switch ( loc.Which() ) {
00324         case e_not_set:
00325             Reset();
00326             return;
00327         case e_Null:
00328             SetNull();
00329             return;
00330         case e_Empty:
00331             SetEmpty().Assign(loc.GetEmpty());
00332             return;
00333         case e_Whole:
00334             SetWhole().Assign(loc.GetWhole());
00335             return;
00336         case e_Int:
00337             x_Assign(SetInt(), loc.GetInt());
00338             return;
00339         case e_Pnt:
00340             x_Assign(SetPnt(), loc.GetPnt());
00341             return;
00342         case e_Packed_int:
00343             x_Assign(SetPacked_int(), loc.GetPacked_int());
00344             return;
00345         case e_Packed_pnt:
00346             x_Assign(SetPacked_pnt(), loc.GetPacked_pnt());
00347             return;
00348         case e_Mix:
00349             x_Assign(SetMix(), loc.GetMix());
00350             return;
00351         case e_Equiv:
00352             x_Assign(SetEquiv(), loc.GetEquiv());
00353             return;
00354         case e_Bond:
00355             x_Assign(SetBond(), loc.GetBond());
00356             return;
00357         case e_Feat:
00358             SetFeat().Assign(loc.GetFeat());
00359             return;
00360         }
00361     }
00362     CSerialObject::Assign(obj, how);
00363 }
00364 
00365 
00366 CSeq_loc::TRange CSeq_loc::x_UpdateTotalRange(void) const
00367 {
00368     TRange range = m_TotalRangeCache;
00369     if ( range.GetFrom() == TSeqPos(kDirtyCache) ) {
00370         const CSeq_id* id = 0;
00371         range = x_CalculateTotalRangeCheckId(id);
00372         m_IdCache = id;
00373         m_TotalRangeCache.SetToOpen(range.GetToOpen());
00374         m_TotalRangeCache.SetFrom(range.GetFrom());
00375     }
00376     return range;
00377 }
00378 
00379 
00380 void CSeq_loc::x_UpdateId(const CSeq_id*& total_id, const CSeq_id* id) const
00381 {
00382     if ( total_id == id ) {
00383         return;
00384     }
00385 
00386     if ( !total_id ) {
00387         total_id = id;
00388     } else if ( (id  &&  !total_id->Equals(*id))  ||  !id ) {
00389         NCBI_THROW(CException, eUnknown, "CSeq_loc -- multiple seq-ids");
00390     }
00391 }
00392 
00393 
00394 
00395 // returns enclosing location range
00396 // the total range is meaningless if there are several seq-ids
00397 // in the location
00398 CSeq_loc::TRange CSeq_loc::x_CalculateTotalRangeCheckId(const CSeq_id*& id) const
00399 {
00400     TRange total_range;
00401     switch ( Which() ) {
00402     case e_not_set:
00403     case e_Null:
00404         {
00405             // Ignore locations without id
00406             total_range = TRange::GetEmpty();
00407             break;
00408         }
00409     case e_Empty:
00410         {
00411             x_UpdateId(id, &GetEmpty());
00412             total_range = TRange::GetEmpty();
00413             break;
00414         }
00415     case e_Whole:
00416         {
00417             x_UpdateId(id, &GetWhole());
00418             total_range = TRange::GetWhole();
00419             break;
00420         }
00421     case e_Int:
00422         {
00423             const CSeq_interval& loc = GetInt();
00424             x_UpdateId(id, &loc.GetId());
00425             total_range.Set(loc.GetFrom(), loc.GetTo());
00426             break;
00427         }
00428     case e_Pnt:
00429         {
00430             const CSeq_point& pnt = GetPnt();
00431             x_UpdateId(id, &pnt.GetId());
00432             TSeqPos pos = pnt.GetPoint();
00433             total_range.Set(pos, pos);
00434             break;
00435         }
00436     case e_Packed_int:
00437         {
00438             // Check ID of each interval
00439             const CPacked_seqint& ints = GetPacked_int();
00440             total_range = TRange::GetEmpty();
00441             ITERATE ( CPacked_seqint::Tdata, ii, ints.Get() ) {
00442                 const CSeq_interval& loc = **ii;
00443                 x_UpdateId(id, &loc.GetId());
00444                 total_range += TRange(loc.GetFrom(), loc.GetTo());
00445             }
00446             break;
00447         }
00448     case e_Packed_pnt:
00449         {
00450             const CPacked_seqpnt& pnts = GetPacked_pnt();
00451             x_UpdateId(id, &pnts.GetId());
00452             total_range = TRange::GetEmpty();
00453             ITERATE( CPacked_seqpnt::TPoints, pi, pnts.GetPoints() ) {
00454                 TSeqPos pos = *pi;
00455                 total_range += TRange(pos, pos);
00456             }
00457             break;
00458         }
00459     case e_Mix:
00460         {
00461             // Check ID of each sub-location.
00462             const CSeq_loc_mix& mix = GetMix();
00463             total_range = TRange::GetEmpty();
00464             ITERATE( CSeq_loc_mix::Tdata, li, mix.Get() ) {
00465                 // instead of Get... to be able to check ID
00466                 total_range += (*li)->x_CalculateTotalRangeCheckId(id);
00467             }
00468             break;
00469         }
00470     case e_Equiv:
00471         {
00472             // Does it make any sense to GetTotalRange() from an equiv?
00473             const CSeq_loc_equiv::Tdata& equiv = GetEquiv().Get();
00474             total_range = TRange::GetEmpty();
00475             ITERATE( CSeq_loc_equiv::Tdata, li, equiv ) {
00476                 total_range += (*li)->x_CalculateTotalRangeCheckId(id);
00477             }
00478             break;
00479         }
00480     case e_Bond:
00481         {
00482             // Does it make any sense to GetTotalRange() from a bond?
00483             const CSeq_bond& bond = GetBond();
00484             const CSeq_point& pointA = bond.GetA();
00485             x_UpdateId(id, &pointA.GetId());
00486             TSeqPos pos = pointA.GetPoint();
00487             total_range = TRange(pos, pos);
00488             if ( bond.IsSetB() ) {
00489                 const CSeq_point& pointB = bond.GetB();
00490                 x_UpdateId(id, &pointB.GetId());
00491                 pos = pointB.GetPoint();
00492                 total_range += TRange(pos, pos);
00493             }
00494             break;
00495         }
00496     case e_Feat:
00497     default:
00498         {
00499             NCBI_THROW(CException, eUnknown,
00500                        "CSeq_loc::CalculateTotalRange -- "
00501                        "unsupported location type");
00502         }
00503     }
00504 
00505     return total_range;
00506 }
00507 
00508 
00509 bool CSeq_loc::IsSetStrand(EIsSetStrand flag) const
00510 {
00511     switch ( Which() ) {
00512     case e_Int:
00513         return GetInt().IsSetStrand();
00514     case e_Pnt:
00515         return GetPnt().IsSetStrand();
00516     case e_Packed_int:
00517         return GetPacked_int().IsSetStrand(flag);
00518     case e_Packed_pnt:
00519         return GetPacked_pnt().IsSetStrand();
00520     case e_Mix:
00521         return GetMix().IsSetStrand(flag);
00522     case e_Bond:
00523         return GetBond().IsSetStrand(flag);
00524 
00525     case e_Equiv:
00526     case e_Feat:
00527     default:
00528         return false;
00529     }
00530 }
00531 
00532 
00533 ENa_strand CSeq_loc::GetStrand(void) const
00534 {
00535     switch ( Which() ) {
00536     case e_not_set:
00537     case e_Null:
00538     case e_Empty:
00539         return eNa_strand_unknown;
00540     case e_Whole:
00541         return eNa_strand_both;
00542     case e_Int:
00543         return GetInt().IsSetStrand() ? GetInt().GetStrand() : eNa_strand_unknown;
00544     case e_Pnt:
00545         return GetPnt().IsSetStrand() ? GetPnt().GetStrand() : eNa_strand_unknown;
00546     case e_Packed_int:
00547         return GetPacked_int().GetStrand();
00548     case e_Packed_pnt:
00549         return GetPacked_pnt().IsSetStrand() ?
00550             GetPacked_pnt().GetStrand() : eNa_strand_unknown;
00551     case e_Mix:
00552         return GetMix().GetStrand();
00553     case e_Bond:
00554         return GetBond().GetStrand();
00555 
00556     case e_Equiv:
00557     case e_Feat:
00558     default:
00559         NCBI_THROW(CException, eUnknown,
00560             "CSeq_loc::GetStrand -- unsupported location type" +
00561             CSeq_loc::SelectionName(Which()));
00562     }
00563 }
00564 
00565 
00566 TSeqPos CSeq_loc::GetStart(ESeqLocExtremes ext) const
00567 {
00568     switch ( Which() ) {
00569     case e_not_set:
00570     case e_Null:
00571     case e_Empty:
00572         {
00573             return kInvalidSeqPos;
00574         }
00575     case e_Whole:
00576         {
00577             return TRange::GetWhole().GetFrom();
00578         }
00579     case e_Int:
00580         {
00581             return (ext == eExtreme_Biological  &&  IsReverseStrand()) ?
00582                 GetInt().GetTo() : GetInt().GetFrom();
00583         }
00584     case e_Pnt:
00585         {
00586             return GetPnt().GetPoint();
00587         }
00588     case e_Packed_int:
00589         {
00590             return GetPacked_int().GetStart(ext);
00591         }
00592     case e_Packed_pnt:
00593         {
00594             return GetPacked_pnt().GetStart(ext);
00595         }
00596     case e_Mix:
00597         {
00598             return GetMix().GetStart(ext);
00599         }
00600     case e_Bond:
00601         {
00602             return GetBond().GetStart(ext);
00603         }
00604 
00605     case e_Equiv:
00606     case e_Feat:
00607     default:
00608         {
00609             NCBI_THROW(CException, eUnknown,
00610                        "CSeq_loc::GetStart -- "
00611                        "unsupported location type");
00612         }
00613     }
00614 }
00615 
00616 
00617 TSeqPos CSeq_loc::GetStop(ESeqLocExtremes ext) const
00618 {
00619     switch ( Which() ) {
00620     case e_not_set:
00621     case e_Null:
00622     case e_Empty:
00623         {
00624             return kInvalidSeqPos;
00625         }
00626     case e_Whole:
00627         {
00628             return TRange::GetWhole().GetTo();
00629         }
00630     case e_Int:
00631         {
00632             return (ext == eExtreme_Biological  &&  IsReverseStrand()) ?
00633                 GetInt().GetFrom() : GetInt().GetTo();
00634         }
00635     case e_Pnt:
00636         {
00637             return GetPnt().GetPoint();
00638         }
00639     case e_Packed_int:
00640         {
00641             return GetPacked_int().GetStop(ext);
00642         }
00643     case e_Packed_pnt:
00644         {
00645             return GetPacked_pnt().GetStop(ext);
00646         }
00647     case e_Mix:
00648         {
00649             return GetMix().GetStop(ext);
00650         }
00651     case e_Bond:
00652         {
00653             return GetBond().GetStop(ext);
00654         }
00655 
00656     case e_Equiv:
00657     case e_Feat:
00658     default:
00659         {
00660             NCBI_THROW(CException, eUnknown,
00661                        "CSeq_loc::GetStart -- "
00662                        "unsupported location type");
00663         }
00664     }
00665 }
00666 
00667 
00668 TSeqPos CSeq_loc::GetCircularLength(TSeqPos seq_len) const
00669 {
00670     if (seq_len == kInvalidSeqPos) {
00671         return GetTotalRange().GetLength();
00672     }
00673     TSeqPos start = GetStart(eExtreme_Biological);
00674     TSeqPos stop  = GetStop (eExtreme_Biological);
00675     bool    minus = IsReverseStrand();
00676 
00677     if (start < stop) {
00678         return minus ? (seq_len - stop + start + 1) : (stop - start - 1);
00679     } else {
00680         return minus ? (start - stop - 1) : (seq_len - start + stop + 1);
00681     }
00682 }
00683 
00684 
00685 // CSeq_loc_CI implementation
00686 
00687 CSeq_loc_CI::CSeq_loc_CI(void)
00688     : m_Location(0),
00689       m_EmptyFlag(eEmpty_Skip)
00690 {
00691     m_CurLoc = m_LocList.end();
00692 }
00693 
00694 
00695 CSeq_loc_CI::CSeq_loc_CI(const CSeq_loc& loc,
00696                          EEmptyFlag empty_flag,
00697                          ESeqLocOrder order)
00698     : m_Location(&loc),
00699       m_EmptyFlag(empty_flag)
00700 {
00701     x_ProcessLocation(loc);
00702     if ( order == eOrder_Biological  &&  loc.IsReverseStrand() ) {
00703         m_LocList.reverse();
00704     }
00705     m_CurLoc = m_LocList.begin();
00706 }
00707 
00708 
00709 CSeq_loc_CI::CSeq_loc_CI(const CSeq_loc_CI& iter)
00710 {
00711     *this = iter;
00712 }
00713 
00714 
00715 CSeq_loc_CI::~CSeq_loc_CI()
00716 {
00717 }
00718 
00719 
00720 CSeq_loc_CI& CSeq_loc_CI::operator= (const CSeq_loc_CI& iter)
00721 {
00722     if (this == &iter)
00723         return *this;
00724     m_LocList.clear();
00725     m_Location = iter.m_Location;
00726     m_EmptyFlag = iter.m_EmptyFlag;
00727     m_CurLoc = m_LocList.end();
00728     ITERATE(TLocList, li, iter.m_LocList) {
00729         TLocList::iterator tmp = m_LocList.insert(m_LocList.end(), *li);
00730         if (iter.m_CurLoc == li)
00731             m_CurLoc = tmp;
00732     }
00733     return *this;
00734 }
00735 
00736 
00737 void CSeq_loc_CI::x_ThrowNotValid(const char* where) const
00738 {
00739     string msg;
00740     msg += "CSeq_loc_CI::";
00741     msg += where;
00742     msg += " -- iterator is not valid";
00743     NCBI_THROW(CException, eUnknown,
00744         msg);
00745 }
00746 
00747 void CSeq_loc_CI::x_ProcessLocation(const CSeq_loc& loc)
00748 {
00749     switch ( loc.Which() ) {
00750     case CSeq_loc::e_not_set:
00751     case CSeq_loc::e_Null:
00752     case CSeq_loc::e_Empty:
00753         {
00754             if (m_EmptyFlag == eEmpty_Allow) {
00755                 SLoc_Info info;
00756                 if (loc.Which() == CSeq_loc::e_Empty) {
00757                     info.m_Id = &loc.GetEmpty();
00758                 }
00759                 else {
00760                     info.m_Id.Reset(new CSeq_id);
00761                 }
00762                 info.m_Range = TRange::GetEmpty();
00763                 info.m_Loc = &loc;
00764                 m_LocList.push_back(info);
00765             }
00766             return;
00767         }
00768     case CSeq_loc::e_Whole:
00769         {
00770             SLoc_Info info;
00771             info.m_Id = &loc.GetWhole();
00772             info.m_Range = TRange::GetWhole();
00773             info.m_Loc = &loc;
00774             m_LocList.push_back(info);
00775             return;
00776         }
00777     case CSeq_loc::e_Int:
00778         {
00779             SLoc_Info info;
00780             info.m_Id = &loc.GetInt().GetId();
00781             info.m_Range.Set(loc.GetInt().GetFrom(), loc.GetInt().GetTo());
00782             if ( loc.GetInt().IsSetStrand() ) {
00783                 info.SetStrand(loc.GetInt().GetStrand());
00784             }
00785             info.m_Loc = &loc;
00786             if (loc.GetInt().IsSetFuzz_from()) {
00787                 info.m_Fuzz.first = &loc.GetInt().GetFuzz_from();
00788             }
00789             if (loc.GetInt().IsSetFuzz_to()) {
00790                 info.m_Fuzz.second = &loc.GetInt().GetFuzz_to();
00791             }
00792             m_LocList.push_back(info);
00793             return;
00794         }
00795     case CSeq_loc::e_Pnt:
00796         {
00797             SLoc_Info info;
00798             info.m_Id = &loc.GetPnt().GetId();
00799             info.m_Range.Set(loc.GetPnt().GetPoint(), loc.GetPnt().GetPoint());
00800             if ( loc.GetPnt().IsSetStrand() ) {
00801                 info.SetStrand(loc.GetPnt().GetStrand());
00802             }
00803             info.m_Loc = &loc;
00804             if (loc.GetPnt().IsSetFuzz()) {
00805                 info.m_Fuzz.first = info.m_Fuzz.second
00806                     = &loc.GetPnt().GetFuzz();
00807             }
00808             m_LocList.push_back(info);
00809             return;
00810         }
00811     case CSeq_loc::e_Packed_int:
00812         {
00813             ITERATE ( CPacked_seqint::Tdata, ii, loc.GetPacked_int().Get() ) {
00814                 SLoc_Info info;
00815                 info.m_Id = &(*ii)->GetId();
00816                 info.m_Range.Set((*ii)->GetFrom(), (*ii)->GetTo());
00817                 if ( (*ii)->IsSetStrand() ) {
00818                     info.SetStrand((*ii)->GetStrand());
00819                 }
00820                 info.m_Loc = &loc;
00821                 if ((*ii)->IsSetFuzz_from()) {
00822                     info.m_Fuzz.first = &(*ii)->GetFuzz_from();
00823                 }
00824                 if ((*ii)->IsSetFuzz_to()) {
00825                     info.m_Fuzz.second = &(*ii)->GetFuzz_to();
00826                 }
00827                 m_LocList.push_back(info);
00828             }
00829             return;
00830         }
00831     case CSeq_loc::e_Packed_pnt:
00832         {
00833             ITERATE ( CPacked_seqpnt::TPoints, pi, loc.GetPacked_pnt().GetPoints() ) {
00834                 SLoc_Info info;
00835                 info.m_Id = &loc.GetPacked_pnt().GetId();
00836                 info.m_Range.Set(*pi, *pi);
00837                 if ( loc.GetPacked_pnt().IsSetStrand() ) {
00838                     info.SetStrand(loc.GetPacked_pnt().GetStrand());
00839                 }
00840                 info.m_Loc = &loc;
00841                 if (loc.GetPacked_pnt().IsSetFuzz()) {
00842                     info.m_Fuzz.first = info.m_Fuzz.second
00843                         = &loc.GetPacked_pnt().GetFuzz();
00844                 }
00845                 m_LocList.push_back(info);
00846             }
00847             return;
00848         }
00849     case CSeq_loc::e_Mix:
00850         {
00851             ITERATE(CSeq_loc_mix::Tdata, li, loc.GetMix().Get()) {
00852                 x_ProcessLocation(**li);
00853             }
00854             return;
00855         }
00856     case CSeq_loc::e_Equiv:
00857         {
00858             ITERATE(CSeq_loc_equiv::Tdata, li, loc.GetEquiv().Get()) {
00859                 x_ProcessLocation(**li);
00860             }
00861             return;
00862         }
00863     case CSeq_loc::e_Bond:
00864         {
00865             SLoc_Info infoA;
00866             infoA.m_Id = &loc.GetBond().GetA().GetId();
00867             infoA.m_Range.Set(loc.GetBond().GetA().GetPoint(),
00868                               loc.GetBond().GetA().GetPoint());
00869             if ( loc.GetBond().GetA().IsSetStrand() ) {
00870                 infoA.SetStrand(loc.GetBond().GetA().GetStrand());
00871             }
00872             infoA.m_Loc = &loc;
00873             if (loc.GetBond().GetA().IsSetFuzz()) {
00874                 infoA.m_Fuzz.first = infoA.m_Fuzz.second
00875                     = &loc.GetBond().GetA().GetFuzz();
00876             }
00877             m_LocList.push_back(infoA);
00878             if ( loc.GetBond().IsSetB() ) {
00879                 SLoc_Info infoB;
00880                 infoB.m_Id = &loc.GetBond().GetB().GetId();
00881                 infoB.m_Range.Set(loc.GetBond().GetB().GetPoint(),
00882                                   loc.GetBond().GetB().GetPoint());
00883                 if ( loc.GetBond().GetB().IsSetStrand() ) {
00884                     infoB.SetStrand(loc.GetBond().GetB().GetStrand());
00885                 }
00886                 infoB.m_Loc = &loc;
00887                 if (loc.GetBond().GetB().IsSetFuzz()) {
00888                     infoB.m_Fuzz.first = infoB.m_Fuzz.second
00889                         = &loc.GetBond().GetB().GetFuzz();
00890                 }
00891                 m_LocList.push_back(infoB);
00892             }
00893             return;
00894         }
00895     case CSeq_loc::e_Feat:
00896     default:
00897         {
00898             NCBI_THROW(CException, eUnknown,
00899                        "CSeq_loc_CI -- unsupported location type");
00900         }
00901     }
00902 }
00903 
00904 
00905 // Append a string representation of a CSeq_id to label
00906 inline
00907 void s_GetLabel(const CSeq_id& id, string* label)
00908 {
00909     CNcbiOstrstream os;
00910     id.WriteAsFasta(os);
00911     *label += CNcbiOstrstreamToString(os);
00912 }
00913 
00914 
00915 // Append to label info for a CSeq_point
00916 inline
00917 const CSeq_id* s_GetLabel
00918 (const CSeq_point& pnt,
00919  const CSeq_id*    last_id,
00920  string*           label)
00921 {
00922     // If CSeq_id does not match last_id, then append id to label
00923     if ( !last_id  ||  !last_id->Match(pnt.GetId()) ) {
00924         s_GetLabel(pnt.GetId(), label);
00925         *label += ":";
00926     }
00927 
00928     // Add strand info to label
00929     if (pnt.IsSetStrand()) {
00930         *label += GetTypeInfo_enum_ENa_strand()
00931             ->FindName(pnt.GetStrand(), true);
00932     }
00933 
00934     if (pnt.IsSetFuzz()) {
00935         // Append Fuzz info to label
00936         pnt.GetFuzz().GetLabel(label, pnt.GetPoint());
00937     } else {
00938         // Append 1 based point to label
00939         *label += NStr::IntToString(pnt.GetPoint()+1);
00940     }
00941 
00942     // update last_id
00943     last_id = &pnt.GetId();
00944     return last_id;
00945 }
00946 
00947 
00948 // Append to label info for CSeq_interval
00949 inline
00950 const CSeq_id* s_GetLabel
00951 (const CSeq_interval& itval,
00952  const CSeq_id*       last_id,
00953  string*              label)
00954 {
00955     if (!last_id || !last_id->Match(itval.GetId())) {
00956         s_GetLabel(itval.GetId(), label);
00957         *label += ":";
00958     }
00959     last_id = &itval.GetId();
00960     if (itval.IsSetStrand()) {
00961         *label += GetTypeInfo_enum_ENa_strand()
00962             ->FindName(itval.GetStrand(), true);
00963     }
00964     if (itval.IsSetStrand() &&
00965         (itval.GetStrand() == eNa_strand_minus ||
00966          itval.GetStrand() == eNa_strand_both_rev)) {
00967         if (itval.IsSetFuzz_to()) {
00968             itval.GetFuzz_to().GetLabel(label, itval.GetTo(), false);
00969         } else {
00970             *label += NStr::IntToString(itval.GetTo()+1);
00971         }
00972         *label += "-";
00973         if (itval.IsSetFuzz_from()) {
00974             itval.GetFuzz_from().GetLabel(label, itval.GetFrom());
00975         } else {
00976             *label += NStr::IntToString(itval.GetFrom()+1);
00977         }
00978     } else {
00979         if (itval.IsSetFuzz_from()) {
00980             itval.GetFuzz_from().GetLabel
00981                 (label, itval.GetFrom(), false);
00982         } else {
00983             *label += NStr::IntToString(itval.GetFrom()+1);
00984         }
00985         *label += "-";
00986         if (itval.IsSetFuzz_to()) {
00987             itval.GetFuzz_to().GetLabel(label, itval.GetTo());
00988         } else {
00989             *label += NStr::IntToString(itval.GetTo()+1);
00990         }
00991     }
00992     return last_id;
00993 }
00994 
00995 
00996 // Forward declaration
00997 const CSeq_id* s_GetLabel
00998 (const CSeq_loc& loc,
00999  const CSeq_id*  last_id,
01000  string*         label,
01001  bool            first = false);
01002 
01003 
01004 // Appends to label info for each CSeq_loc in a list of CSeq_locs
01005 inline
01006 const CSeq_id* s_GetLabel
01007 (const list<CRef<CSeq_loc> >&  loc_list,
01008  const CSeq_id*                last_id,
01009  string*                       label)
01010 {
01011     bool first = true;
01012     ITERATE (list<CRef<CSeq_loc> >, it, loc_list) {
01013 
01014         // Append to label for each CSeq_loc in list
01015         last_id = s_GetLabel(**it, last_id, label, first);
01016         first = false;
01017     }
01018 
01019     return last_id;
01020 }
01021 
01022 
01023 // Builds a label based upon a CSeq_loc and all embedded CSeq_locs
01024 const CSeq_id* s_GetLabel
01025 (const CSeq_loc& loc,
01026  const CSeq_id*  last_id,
01027  string*         label,
01028  bool            first)
01029 {
01030     // Ensure label is not null
01031     if (!label) {
01032         return last_id;
01033     }
01034 
01035     // Put a comma separator if necessary
01036     if (!first) {
01037         *label += ", ";
01038     }
01039 
01040     // Loop through embedded CSeq_locs and create a label, depending on
01041     // type of CSeq_loc
01042     switch (loc.Which()) {
01043     case CSeq_loc::e_Null:
01044         *label += "~";
01045         break;
01046     case CSeq_loc::e_Empty:
01047         *label += "{";
01048         s_GetLabel(loc.GetEmpty(), label);
01049         last_id = &loc.GetEmpty();
01050         *label += "}";
01051         break;
01052     case CSeq_loc::e_Whole:
01053         s_GetLabel(loc.GetWhole(), label);
01054         last_id = &loc.GetWhole();
01055         break;
01056     case CSeq_loc::e_Int:
01057         last_id = s_GetLabel(loc.GetInt(), last_id, label);
01058         break;
01059     case CSeq_loc::e_Packed_int:
01060     {
01061         *label += "(";
01062         bool frst = true;
01063         ITERATE(CPacked_seqint::Tdata, it, loc.GetPacked_int().Get()) {
01064             if (!frst) {
01065                 *label += ", ";
01066             }
01067             frst = false;
01068             last_id = s_GetLabel(**it, last_id, label);
01069         }
01070         *label += ")";
01071         break;
01072     }
01073     case CSeq_loc::e_Pnt:
01074         last_id = s_GetLabel(loc.GetPnt(), last_id, label);
01075         break;
01076     case CSeq_loc::e_Packed_pnt:
01077         *label += "(" + loc.GetPacked_pnt().GetId().AsFastaString() + ":";
01078         {{
01079              string str;
01080              ITERATE (CPacked_seqpnt::TPoints, iter,
01081                       loc.GetPacked_pnt().GetPoints()) {
01082                  if ( !str.empty() ) {
01083                      str += ", ";
01084                  }
01085                  str += NStr::IntToString(*iter);
01086              }
01087              *label += str;
01088          }}
01089         *label += ")";
01090         last_id = &loc.GetPacked_pnt().GetId();
01091         break;
01092     case CSeq_loc::e_Mix:
01093         *label += "[";
01094         last_id = s_GetLabel(loc.GetMix().Get(), last_id, label);
01095         *label += "]";
01096         break;
01097     case CSeq_loc::e_Equiv:
01098         *label += "[";
01099         last_id = s_GetLabel(loc.GetEquiv().Get(), last_id, label);
01100         *label += "]";
01101         break;
01102     case CSeq_loc::e_Bond:
01103         last_id = s_GetLabel(loc.GetBond().GetA(), last_id, label);
01104         *label += "=";
01105         if (loc.GetBond().IsSetB()) {
01106             last_id = s_GetLabel(loc.GetBond().GetB(), last_id, label);
01107         } else {
01108             *label += "?";
01109         }
01110         break;
01111     case CSeq_loc::e_Feat:
01112         *label += "(feat)";
01113         break;
01114     default:
01115         *label += "(?\?)";
01116         break;
01117     }
01118     return last_id;
01119 }
01120 
01121 
01122 bool CSeq_loc::IsPartialStart(ESeqLocExtremes ext) const
01123 {
01124     switch (Which ()) {
01125         case e_Null :
01126             return true;
01127 
01128         case e_Int :
01129             return GetInt().IsPartialStart(ext);
01130 
01131         case e_Packed_int :
01132             return GetPacked_int().IsPartialStart(ext);
01133 
01134         case e_Pnt :
01135             return GetPnt().IsPartialStart(ext);
01136 
01137         case e_Packed_pnt :
01138             return GetPacked_pnt().IsPartialStart(ext);
01139 
01140         case e_Mix :
01141             return GetMix().IsPartialStart(ext);
01142 
01143         default :
01144             break;
01145     }
01146 
01147     return false;
01148 }
01149 
01150 
01151 bool CSeq_loc::IsPartialStop(ESeqLocExtremes ext) const
01152 {
01153     switch (Which ()) {
01154         case e_Null :
01155             return true;
01156 
01157         case e_Int :
01158             return GetInt().IsPartialStop(ext);
01159 
01160         case e_Packed_int :
01161             return GetPacked_int().IsPartialStop(ext);
01162 
01163         case e_Pnt :
01164             return GetPnt().IsPartialStop(ext);
01165 
01166         case e_Packed_pnt :
01167             return GetPacked_pnt().IsPartialStop(ext);
01168 
01169         case e_Mix :
01170             return GetMix().IsPartialStop(ext);
01171 
01172         default :
01173             break;
01174     }
01175 
01176     return false;
01177 }
01178 
01179 
01180 void CSeq_loc::SetPartialStart(bool val, ESeqLocExtremes ext)
01181 {
01182     if (val == IsPartialStart(ext)) {
01183         return;
01184     }
01185 
01186     switch (Which()) {
01187         case e_Int:
01188             SetInt().SetPartialStart(val, ext);
01189             break;
01190 
01191         case e_Packed_int :
01192             SetPacked_int().SetPartialStart(val, ext);
01193             break;
01194 
01195         case e_Pnt:
01196             SetPnt().SetPartialStart(val, ext);
01197             break;
01198 
01199         case e_Packed_pnt:
01200             SetPacked_pnt().SetPartialStart(val, ext);
01201             break;
01202 
01203         case e_Mix :
01204             SetMix().SetPartialStart(val, ext);
01205             break;
01206 
01207         default :
01208             break;
01209     }
01210 }
01211 
01212 
01213 void CSeq_loc::SetPartialStop(bool val, ESeqLocExtremes ext)
01214 {
01215     if (val == IsPartialStop(ext)) {
01216         return;
01217     }
01218 
01219     switch (Which()) {
01220         case e_Int:
01221             SetInt().SetPartialStop(val, ext);
01222             break;
01223 
01224         case e_Packed_int :
01225             SetPacked_int().SetPartialStop(val, ext);
01226             break;
01227 
01228         case e_Pnt:
01229             SetPnt().SetPartialStop(val, ext);
01230             break;
01231 
01232         case e_Packed_pnt:
01233             SetPacked_pnt().SetPartialStop(val, ext);
01234             break;
01235 
01236         case e_Mix:
01237             SetMix().SetPartialStop(val, ext);
01238             break;
01239 
01240         default :
01241             break;
01242     }
01243 }
01244 
01245 
01246 bool CSeq_loc::IsTruncatedStart(ESeqLocExtremes ext) const
01247 {
01248     switch (Which ()) {
01249         case e_Int :
01250             return GetInt().IsTruncatedStart(ext);
01251 
01252         case e_Packed_int :
01253             return GetPacked_int().IsTruncatedStart(ext);
01254 
01255         case e_Pnt :
01256             return GetPnt().IsTruncatedStart(ext);
01257 
01258         case e_Packed_pnt :
01259             return GetPacked_pnt().IsTruncatedStart(ext);
01260 
01261         case e_Mix :
01262             return GetMix().IsTruncatedStart(ext);
01263 
01264         default :
01265             break;
01266     }
01267 
01268     return false;
01269 }
01270 
01271 
01272 bool CSeq_loc::IsTruncatedStop(ESeqLocExtremes ext) const
01273 {
01274     switch (Which ()) {
01275         case e_Int :
01276             return GetInt().IsTruncatedStop(ext);
01277 
01278         case e_Packed_int :
01279             return GetPacked_int().IsTruncatedStop(ext);
01280 
01281         case e_Pnt :
01282             return GetPnt().IsTruncatedStop(ext);
01283 
01284         case e_Packed_pnt :
01285             return GetPacked_pnt().IsTruncatedStop(ext);
01286 
01287         case e_Mix :
01288             return GetMix().IsTruncatedStop(ext);
01289 
01290         default :
01291             break;
01292     }
01293 
01294     return false;
01295 }
01296 
01297 
01298 void CSeq_loc::SetTruncatedStart(bool val, ESeqLocExtremes ext)
01299 {
01300     if (val == IsTruncatedStart(ext)) {
01301         return;
01302     }
01303 
01304     switch (Which()) {
01305         case e_Int:
01306             SetInt().SetTruncatedStart(val, ext);
01307             break;
01308 
01309         case e_Packed_int :
01310             SetPacked_int().SetTruncatedStart(val, ext);
01311             break;
01312 
01313         case e_Pnt:
01314             SetPnt().SetTruncatedStart(val, ext);
01315             break;
01316 
01317         case e_Packed_pnt:
01318             SetPacked_pnt().SetTruncatedStart(val, ext);
01319             break;
01320 
01321         case e_Mix :
01322             SetMix().SetTruncatedStart(val, ext);
01323             break;
01324 
01325         default :
01326             break;
01327     }
01328 }
01329 
01330 
01331 void CSeq_loc::SetTruncatedStop(bool val, ESeqLocExtremes ext)
01332 {
01333     if (val == IsTruncatedStop(ext)) {
01334         return;
01335     }
01336 
01337     switch (Which()) {
01338         case e_Int:
01339             SetInt().SetTruncatedStop(val, ext);
01340             break;
01341 
01342         case e_Packed_int :
01343             SetPacked_int().SetTruncatedStop(val, ext);
01344             break;
01345 
01346         case e_Pnt:
01347             SetPnt().SetTruncatedStop(val, ext);
01348             break;
01349 
01350         case e_Packed_pnt:
01351             SetPacked_pnt().SetTruncatedStop(val, ext);
01352             break;
01353 
01354         case e_Mix:
01355             SetMix().SetTruncatedStop(val, ext);
01356             break;
01357 
01358         default :
01359             break;
01360     }
01361 }
01362 
01363 
01364 // Appends a label suitable for display (e.g., error messages)
01365 // label must point to an existing string object
01366 // Method just returns if label is null
01367 void CSeq_loc::GetLabel(string* label) const
01368 {
01369     s_GetLabel(*this, 0, label, true);
01370 }
01371 
01372 
01373 // assign the 'id' field of each sub-interval to the supplied id
01374 void CSeq_loc::SetId(CSeq_id& id)
01375 {
01376     x_InvalidateCache();
01377     switch (Which()) {
01378     case e_Null:
01379         break;
01380 
01381     case e_Int:
01382         SetInt().SetId(id);
01383         break;
01384 
01385     case e_Pnt:
01386         SetPnt().SetId(id);
01387         break;
01388 
01389     case e_Packed_int:
01390         NON_CONST_ITERATE (CPacked_seqint::Tdata, iter, SetPacked_int().Set()) {
01391             (*iter)->SetId(id);
01392         }
01393         break;
01394 
01395     case e_Packed_pnt:
01396         SetPacked_pnt().SetId(id);
01397         break;
01398 
01399     case e_Mix:
01400         NON_CONST_ITERATE (CSeq_loc_mix::Tdata, iter, SetMix().Set()) {
01401             (*iter)->SetId(id);
01402         }
01403         break;
01404 
01405     case e_Whole:
01406         SetWhole(id);
01407         break;
01408 
01409     case e_Empty:
01410         SetEmpty(id);
01411         break;
01412 
01413     case e_Equiv:
01414         NON_CONST_ITERATE (CSeq_loc_equiv::Tdata, iter, SetEquiv().Set()) {
01415             (*iter)->SetId(id);
01416         }
01417         break;
01418 
01419     case e_Bond:
01420         if (GetBond().IsSetA()) {
01421             SetBond().SetA().SetId(id);
01422         }
01423         if (GetBond().IsSetB()) {
01424             SetBond().SetB().SetId(id);
01425         }
01426         break;
01427 
01428     case e_Feat:
01429         LOG_POST_X(1, Error
01430                       << "unhandled loc type in CSeq_loc::SetId(): e_Feat");
01431         break;
01432 
01433     default:
01434         LOG_POST_X(2, Error << "unhandled loc type in CSeq_loc::SetId(): "
01435                       << Which());
01436         break;
01437     }
01438 }
01439 
01440 
01441 void CSeq_loc::x_CheckId(const CSeq_id*& id) const
01442 {
01443     switch ( Which() ) {
01444     case e_not_set:
01445     case e_Null:
01446         {
01447             x_UpdateId(id, 0);
01448             break;
01449         }
01450     case e_Empty:
01451         {
01452             x_UpdateId(id, &GetEmpty());
01453             break;
01454         }
01455     case e_Whole:
01456         {
01457             x_UpdateId(id, &GetWhole());
01458             break;
01459         }
01460     case e_Int:
01461         {
01462             const CSeq_interval& loc = GetInt();
01463             x_UpdateId(id, &loc.GetId());
01464             break;
01465         }
01466     case e_Pnt:
01467         {
01468             const CSeq_point& pnt = GetPnt();
01469             x_UpdateId(id, &pnt.GetId());
01470             break;
01471         }
01472     case e_Packed_int:
01473         {
01474             // Check ID of each interval
01475             const CPacked_seqint& ints = GetPacked_int();
01476             ITERATE ( CPacked_seqint::Tdata, ii, ints.Get() ) {
01477                 const CSeq_interval& loc = **ii;
01478                 x_UpdateId(id, &loc.GetId());
01479             }
01480             break;
01481         }
01482     case e_Packed_pnt:
01483         {
01484             const CPacked_seqpnt& pnts = GetPacked_pnt();
01485             x_UpdateId(id, &pnts.GetId());
01486             break;
01487         }
01488     case e_Mix:
01489         {
01490             // Check ID of each sub-location.
01491             const CSeq_loc_mix& mix = GetMix();
01492             ITERATE( CSeq_loc_mix::Tdata, li, mix.Get() ) {
01493                 (*li)->CheckId(id);
01494             }
01495             break;
01496         }
01497     case e_Bond:
01498         {
01499             const CSeq_bond& bond = GetBond();
01500             if ( bond.CanGetA() ) {
01501                 x_UpdateId(id, &bond.GetA().GetId());
01502             }
01503             if ( bond.CanGetB() ) {
01504                 x_UpdateId(id, &bond.GetB().GetId());
01505             }
01506             break;
01507         }
01508     case e_Equiv:
01509         {
01510             // Doesn't make much sense to test equiv, but ...
01511             ITERATE(CSeq_loc_equiv::Tdata, li, GetEquiv().Get()) {
01512                 (*li)->CheckId(id);
01513             }
01514             break;
01515         }
01516     case e_Feat:
01517     default:
01518         {
01519             NCBI_THROW(CException, eUnknown,
01520                        "CSeq_loc::CheckId -- "
01521                        "unsupported location type");
01522         }
01523     }
01524 }
01525 
01526 
01527 void CSeq_loc::ChangeToMix(void)
01528 {
01529     switch ( Which() ) {
01530     case e_not_set:
01531         {
01532             SetMix();
01533             break;
01534         }
01535     case e_Mix:
01536         {
01537             break;
01538         }
01539     case e_Packed_int:
01540         {
01541             // unpack
01542             CRef<CSeq_loc> self(new CSeq_loc);
01543             self->Assign(*this, eShallow);
01544 
01545             CSeq_loc_mix& mix = SetMix();
01546             NON_CONST_ITERATE (CPacked_seqint::Tdata, it, self->SetPacked_int().Set()) {
01547                 CRef<CSeq_loc> ival(new CSeq_loc);
01548                 ival->SetInt(**it);
01549                 mix.Set().push_back(ival);
01550             }
01551             break;
01552         }
01553     default:
01554         {
01555             CRef<CSeq_loc> self(new CSeq_loc);
01556             self->Assign(*this, eShallow);
01557             CSeq_loc_mix& mix = SetMix();
01558             mix.AddSeqLoc(*self);
01559         }
01560     }
01561 }
01562 
01563 
01564 void CSeq_loc::ChangeToPackedInt(void)
01565 {
01566     switch ( Which() ) {
01567     case e_not_set:
01568         {
01569             SetPacked_int();
01570             return;
01571         }
01572     case e_Packed_int:
01573         {
01574             return;
01575         }
01576     case e_Int:
01577         {
01578             CConstRef<CSeq_interval> self(&GetInt());
01579             SetPacked_int().AddInterval(*self);
01580             return;
01581         }
01582     case e_Pnt:
01583         {
01584             // Make an interval of length 1
01585             CRef<CSeq_interval> new_int(new CSeq_interval);
01586             new_int->SetId().Assign(GetPnt().GetId());
01587             new_int->SetFrom(GetPnt().GetPoint());
01588             new_int->SetTo(GetPnt().GetPoint());
01589             if (GetPnt().IsSetStrand()) {
01590                 new_int->SetStrand(GetPnt().GetStrand());
01591             }
01592             if (GetPnt().IsSetFuzz()) {
01593                 new_int->SetFuzz_from().Assign(GetPnt().GetFuzz());
01594                 new_int->SetFuzz_to().Assign(GetPnt().GetFuzz());
01595             }
01596             SetPacked_int().AddInterval(*new_int);
01597             return;
01598         }
01599     case e_Mix:
01600         {
01601             // Recursively convert each sub-location to packed-int, then merge.
01602             // Work with copies of sub-locs so that if an exception is thrown
01603             // the original location remains unchanged.
01604             vector<CRef<CSeq_loc> > sub_locs;
01605             sub_locs.reserve(GetMix().Get().size());
01606             ITERATE (CSeq_loc_mix::Tdata, orig_sub_loc, GetMix().Get()) {
01607                 CRef<CSeq_loc> new_sub_loc(new CSeq_loc);
01608                 new_sub_loc->Assign(**orig_sub_loc);
01609                 new_sub_loc->ChangeToPackedInt();
01610                 sub_locs.push_back(new_sub_loc);
01611             }
01612             SetPacked_int();  // in case there are zero intervals
01613             ITERATE (vector<CRef<CSeq_loc> >, sub_loc, sub_locs) {
01614                 copy((*sub_loc)->GetPacked_int().Get().begin(),
01615                      (*sub_loc)->GetPacked_int().Get().end(),
01616                      back_inserter(SetPacked_int().Set()));
01617             }
01618             return;
01619         }
01620     default:
01621         {
01622             NCBI_THROW(CException, eUnknown,
01623                 "Can not convert location to packed-int");
01624         }
01625     }
01626 }
01627 
01628 
01629 void CSeq_loc::x_ChangeToMix(const CSeq_loc& other)
01630 {
01631     ChangeToMix();
01632     SetMix().AddSeqLoc(other);
01633 }
01634 
01635 
01636 void CSeq_loc::x_ChangeToPackedInt(const CSeq_interval& other)
01637 {
01638     _ASSERT(IsInt());
01639 
01640     ChangeToPackedInt();
01641     SetPacked_int().AddInterval(other);
01642 }
01643 
01644 
01645 void CSeq_loc::x_ChangeToPackedInt(const CSeq_loc& other)
01646 {
01647     _ASSERT(IsInt());
01648     _ASSERT(other.IsInt()  ||  other.IsPacked_int());
01649 
01650     ChangeToPackedInt();
01651 
01652     if ( other.IsInt() ) {
01653         SetPacked_int().AddInterval(other.GetInt());
01654     } else {  // other is packed int
01655         SetPacked_int().AddIntervals(other.GetPacked_int());
01656     }
01657 }
01658 
01659 
01660 void CSeq_loc::x_ChangeToPackedPnt(const CSeq_loc& other)
01661 {
01662     _ASSERT(IsPnt());
01663     _ASSERT(other.IsPnt()  ||  other.IsPacked_pnt());
01664 
01665     CRef<CSeq_point> pnt(&SetPnt());
01666     CPacked_seqpnt& ppnt = SetPacked_pnt();
01667     if ( pnt->IsSetStrand() ) {
01668         ppnt.SetStrand(pnt->GetStrand());
01669     }
01670     if ( pnt->IsSetId() ) {
01671         ppnt.SetId(pnt->SetId());
01672     }
01673     if ( pnt->IsSetFuzz() ) {
01674         ppnt.SetFuzz(pnt->SetFuzz());
01675     }
01676     ppnt.AddPoint(pnt->GetPoint());
01677 
01678     if ( other.IsPnt() ) {
01679         ppnt.AddPoint(other.GetPnt().GetPoint());
01680     } else { // other is packed point
01681         ppnt.AddPoints(other.GetPacked_pnt().GetPoints());
01682     }
01683 }
01684 
01685 
01686 template<typename T1, typename T2>
01687 bool s_CanAdd(const T1& obj1, const T2& obj2)
01688 {
01689     // test strands
01690     {{
01691         ENa_strand s1 = obj1.CanGetStrand() ? obj1.GetStrand() : eNa_strand_unknown;
01692         ENa_strand s2 = obj2.CanGetStrand() ? obj2.GetStrand() : eNa_strand_unknown;
01693         if ( s1 != s2 ) {
01694             return false;
01695         }
01696     }}
01697 
01698     // test ids
01699     {{
01700         const CSeq_id* id1 = obj1.CanGetId() ? &obj1.GetId() : 0;
01701         const CSeq_id* id2 = obj2.CanGetId() ? &obj2.GetId() : 0;
01702         if ( ((id1 != id2)  &&  (id1 == 0  ||  id2 == 0))  ||
01703              !id1->Match(*id2) ) {
01704             return false;
01705         }
01706     }}
01707 
01708     // test fuzz
01709     {{
01710         const CInt_fuzz* f1 = obj1.CanGetFuzz() ? &obj1.GetFuzz() : 0;
01711         const CInt_fuzz* f2 = obj2.CanGetFuzz() ? &obj2.GetFuzz() : 0;
01712         if ( ((f1 != f2)  &&  (f1 == 0  ||  f2 == 0))  ||
01713              !f1->Equals(*f2) ) {
01714             return false;
01715         }
01716     }}
01717 
01718     return true;
01719 }
01720 
01721 
01722 bool s_CanAdd(const CSeq_loc& loc1, const CSeq_loc& loc2)
01723 {
01724     switch ( loc1.Which() ) {
01725     case CSeq_loc::e_Pnt:
01726         {
01727             switch ( loc2.Which() ) {
01728             case CSeq_loc::e_Pnt:
01729                 return s_CanAdd(loc1.GetPnt(), loc2.GetPnt());
01730             case CSeq_loc::e_Packed_pnt:
01731                 return s_CanAdd(loc1.GetPnt(), loc2.GetPacked_pnt());
01732             default:
01733                 break;
01734             }
01735             break;
01736         }
01737     case CSeq_loc::e_Packed_pnt:
01738         {
01739             switch ( loc2.Which() ) {
01740             case CSeq_loc::e_Pnt:
01741                 return s_CanAdd(loc1.GetPacked_pnt(), loc2.GetPnt());
01742             case CSeq_loc::e_Packed_pnt:
01743                 return s_CanAdd(loc1.GetPacked_pnt(), loc2.GetPacked_pnt());
01744             default:
01745                 break;
01746             }
01747             break;
01748         }
01749     default:
01750         {
01751             return false;
01752         }
01753     }
01754 
01755     return false;
01756 }
01757 
01758 
01759 void CSeq_loc::Add(const CSeq_loc& other)
01760 {
01761     x_InvalidateCache();
01762     switch ( Which() ) {
01763     case e_not_set:
01764         {
01765             Assign(other);
01766             break;
01767         }
01768     case e_Null:
01769         {
01770             // ??? skip if other is null?
01771             x_ChangeToMix(other);
01772             break;
01773         }
01774     case e_Empty:
01775         {
01776             // ??? skip if other is empty and ids match?
01777             x_ChangeToMix(other);
01778             break;
01779         }
01780 
01781     case e_Whole:
01782         {
01783             x_ChangeToMix(other);
01784             break;
01785         }
01786     case e_Int:
01787         {
01788             if ( other.IsInt()  ||  other.IsPacked_int() ) {
01789                 x_ChangeToPackedInt(other);
01790             } else {
01791                 x_ChangeToMix(other);
01792             }
01793         }
01794         break;
01795     case e_Pnt:
01796         {
01797             if ( s_CanAdd(*this, other) ) {
01798                 x_ChangeToPackedPnt(other);
01799             } else {
01800                 x_ChangeToMix(other);
01801             }
01802             break;
01803         }
01804     case e_Packed_int:
01805         {
01806             if ( other.IsInt() ) {
01807                 SetPacked_int().AddInterval(other.GetInt());
01808             } else if ( other.IsPacked_int() ) {
01809                 SetPacked_int().AddIntervals(other.GetPacked_int());
01810             } else {
01811                 x_ChangeToMix(other);
01812             }
01813             break;
01814         }
01815     case e_Packed_pnt:
01816         {
01817             if ( s_CanAdd(*this, other) ) {
01818                 if ( other.IsPnt() ) {
01819                     SetPacked_pnt().AddPoint(other.GetPnt().GetPoint());
01820                 } else if ( other.IsPacked_pnt() ) {
01821                     SetPacked_pnt().AddPoints(other.GetPacked_pnt().GetPoints());
01822                 }
01823             } else {
01824                 x_ChangeToMix(other);
01825             }
01826             break;
01827         }
01828     case e_Mix:
01829         {
01830             SetMix().AddSeqLoc(other);
01831             break;
01832         }
01833     case e_Equiv:
01834         {
01835             SetEquiv().Add(other);
01836             break;
01837         }
01838     case e_Bond:
01839         {
01840             x_ChangeToMix(other);
01841             break;
01842         }
01843     case e_Feat:
01844     default:
01845         {
01846             NCBI_THROW(CException, eUnknown,
01847                        "CSeq_loc::Add -- "
01848                        "unsupported location type");
01849         }
01850     }
01851 }
01852 
01853 
01854 void CSeq_loc::FlipStrand(void)
01855 {
01856     switch ( Which() ) {
01857     case e_Int:
01858         SetInt().FlipStrand();
01859         break;
01860     case e_Pnt:
01861         SetPnt().FlipStrand();
01862         break;
01863     case e_Packed_int:
01864         SetPacked_int().FlipStrand();
01865         break;
01866     case e_Packed_pnt:
01867         SetPacked_pnt().FlipStrand();
01868         break;
01869     case e_Mix:
01870         SetMix().FlipStrand();
01871         break;
01872 
01873     default:
01874         break;
01875     }
01876 }
01877 
01878 
01879 // Types used in operations with seq-locs
01880 
01881 class CRangeWithFuzz : public CSeq_loc::TRange
01882 {
01883 public:
01884     typedef CSeq_loc::TRange TParent;
01885     typedef CConstRef<CInt_fuzz>  TFuzz;
01886 
01887     CRangeWithFuzz(const TParent& rg)
01888         : TParent(rg)
01889     {
01890     }
01891     CRangeWithFuzz(const CSeq_loc_CI& it)
01892         : TParent(it.GetRange()),
01893           m_Fuzz_from(it.GetFuzzFrom()),
01894           m_Fuzz_to(it.GetFuzzTo())
01895     {
01896     }
01897     void ResetFuzzFrom(void) { m_Fuzz_from.Reset(); }
01898     void ResetFuzzTo(void) { m_Fuzz_to.Reset(); }
01899     TFuzz IsSetFuzzFrom(void) const { return m_Fuzz_from; }
01900     TFuzz IsSetFuzzTo(void) const { return m_Fuzz_to; }
01901     const CInt_fuzz& GetFuzzFrom(void) const { return *m_Fuzz_from; }
01902     const CInt_fuzz& GetFuzzTo(void) const { return *m_Fuzz_to; }
01903 
01904     void CopyFrom(const CRangeWithFuzz& rg)
01905     {
01906         SetFrom(rg.GetFrom());
01907         m_Fuzz_from = rg.m_Fuzz_from;
01908     }
01909 
01910     void CopyTo(const CRangeWithFuzz& rg)
01911     {
01912         SetTo(rg.GetTo());
01913         m_Fuzz_to = rg.m_Fuzz_to;
01914     }
01915 
01916     CRangeWithFuzz& operator +=(const CRangeWithFuzz& rg)
01917     {
01918         TParent::position_type old_from = GetFrom();
01919         TParent::position_type old_to = GetTo();
01920         TParent::operator+=(rg);
01921         if (old_from != GetFrom()) {
01922             m_Fuzz_from.Reset(rg.m_Fuzz_from);
01923         }
01924         else if (old_from == rg.GetFrom()) {
01925             ResetFuzzFrom();
01926         }
01927         if (old_to != GetTo()) {
01928             m_Fuzz_to.Reset(rg.m_Fuzz_to);
01929         }
01930         else if (old_to == rg.GetTo()) {
01931             ResetFuzzTo();
01932         }
01933         return *this;
01934     }
01935 
01936     CRangeWithFuzz& operator +=(const TParent& rg)
01937     {
01938         TParent::position_type old_from = GetFrom();
01939         TParent::position_type old_to = GetTo();
01940         TParent::operator+=(rg);
01941         if (old_from != GetFrom()  ||  old_from == rg.GetFrom()) {
01942             ResetFuzzFrom();
01943         }
01944         if (old_to != GetTo()  ||  old_to == rg.GetTo()) {
01945             ResetFuzzTo();
01946         }
01947         return *this;
01948     }
01949 
01950 private:
01951     TFuzz m_Fuzz_from;
01952     TFuzz m_Fuzz_to;
01953 };
01954 
01955 
01956 typedef CRangeWithFuzz                      TRangeWithFuzz;
01957 typedef vector<TRangeWithFuzz>              TRanges;
01958 typedef map<CSeq_id_Handle, TRanges>        TIdToRangeMap;
01959 typedef CRangeCollection<TSeqPos>           TRangeColl;
01960 typedef map<CSeq_id_Handle, TRangeColl>     TIdToRangeColl;
01961 
01962 
01963 class CRange_Less
01964 {
01965 public:
01966     CRange_Less(void) {}
01967 
01968     bool operator() (const TRangeWithFuzz& rg1, const TRangeWithFuzz& rg2) const
01969     {
01970         if ( rg1.IsWhole() ) {
01971             return !rg2.IsWhole();
01972         }
01973         if ( rg1.Empty() ) {
01974             return !rg2.Empty()  &&  !rg2.IsWhole();
01975         }
01976         return !rg2.IsWhole()  &&  !rg2.Empty()  &&  rg1 < rg2;
01977     }
01978 };
01979 
01980 
01981 class CRange_ReverseLess
01982 {
01983 public:
01984     CRange_ReverseLess(void) {}
01985 
01986     bool operator() (const TRangeWithFuzz& rg1, const TRangeWithFuzz& rg2) const
01987     {
01988         if ( rg1.IsWhole() ) {
01989             return !rg2.IsWhole();
01990         }
01991         if ( rg1.Empty() ) {
01992             return !rg2.Empty()  &&  !rg2.IsWhole();
01993         }
01994         if ( rg2.IsWhole()  ||  rg2.Empty() ) {
01995             return false;
01996         }
01997         if (rg1.GetTo() != rg2.GetTo()) {
01998             return rg1.GetTo() > rg2.GetTo();
01999         }
02000         return rg1.GetFrom() < rg2.GetFrom();
02001     }
02002 };
02003 
02004 
02005 inline
02006 bool x_MatchStrand(ENa_strand str1, ENa_strand str2, CSeq_loc::TOpFlags flags)
02007 {
02008     return (flags & CSeq_loc::fStrand_Ignore) != 0 ||
02009     IsReverse(str1) == IsReverse(str2);
02010 }
02011 
02012 
02013 bool x_MergeRanges(TRangeWithFuzz& rg1, ENa_strand str1,
02014                    const TRangeWithFuzz& rg2, ENa_strand str2,
02015                    CSeq_loc::TOpFlags flags)
02016 {
02017     if ( !x_MatchStrand(str1, str2, flags) ) {
02018         return false;
02019     }
02020     // Check contained
02021     if ( (flags & CSeq_loc::fMerge_Contained) != 0 ) {
02022         if (rg1.GetFrom() <= rg2.GetFrom()  &&  rg1.GetTo() >= rg2.GetTo()) {
02023             // rg2 already contained in rg1
02024             if (rg1.GetFrom() == rg2.GetFrom()) {
02025                 rg1.ResetFuzzFrom();
02026             }
02027             if (rg1.GetTo() == rg2.GetTo()) {
02028                 rg1.ResetFuzzTo();
02029             }
02030             return true;
02031         }
02032         if (rg1.GetFrom() >= rg2.GetFrom()  &&  rg1.GetTo() <= rg2.GetTo()) {
02033             // rg1 contained in rg2
02034             bool reset_from = rg1.GetFrom() == rg2.GetFrom();
02035             bool reset_to = rg1.GetTo() == rg2.GetTo();
02036             rg1 = rg2;
02037             if (reset_from) {
02038                 rg1.ResetFuzzFrom();
02039             }
02040             if (reset_to) {
02041                 rg1.ResetFuzzTo();
02042             }
02043             return true;
02044         }
02045     }
02046     // Check overlapping
02047     if ( (flags & CSeq_loc::fMerge_OverlappingOnly) != 0  &&
02048         rg1.IntersectingWith(rg2) ) {
02049         rg1 += rg2;
02050         return true;
02051     }
02052     // Check abutting
02053     if ((flags & CSeq_loc::fMerge_AbuttingOnly) != 0) {
02054         if ( !IsReverse(str1) ) {
02055             if ( rg1.GetToOpen() == rg2.GetFrom() ) {
02056                 rg1.CopyTo(rg2);
02057                 return true;
02058             }
02059         }
02060         else {
02061             if (rg1.GetFrom() == rg2.GetToOpen()) {
02062                 rg1.CopyFrom(rg2);
02063                 return true;
02064             }
02065         }
02066     }
02067     return false;
02068 }
02069 
02070 
02071 void x_PushRange(CSeq_loc& dst,
02072                  CSeq_id_Handle idh,
02073                  TRangeWithFuzz rg,
02074                  ENa_strand strand)
02075 {
02076     if (dst.Which() != CSeq_loc::e_not_set) {
02077         if ( !dst.IsMix() ) {
02078             dst.ChangeToMix();
02079         }
02080     }
02081     if ( !idh ) {
02082         // NULL
02083         if (dst.IsMix()) {
02084             CRef<CSeq_loc> null_loc(new CSeq_loc);
02085             null_loc->SetNull();
02086             dst.SetMix().Set().push_back(null_loc);
02087         }
02088         else {
02089             dst.SetNull();
02090         }
02091     }
02092     else if ( rg.IsWhole() ) {
02093         if (dst.IsMix()) {
02094             CRef<CSeq_loc> whole(new CSeq_loc);
02095             whole->SetWhole().Assign(*idh.GetSeqId());
02096             dst.SetMix().Set().push_back(whole);
02097         }
02098         else {
02099             dst.SetWhole().Assign(*idh.GetSeqId());
02100         }
02101     }
02102     else if ( rg.Empty() ) {
02103         if (dst.IsMix()) {
02104             CRef<CSeq_loc> empty(new CSeq_loc);
02105             empty->SetEmpty().Assign(*idh.GetSeqId());
02106             dst.SetMix().Set().push_back(empty);
02107         }
02108         else {
02109             dst.SetEmpty().Assign(*idh.GetSeqId());
02110         }
02111     }
02112     else if ( rg.GetLength() == 1 ) {
02113         // Preserve points
02114         CRef<CSeq_id> id(new CSeq_id);
02115         id->Assign(*idh.GetSeqId());
02116         CRef<CSeq_point> pnt(new CSeq_point);
02117         pnt->SetId(*id);
02118         pnt->SetPoint(rg.GetFrom());
02119         if (strand != eNa_strand_unknown) {
02120             pnt->SetStrand(strand);
02121         }
02122         if ( rg.IsSetFuzzFrom() ) {
02123             pnt->SetFuzz().Assign(rg.GetFuzzFrom());
02124         }
02125         if (dst.IsMix()) {
02126             CRef<CSeq_loc> pnt_loc(new CSeq_loc);
02127             pnt_loc->SetPnt(*pnt);
02128             dst.SetMix().Set().push_back(pnt_loc);
02129         }
02130         else {
02131             dst.SetPnt(*pnt);
02132         }
02133     }
02134     else {
02135         CRef<CSeq_id> id(new CSeq_id);
02136         id->Assign(*idh.GetSeqId());
02137         if (dst.IsMix()) {
02138             dst.SetMix().AddInterval(*id,
02139                                     rg.GetFrom(),
02140                                     rg.GetTo(),
02141                                     strand);
02142             if ( rg.IsSetFuzzFrom() ) {
02143                 dst.SetMix().Set().back()->SetInt().SetFuzz_from()
02144                     .Assign(rg.GetFuzzFrom());
02145             }
02146             if ( rg.IsSetFuzzTo() ) {
02147                 dst.SetMix().Set().back()->SetInt().SetFuzz_to()
02148                     .Assign(rg.GetFuzzTo());
02149             }
02150         }
02151         else {
02152             CRef<CSeq_interval> interval(new CSeq_interval(*id,
02153                                                            rg.GetFrom(),
02154                                                            rg.GetTo(),
02155                                                            strand));
02156             if ( rg.IsSetFuzzFrom() ) {
02157                 interval->SetFuzz_from().Assign(rg.GetFuzzFrom());
02158             }
02159             if ( rg.IsSetFuzzTo() ) {
02160                 interval->SetFuzz_to().Assign(rg.GetFuzzTo());
02161             }
02162             dst.SetInt(*interval);
02163         }
02164     }
02165 }
02166 
02167 
02168 void x_SingleRange(CSeq_loc& dst,
02169                    const CSeq_loc& src,
02170                    ISynonymMapper& syn_mapper)
02171 {
02172     // Create a single range
02173     TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty());
02174     CSeq_id_Handle first_id;
02175     ENa_strand first_strand = eNa_strand_unknown;
02176     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02177         CSeq_id_Handle next_id = syn_mapper.GetBestSynonym(it.GetSeq_id());
02178         if ( !next_id ) {
02179             // Ignore NULLs
02180             continue;
02181         }
02182         if ( first_id ) {
02183             // Seq-id may be missing for NULL seq-loc
02184             if (next_id  &&  first_id != next_id) {
02185                 NCBI_THROW(CException, eUnknown,
02186                     "Can not merge multi-id seq-loc");
02187             }
02188         }
02189         else {
02190             first_id = next_id;
02191             first_strand = it.GetStrand();
02192         }
02193         total_rg += TRangeWithFuzz(it);
02194     }
02195     if ( first_id ) {
02196         CRef<CSeq_id> id(new CSeq_id);
02197         id->Assign(*first_id.GetSeqId());
02198         CRef<CSeq_interval> interval(new CSeq_interval(*id,
02199                                                        total_rg.GetFrom(),
02200                                                        total_rg.GetTo(),
02201                                                        first_strand));
02202         if ( total_rg.IsSetFuzzFrom() ) {
02203             interval->SetFuzz_from().Assign(total_rg.GetFuzzFrom());
02204         }
02205         if ( total_rg.IsSetFuzzTo() ) {
02206             interval->SetFuzz_to().Assign(total_rg.GetFuzzTo());
02207         }
02208         dst.SetInt(*interval);
02209     }
02210     else {
02211         // Null seq-loc
02212         dst.SetNull();
02213     }
02214 }
02215 
02216 
02217 void x_RangesToSeq_loc(CSeq_loc& dst,
02218                        TIdToRangeMap& id_map,
02219                        ENa_strand default_strand,
02220                        CSeq_loc::TOpFlags flags)
02221 {
02222     // Iterate ids for each strand
02223     NON_CONST_ITERATE(TIdToRangeMap, id_it, id_map) {
02224         if ( !id_it->first ) {
02225             // All NULLs merged
02226             x_PushRange(dst,
02227                         id_it->first,
02228                         TRangeWithFuzz(TRangeWithFuzz::GetEmpty()),
02229                         eNa_strand_unknown);
02230             continue;
02231         }
02232         CRef<CSeq_id> id(new CSeq_id);
02233         id->Assign(*id_it->first.GetSeqId());
02234         TRanges& ranges = id_it->second;
02235         if ( (flags & CSeq_loc::fSort) != 0 ) {
02236             if ( !IsReverse(default_strand) ) {
02237                 sort(ranges.begin(), ranges.end(), CRange_Less());
02238             }
02239             else {
02240                 sort(ranges.begin(), ranges.end(), CRange_ReverseLess());
02241             }
02242         }
02243         // Merge ranges according to the flags, add to destination
02244         TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
02245         bool have_range = false;
02246         ITERATE(TRanges, rg, ranges) {
02247             if (x_MergeRanges(last_rg, default_strand,
02248                             *rg, default_strand,
02249                             flags)) {
02250                 have_range = true;
02251                 continue;
02252             }
02253             // No merging - push current range, reset last values
02254             if (have_range) {
02255                 x_PushRange(dst, id_it->first, last_rg, default_strand);
02256             }
02257             last_rg = *rg;
02258             have_range = true;
02259         }
02260         if (have_range) {
02261             x_PushRange(dst, id_it->first, last_rg, default_strand);
02262         }
02263     }
02264 }
02265 
02266 
02267 void x_MergeNoSort(CSeq_loc& dst,
02268                    const CSeq_loc& src,
02269                    CSeq_loc::TOpFlags flags,
02270                    ISynonymMapper& syn_mapper)
02271 {
02272     _ASSERT((flags & CSeq_loc::fSort) == 0);
02273     CSeq_id_Handle last_id;
02274     TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
02275     ENa_strand last_strand = eNa_strand_unknown;
02276     bool have_range = false;
02277     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02278         CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id());
02279         // ID and strand must match
02280         TRangeWithFuzz it_rg(it);
02281         if ( have_range  &&  last_id == idh ) {
02282             if (x_MergeRanges(last_rg,
02283                               last_strand,
02284                               it_rg,
02285                               it.GetStrand(),
02286                               flags)) {
02287                 have_range = true;
02288                 continue;
02289             }
02290         }
02291         // No merging - push current range, reset last values
02292         if ( have_range ) {
02293             x_PushRange(dst, last_id, last_rg, last_strand);
02294         }
02295         last_id = idh;
02296         last_rg = it_rg;
02297         last_strand = it.GetStrand();
02298         have_range = true;
02299     }
02300     if ( have_range ) {
02301         x_PushRange(dst, last_id, last_rg, last_strand);
02302     }
02303 }
02304 
02305 
02306 void x_MergeAndSort(CSeq_loc& dst,
02307                     const CSeq_loc& src,
02308                     CSeq_loc::TOpFlags flags,
02309                     ISynonymMapper& syn_mapper)
02310 {
02311     bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
02312     // Id -> range map for both strands
02313     auto_ptr<TIdToRangeMap> pid_map_minus(use_strand ?
02314         new TIdToRangeMap : 0);
02315     TIdToRangeMap id_map_plus;
02316     TIdToRangeMap& id_map_minus = use_strand ?
02317         *pid_map_minus.get() : id_map_plus;
02318 
02319     // Prepare default strands
02320     ENa_strand default_plus = use_strand ?
02321         eNa_strand_plus : eNa_strand_unknown;
02322     ENa_strand default_minus = use_strand ?
02323         eNa_strand_minus : eNa_strand_unknown;
02324 
02325     // Split location by by id/strand/range
02326     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02327         CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id());
02328         if ( IsReverse(it.GetStrand()) ) {
02329             id_map_minus[idh].push_back(TRangeWithFuzz(it));
02330         }
02331         else {
02332             id_map_plus[idh].push_back(TRangeWithFuzz(it));
02333         }
02334     }
02335 
02336     x_RangesToSeq_loc(dst, id_map_plus, default_plus, flags);
02337     if ( use_strand ) {
02338         x_RangesToSeq_loc(dst, id_map_minus, default_minus, flags);
02339     }
02340 }
02341 
02342 
02343 void x_SingleRange(CSeq_loc& dst,
02344                    const CSeq_loc& src,
02345                    TIdToRangeColl& rg_coll_plus,
02346                    TIdToRangeColl& rg_coll_minus,
02347                    ISynonymMapper& syn_mapper,
02348                    ILengthGetter& len_getter)
02349 {
02350     TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty());
02351     CSeq_id_Handle first_id;
02352     ENa_strand first_strand = eNa_strand_unknown;
02353     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02354         CSeq_id_Handle next_id = syn_mapper.GetBestSynonym(it.GetSeq_id());
02355         if ( !next_id ) {
02356             // Ignore NULLs
02357             continue;
02358         }
02359         if ( first_id ) {
02360             // Seq-id may be missing for NULL seq-loc
02361             if (next_id  &&  first_id != next_id) {
02362                 NCBI_THROW(CException, eUnknown,
02363                     "Can not merge multi-id seq-loc");
02364             }
02365         }
02366         else {
02367             first_id = next_id;
02368             first_strand = it.GetStrand();
02369         }
02370         TRangeWithFuzz it_range = TRangeWithFuzz(it);
02371         if (it_range.GetFrom() >= total_rg.GetFrom()  &&
02372             it_range.GetTo() <= total_rg.GetTo()) {
02373             // Nothing new can be added from this interval
02374             continue;
02375         }
02376         if ( it_range.IsWhole() ) {
02377             it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
02378             it_range.ResetFuzzFrom();
02379             it_range.ResetFuzzTo();
02380         }
02381         TRangeColl it_rg_coll(it_range);
02382         TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
02383             rg_coll_minus : rg_coll_plus;
02384         TIdToRangeColl::const_iterator id_it = rg_coll.find(next_id);
02385         if (id_it != rg_coll.end()) {
02386             it_rg_coll -= id_it->second;
02387         }
02388         total_rg += it_rg_coll.GetLimits();
02389     }
02390 
02391     if ( first_id ) {
02392         CRef<CSeq_id> id(new CSeq_id);
02393         id->Assign(*first_id.GetSeqId());
02394         CRef<CSeq_interval> interval(new CSeq_interval(*id,
02395                                                        total_rg.GetFrom(),
02396                                                        total_rg.GetTo(),
02397                                                        first_strand));
02398         dst.SetInt(*interval);
02399     }
02400     else {
02401         // Null seq-loc
02402         dst.SetNull();
02403     }
02404 }
02405 
02406 
02407 void x_SubNoSort(CSeq_loc& dst,
02408                  const CSeq_loc& src,
02409                  TIdToRangeColl& rg_coll_plus,
02410                  TIdToRangeColl& rg_coll_minus,
02411                  ISynonymMapper& syn_mapper,
02412                  ILengthGetter& len_getter,
02413                  CSeq_loc::TOpFlags flags)
02414 {
02415     _ASSERT((flags & CSeq_loc::fSort) == 0);
02416     CSeq_id_Handle last_id;
02417     TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
02418     ENa_strand last_strand = eNa_strand_unknown;
02419     bool have_range = false;
02420     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02421         CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id());
02422         TRangeWithFuzz it_range = TRangeWithFuzz(it);
02423         if ( it_range.IsWhole() ) {
02424             it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
02425         }
02426         TRangeColl it_rg_coll(it_range);
02427         TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
02428             rg_coll_minus : rg_coll_plus;
02429         TIdToRangeColl::const_iterator id_it = rg_coll.find(idh);
02430         if (id_it != rg_coll.end()) {
02431             it_rg_coll -= id_it->second;
02432         }
02433         ITERATE(TRangeColl, rg_it, it_rg_coll) {
02434             if ( have_range  &&  last_id == idh ) {
02435                 if (x_MergeRanges(last_rg,
02436                                 last_strand,
02437                                 *rg_it,
02438                                 it.GetStrand(),
02439                                 flags)) {
02440                     have_range = true;
02441                     continue;
02442                 }
02443             }
02444             // No merging - push current range, reset last values
02445             if ( have_range ) {
02446                 x_PushRange(dst, last_id, last_rg, last_strand);
02447             }
02448             last_id = idh;
02449             last_rg = *rg_it;
02450             last_strand = it.GetStrand();
02451             have_range = true;
02452         }
02453     }
02454     if ( have_range ) {
02455         x_PushRange(dst, last_id, last_rg, last_strand);
02456     }
02457 }
02458 
02459 
02460 void x_SubAndSort(CSeq_loc& dst,
02461                   const CSeq_loc& src,
02462                   TIdToRangeColl& rg_coll_plus,
02463                   TIdToRangeColl& rg_coll_minus,
02464                   ISynonymMapper& syn_mapper,
02465                   ILengthGetter& len_getter,
02466                   CSeq_loc::TOpFlags flags)
02467 {
02468     bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
02469 
02470     // Id -> range map for both strands
02471     auto_ptr<TIdToRangeMap> p_id_map_minus(use_strand ?
02472         new TIdToRangeMap : 0);
02473     TIdToRangeMap id_map_plus;
02474     TIdToRangeMap& id_map_minus = use_strand ?
02475         *p_id_map_minus.get() : id_map_plus;
02476 
02477     // Prepare default strands
02478     ENa_strand default_plus = use_strand ?
02479         eNa_strand_plus : eNa_strand_unknown;
02480     ENa_strand default_minus = use_strand ?
02481         eNa_strand_minus : eNa_strand_unknown;
02482 
02483     for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
02484         CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id());
02485         TRangeWithFuzz it_range = it.GetRange();
02486         if ( it_range.IsWhole() ) {
02487             it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
02488             it_range.ResetFuzzFrom();
02489             it_range.ResetFuzzTo();
02490         }
02491         TRangeColl it_rg_coll(it_range);
02492         TRanges& rg_map = IsReverse(it.GetStrand()) ?
02493             id_map_minus[idh] : id_map_plus[idh];
02494         TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
02495             rg_coll_minus : rg_coll_plus;
02496         TIdToRangeColl::const_iterator id_it = rg_coll.find(idh);
02497         if (id_it != rg_coll.end()) {
02498             it_rg_coll -= id_it->second;
02499         }
02500         ITERATE(TRangeColl, rg_it, it_rg_coll) {
02501             rg_map.push_back(*rg_it);
02502         }
02503     }
02504 
02505     x_RangesToSeq_loc(dst, id_map_plus, default_plus, flags);
02506     if ( use_strand ) {
02507         x_RangesToSeq_loc(dst, id_map_minus, default_minus, flags);
02508     }
02509 }
02510 
02511 
02512 class CDummySynonymMapper : public ISynonymMapper
02513 {
02514 public:
02515     CDummySynonymMapper(void) {}
02516     virtual ~CDummySynonymMapper(void) {}
02517 
02518     virtual CSeq_id_Handle GetBestSynonym(const CSeq_id& id)
02519         {
02520             return CSeq_id_Handle::GetHandle(id);
02521         }
02522 };
02523 
02524 
02525 class CDummyLengthGetter : public ILengthGetter
02526 {
02527 public:
02528     CDummyLengthGetter(void) {}
02529     virtual ~CDummyLengthGetter(void) {}
02530 
02531     virtual TSeqPos GetLength(const CSeq_id& id)
02532         {
02533             return CSeq_loc::TRange::GetWholeToOpen();
02534         }
02535 };
02536 
02537 
02538 CRef<CSeq_loc> CSeq_loc::Merge(TOpFlags        flags,
02539                                ISynonymMapper* syn_mapper) const
02540 {
02541     auto_ptr<CDummySynonymMapper> p_mapper;
02542     if ( !syn_mapper ) {
02543         p_mapper.reset(new CDummySynonymMapper);
02544         syn_mapper = p_mapper.get();
02545     }
02546 
02547     CRef<CSeq_loc> ret(new CSeq_loc);
02548     if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
02549         x_SingleRange(*ret, *this, *syn_mapper);
02550     }
02551     else if ( (flags & CSeq_loc::fSort) == 0 ) {
02552         x_MergeNoSort(*ret, *this, flags, *syn_mapper);
02553     }
02554     else {
02555         x_MergeAndSort(*ret, *this, flags, *syn_mapper);
02556     }
02557     return ret;
02558 }
02559 
02560 
02561 CRef<CSeq_loc> CSeq_loc::Add(const CSeq_loc& other,
02562                              TOpFlags        flags,
02563                              ISynonymMapper* syn_mapper) const
02564 {
02565     auto_ptr<CDummySynonymMapper> p_mapper;
02566     if ( !syn_mapper ) {
02567         p_mapper.reset(new CDummySynonymMapper);
02568         syn_mapper = p_mapper.get();
02569     }
02570 
02571     CRef<CSeq_loc> ret(new CSeq_loc);
02572     CSeq_loc tmp;
02573     tmp.SetMix().AddSeqLoc(const_cast<CSeq_loc&>(*this));
02574     tmp.SetMix().AddSeqLoc(const_cast<CSeq_loc&>(other));
02575     if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
02576         x_SingleRange(*ret, tmp, *syn_mapper);
02577     }
02578     else if ( (flags & CSeq_loc::fSort) == 0 ) {
02579         x_MergeNoSort(*ret, tmp, flags, *syn_mapper);
02580     }
02581     else {
02582         x_MergeAndSort(*ret, tmp, flags, *syn_mapper);
02583     }
02584     return ret;
02585 }
02586 
02587 
02588 CRef<CSeq_loc> CSeq_loc::Subtract(const CSeq_loc& other,
02589                                   TOpFlags        flags,
02590                                   ISynonymMapper* syn_mapper,
02591                                   ILengthGetter*  len_getter) const
02592 {
02593     auto_ptr<CDummySynonymMapper> p_mapper;
02594     if ( !syn_mapper ) {
02595         p_mapper.reset(new CDummySynonymMapper);
02596         syn_mapper = p_mapper.get();
02597     }
02598     auto_ptr<CDummyLengthGetter> p_getter;
02599     if ( !len_getter ) {
02600         p_getter.reset(new CDummyLengthGetter);
02601         len_getter = p_getter.get();
02602     }
02603 
02604     CRef<CSeq_loc> ret(new CSeq_loc);
02605 
02606     bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
02607 
02608     // Range collection for each strand
02609     auto_ptr<TIdToRangeColl> p_rg_coll_minus(use_strand ?
02610         new TIdToRangeColl : 0);
02611     TIdToRangeColl rg_coll_plus;
02612     TIdToRangeColl& rg_coll_minus = use_strand ?
02613         *p_rg_coll_minus.get() : rg_coll_plus;
02614 
02615     // Create range collection(s) for loc2
02616     for (CSeq_loc_CI it(other); it; ++it) {
02617         if ( it.IsEmpty() ) {
02618             continue;
02619         }
02620         CSeq_id_Handle idh = syn_mapper->GetBestSynonym(it.GetSeq_id());
02621         TRangeColl& rmap = IsReverse(it.GetStrand()) ?
02622             rg_coll_minus[idh] : rg_coll_plus[idh];
02623         rmap += TRangeWithFuzz(it);
02624     }
02625 
02626     if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
02627         x_SingleRange(*ret,
02628                       *this,
02629                       rg_coll_plus,
02630                       rg_coll_minus,
02631                       *syn_mapper,
02632                       *len_getter);
02633     }
02634     else if ( (flags & CSeq_loc::fSort) == 0 ) {
02635         x_SubNoSort(*ret,
02636                     *this,
02637                     rg_coll_plus,
02638                     rg_coll_minus,
02639                     *syn_mapper,
02640                     *len_getter,
02641                     flags);
02642     }
02643     else {
02644         x_SubAndSort(*ret,
02645                      *this,
02646                      rg_coll_plus,
02647                      rg_coll_minus,
02648                      *syn_mapper,
02649                      *len_getter,
02650                      flags);
02651     }
02652 
02653     return ret;
02654 }
02655 
02656 
02657 CRef<CSeq_loc> CSeq_loc::Intersect(const CSeq_loc& other,
02658                                    TOpFlags        flags,
02659                                    ISynonymMapper* syn_mapper) const
02660 {
02661     auto_ptr<CDummyLengthGetter> len_getter(new CDummyLengthGetter);
02662     CRef<CSeq_loc> tmp = Subtract(other,
02663         // This flag should be used only in the second subtraction
02664         flags & ~fMerge_SingleRange,
02665         syn_mapper, len_getter.get());
02666     return Subtract(*tmp, flags, syn_mapper, len_getter.get());
02667 }
02668 
02669 
02670 void CSeq_loc::SetStrand(ENa_strand strand)
02671 {
02672     switch ( Which() ) {
02673     case e_Int:
02674         SetInt().SetStrand(strand);
02675         break;
02676     case e_Pnt:
02677         SetPnt().SetStrand(strand);
02678         break;
02679     case e_Packed_int:
02680         SetPacked_int().SetStrand(strand);
02681         break;
02682     case e_Packed_pnt:
02683         SetPacked_pnt().SetStrand(strand);
02684         break;
02685     case e_Mix:
02686         SetMix().SetStrand(strand);
02687         break;
02688 
02689     default:
02690         break;
02691     }
02692 }
02693 
02694 
02695 void CSeq_loc::ResetStrand(void)
02696 {
02697     switch ( Which() ) {
02698     case e_Int:
02699         SetInt().ResetStrand();
02700         break;
02701     case e_Pnt:
02702         SetPnt().ResetStrand();
02703         break;
02704     case e_Packed_int:
02705         SetPacked_int().ResetStrand();
02706         break;
02707     case e_Packed_pnt:
02708         SetPacked_pnt().ResetStrand();
02709         break;
02710     case e_Mix:
02711         SetMix().ResetStrand();
02712         break;
02713 
02714     default:
02715         break;
02716     }
02717 }
02718 
02719 
02720 END_objects_SCOPE // namespace ncbi::objects::
02721 END_NCBI_SCOPE
02722 
02723 #undef NCBI_USE_ERRCODE_X
02724 
02725 

Generated on Wed Dec 9 05:08:11 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:18:09 2009 by modify_doxy.py rev. 173732