NCBI C++ ToolKit
Seq_loc.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: Seq_loc.cpp 99792 2023-05-10 18:02:42Z vasilche $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Author: Cliff Clausen, Eugene Vasilchenko
27  *
28  * File Description:
29  * .......
30  *
31  * Remark:
32  * This code was originally generated by application DATATOOL
33  * using specifications from the ASN data definition file
34  * 'seqloc.asn'.
35  *
36  * ===========================================================================
37  */
38 
39 #include <ncbi_pch.hpp>
40 #include <serial/enumvalues.hpp>
52 #include <util/range_coll.hpp>
55 #include <algorithm>
56 
57 
58 #define NCBI_USE_ERRCODE_X Objects_SeqLoc
59 
61 BEGIN_objects_SCOPE // namespace ncbi::objects::
62 
63 
64 // CSeqLocException
65 const char* CSeqLocException::GetErrCodeString(void) const
66 {
67  switch (GetErrCode()) {
68  case eNotSet: return "eNotSet";
69  case eMultipleId: return "eMultipleId";
70  case eUnsupported: return "eUnsupported";
71  case eBadLocation: return "eBadLocation";
72  case eBadIterator: return "eBadIterator";
73  case eIncomatible: return "eIncomatible";
74  case eOutOfRange: return "eOutOfRange";
75  case eOtherError: return "eOtherError";
76  default: return CException::GetErrCodeString();
77  }
78 }
79 
80 
81 // constructors
83 {
85  switch ( index ) {
86  case e_Null:
87  {
88  SetNull();
89  break;
90  }
91  case e_Empty:
92  {
93  SetEmpty();
94  break;
95  }
96  case e_Whole:
97  {
98  SetWhole();
99  break;
100  }
101  case e_Int:
102  {
103  SetInt();
104  break;
105  }
106  case e_Packed_int:
107  {
108  SetPacked_int();
109  break;
110  }
111  case e_Pnt:
112  {
113  SetPnt();
114  break;
115  }
116  case e_Packed_pnt:
117  {
118  SetPacked_pnt();
119  break;
120  }
121  case e_Mix:
122  {
123  SetMix();
124  break;
125  }
126  case e_Equiv:
127  {
128  SetEquiv();
129  break;
130  }
131  case e_Bond:
132  {
133  SetBond();
134  break;
135  }
136  case e_Feat:
137  {
138  SetFeat();
139  break;
140  }
141  case e_not_set:
142  default:
143  break;
144  }
145 }
146 
147 
149 {
150  InvalidateCache();
151  SetPnt(*new CSeq_point(id, point, strand));
152 }
153 
154 
155 CSeq_loc::CSeq_loc(TId& id, const TPoints& points, TStrand strand)
156 {
157  InvalidateCache();
158  if ( points.size() == 1 ) {
159  SetPnt(*new CSeq_point(id, points.front(), strand));
160  } else {
161  SetPacked_pnt(*new CPacked_seqpnt(id, points, strand));
162  }
163 }
164 
165 
167 {
168  InvalidateCache();
169  SetInt(*new CSeq_interval(id, from, to, strand));
170 }
171 
172 
173 CSeq_loc::CSeq_loc(TId& id, TRanges ranges, TStrand strand)
174 {
175  InvalidateCache();
176  if ( ranges.size() == 1 ) {
177  SetInt(*new CSeq_interval(id,
178  ranges.front().GetFrom(), ranges.front().GetTo(), strand));
179  } else {
180  SetPacked_int(*new CPacked_seqint(id, ranges, strand));
181  }
182 }
183 
184 
185 // destructor
187 {
188 }
189 
190 
191 inline
192 void x_Assign(CInt_fuzz& dst, const CInt_fuzz& src)
193 {
194  switch ( src.Which() ) {
196  dst.Reset();
197  break;
198  case CInt_fuzz::e_P_m:
199  dst.SetP_m(src.GetP_m());
200  break;
201  case CInt_fuzz::e_Range:
202  dst.SetRange().SetMin(src.GetRange().GetMin());
203  dst.SetRange().SetMax(src.GetRange().GetMax());
204  break;
205  case CInt_fuzz::e_Pct:
206  dst.SetPct(src.GetPct());
207  break;
208  case CInt_fuzz::e_Lim:
209  dst.SetLim(src.GetLim());
210  break;
211  case CInt_fuzz::e_Alt:
212  dst.SetAlt() = src.GetAlt();
213  break;
214  default:
216  "Int-fuzz is not set");
217  }
218 }
219 
220 
221 inline
222 void x_Assign(CSeq_interval& dst, const CSeq_interval& src)
223 {
224  dst.SetFrom(src.GetFrom());
225  dst.SetTo(src.GetTo());
226  if ( src.IsSetStrand() ) {
227  dst.SetStrand(src.GetStrand());
228  }
229  else {
230  dst.ResetStrand();
231  }
232  dst.SetId().Assign(src.GetId());
233  if ( src.IsSetFuzz_from() ) {
234  x_Assign(dst.SetFuzz_from(), src.GetFuzz_from());
235  }
236  else {
237  dst.ResetFuzz_from();
238  }
239  if ( src.IsSetFuzz_to() ) {
240  x_Assign(dst.SetFuzz_to(), src.GetFuzz_to());
241  }
242  else {
243  dst.ResetFuzz_to();
244  }
245 }
246 
247 
248 inline
249 void x_Assign(CSeq_point& dst, const CSeq_point& src)
250 {
251  dst.SetPoint(src.GetPoint());
252  if ( src.IsSetStrand() ) {
253  dst.SetStrand(src.GetStrand());
254  }
255  else {
256  dst.ResetStrand();
257  }
258  dst.SetId().Assign(src.GetId());
259  if ( src.IsSetFuzz() ) {
260  x_Assign(dst.SetFuzz(), src.GetFuzz());
261  }
262  else {
263  dst.ResetFuzz();
264  }
265 }
266 
267 
268 inline
269 void x_Assign(CPacked_seqint& dst, const CPacked_seqint& src)
270 {
271  CPacked_seqint::Tdata& data = dst.Set();
272  data.clear();
273  ITERATE ( CPacked_seqint::Tdata, i, src.Get() ) {
274  data.push_back(CRef<CSeq_interval>(new CSeq_interval));
275  x_Assign(*data.back(), **i);
276  }
277 }
278 
279 
280 inline
281 void x_Assign(CPacked_seqpnt& dst, const CPacked_seqpnt& src)
282 {
283  if ( src.IsSetStrand() ) {
284  dst.SetStrand(src.GetStrand());
285  }
286  else {
287  dst.ResetStrand();
288  }
289  dst.SetId().Assign(src.GetId());
290  if ( src.IsSetFuzz() ) {
291  x_Assign(dst.SetFuzz(), src.GetFuzz());
292  }
293  else {
294  dst.ResetFuzz();
295  }
296  dst.SetPoints() = src.GetPoints();
297 }
298 
299 
300 inline
301 void x_Assign(CSeq_bond& dst, const CSeq_bond& src)
302 {
303  x_Assign(dst.SetA(), src.GetA());
304  if ( src.IsSetB() ) {
305  x_Assign(dst.SetB(), src.GetB());
306  }
307  else {
308  dst.ResetB();
309  }
310 }
311 
312 
313 inline
314 void x_Assign(CSeq_loc_mix& dst, const CSeq_loc_mix& src)
315 {
316  CSeq_loc_mix::Tdata& data = dst.Set();
317  data.clear();
318  ITERATE ( CSeq_loc_mix::Tdata, i, src.Get() ) {
319  data.push_back(CRef<CSeq_loc>(new CSeq_loc));
320  data.back()->Assign(**i);
321  }
322 }
323 
324 
325 inline
326 void x_Assign(CSeq_loc_equiv& dst, const CSeq_loc_equiv& src)
327 {
328  CSeq_loc_equiv::Tdata& data = dst.Set();
329  data.clear();
330  ITERATE ( CSeq_loc_equiv::Tdata, i, src.Get() ) {
331  data.push_back(CRef<CSeq_loc>(new CSeq_loc));
332  data.back()->Assign(**i);
333  }
334 }
335 
336 
338 {
339  InvalidateCache();
340  if ( GetTypeInfo() == obj.GetThisTypeInfo() ) {
341  const CSeq_loc& loc = static_cast<const CSeq_loc&>(obj);
342  switch ( loc.Which() ) {
343  case e_not_set:
344  Reset();
345  return;
346  case e_Null:
347  SetNull();
348  return;
349  case e_Empty:
350  SetEmpty().Assign(loc.GetEmpty());
351  return;
352  case e_Whole:
353  SetWhole().Assign(loc.GetWhole());
354  return;
355  case e_Int:
356  x_Assign(SetInt(), loc.GetInt());
357  return;
358  case e_Pnt:
359  x_Assign(SetPnt(), loc.GetPnt());
360  return;
361  case e_Packed_int:
363  return;
364  case e_Packed_pnt:
366  return;
367  case e_Mix:
368  x_Assign(SetMix(), loc.GetMix());
369  return;
370  case e_Equiv:
371  x_Assign(SetEquiv(), loc.GetEquiv());
372  return;
373  case e_Bond:
374  x_Assign(SetBond(), loc.GetBond());
375  return;
376  case e_Feat:
377  SetFeat().Assign(loc.GetFeat());
378  return;
379  }
380  }
381  CSerialObject::Assign(obj, how);
382 }
383 
384 
386 {
387  TSeqPos range_from = m_TotalRangeCacheFrom.load(memory_order_acquire);
388  if ( range_from == TSeqPos(kDirtyCache) ) {
389  const CSeq_id* id = 0;
391  m_IdCache.store(id, memory_order_release);
392  m_TotalRangeCacheToOpen.store(range.GetToOpen(), memory_order_relaxed);
393  m_TotalRangeCacheFrom.store(range.GetFrom(), memory_order_release);
394  return range;
395  }
396  else {
397  TSeqPos range_to_open = m_TotalRangeCacheToOpen.load(memory_order_relaxed);
398  return COpenRange<TSeqPos>(range_from, range_to_open);
399  }
400 }
401 
402 
403 bool CSeq_loc::x_UpdateId(const CSeq_id*& total_id, const CSeq_id* id,
404  bool may_throw) const
405 {
406  if ( total_id == id ) {
407  return true;
408  }
409 
410  if ( !total_id ) {
411  total_id = id;
412  } else if ( (id && !total_id->Equals(*id)) ) {
413  if (may_throw) {
414  NCBI_THROW(CSeqLocException, eMultipleId,
415  "CSeq_loc::GetTotalRange() is not defined "
416  "for seq-loc with several different seq-ids");
417  } else {
418  return false;
419  }
420  }
421  return true;
422 }
423 
424 
425 
426 // returns enclosing location range
427 // the total range is meaningless if there are several seq-ids
428 // in the location
430 {
431  TRange total_range;
432  switch ( Which() ) {
433  case e_not_set:
434  case e_Null:
435  {
436  // Ignore locations without id
437  total_range = TRange::GetEmpty();
438  break;
439  }
440  case e_Empty:
441  {
442  x_UpdateId(id, &GetEmpty());
443  total_range = TRange::GetEmpty();
444  break;
445  }
446  case e_Whole:
447  {
448  x_UpdateId(id, &GetWhole());
449  total_range = TRange::GetWhole();
450  break;
451  }
452  case e_Int:
453  {
454  const CSeq_interval& loc = GetInt();
455  x_UpdateId(id, &loc.GetId());
456  total_range.Set(loc.GetFrom(), loc.GetTo());
457  break;
458  }
459  case e_Pnt:
460  {
461  const CSeq_point& pnt = GetPnt();
462  x_UpdateId(id, &pnt.GetId());
463  TSeqPos pos = pnt.GetPoint();
464  total_range.Set(pos, pos);
465  break;
466  }
467  case e_Packed_int:
468  {
469  // Check ID of each interval
470  const CPacked_seqint& ints = GetPacked_int();
471  total_range = TRange::GetEmpty();
472  ITERATE ( CPacked_seqint::Tdata, ii, ints.Get() ) {
473  const CSeq_interval& loc = **ii;
474  x_UpdateId(id, &loc.GetId());
475  total_range += TRange(loc.GetFrom(), loc.GetTo());
476  }
477  break;
478  }
479  case e_Packed_pnt:
480  {
481  const CPacked_seqpnt& pnts = GetPacked_pnt();
482  x_UpdateId(id, &pnts.GetId());
483  total_range = TRange::GetEmpty();
485  TSeqPos pos = *pi;
486  total_range += TRange(pos, pos);
487  }
488  break;
489  }
490  case e_Mix:
491  {
492  // Check ID of each sub-location.
493  const CSeq_loc_mix& mix = GetMix();
494  total_range = TRange::GetEmpty();
495  ITERATE( CSeq_loc_mix::Tdata, li, mix.Get() ) {
496  // instead of Get... to be able to check ID
497  total_range += (*li)->x_CalculateTotalRangeCheckId(id);
498  }
499  break;
500  }
501  case e_Equiv:
502  {
503  // Does it make any sense to GetTotalRange() from an equiv?
504  const CSeq_loc_equiv::Tdata& equiv = GetEquiv().Get();
505  total_range = TRange::GetEmpty();
506  ITERATE( CSeq_loc_equiv::Tdata, li, equiv ) {
507  total_range += (*li)->x_CalculateTotalRangeCheckId(id);
508  }
509  break;
510  }
511  case e_Bond:
512  {
513  // Does it make any sense to GetTotalRange() from a bond?
514  const CSeq_bond& bond = GetBond();
515  const CSeq_point& pointA = bond.GetA();
516  x_UpdateId(id, &pointA.GetId());
517  TSeqPos pos = pointA.GetPoint();
518  total_range = TRange(pos, pos);
519  if ( bond.IsSetB() ) {
520  const CSeq_point& pointB = bond.GetB();
521  x_UpdateId(id, &pointB.GetId());
522  pos = pointB.GetPoint();
523  total_range += TRange(pos, pos);
524  }
525  break;
526  }
527 
528  case e_Feat:
529  default:
530  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
531  "CSeq_loc::CalculateTotalRange(): "
532  "unsupported location type: "<<
533  SelectionName(Which()));
534  }
535 
536  return total_range;
537 }
538 
539 
540 int CSeq_loc::x_CompareSingleId(const CSeq_loc& loc, const CSeq_id* id1,
541  const CSeq_id* id2,
542  TCompareFlags flags) const
543 {
544  if ( !id1 || !id2 ) {
545  NCBI_THROW(CSeqLocException, eMultipleId,
546  "CSeq_loc::Compare(): "
547  "cannot compare locations with several different seq-ids");
548  }
549  if ( int diff = INT_ID_TO(int, id1->CompareOrdered(*id2)) ) {
550  // ids are different - order by them
551  return diff;
552  }
553 
556  TSeqPos from2 = loc.GetStart(eExtreme_Positional);
558 
559  // (from > to) means circular location.
560  // Any circular location is less than (before) non-circular one.
561  // If both are circular, compare them regular way.
562  bool circular1 = from1 > to1;
563  bool circular2 = from2 > to2;
564  if ( int diff = circular2 - circular1 ) {
565  return diff;
566  }
567 
568  // smallest left extreme first
569  if ( from1 != from2 ) {
570  return from1 < from2? -1: 1;
571  }
572  // longest feature first
573  if ( to1 != to2 ) {
574  return to1 > to2? -1: 1;
575  }
576  if (flags & fCompare_Strand) {
577  if (!IsSetStrand()) {
578  return loc.IsSetStrand() ? -1 : 0;
579  }
580  else {
581  if (!loc.IsSetStrand()) return 1;
582  }
583  auto s1 = GetStrand();
584  auto s2 = loc.GetStrand();
585  if (s1 != s2) return s1 < s2 ? -1 : 1;
586  }
587  return 0;
588 }
589 
590 int CSeq_loc::Compare(const CSeq_loc& loc_arg) const
591 {
592  return Compare(loc_arg, fCompare_Default);
593 }
594 
595 
596 int CSeq_loc::Compare(const CSeq_loc& loc_arg, TCompareFlags flags) const
597 {
598  // first try fast single-id comparison
599  const CSeq_id* id1 = GetId();
600  const CSeq_id* id2 = id1 == NULL ? NULL : loc_arg.GetId();
601  if (id1 != NULL && id2 != NULL) {
602  return x_CompareSingleId(loc_arg, id1, id2, flags);
603  }
604  // Slow comparison of ranges on each Seq-id separately.
606  CSeq_loc_CI iter2(loc_arg, CSeq_loc_CI::eEmpty_Allow);
607 
608  for ( ; iter1 && iter2; ) {
609  CRef<CSeq_loc> loc1, loc2;
610  for ( int k = 0; k < 2; ++k ) {
611  CSeq_loc_CI& iter = k? iter2: iter1;
612  CRef<CSeq_loc>& loc = k? loc2: loc1;
613  // skip null locations (no Seq-id)
614  while ( iter && iter.GetSeq_id().Which() == CSeq_id::e_not_set ) {
615  ++iter;
616  }
617  if ( !iter ) {
618  // all the remaining segments were null -> end of location
619  loc = null;
620  continue;
621  }
622  const CSeq_id& id = iter.GetSeq_id();
623  loc = const_cast<CSeq_loc*>(&*iter.GetRangeAsSeq_loc());
624  // skip all sub-locations with the same Seq-id
625  while ( ++iter ) {
626  if ( !iter.GetSeq_id().Equals(id) ) {
627  if ( iter.GetSeq_id().Which() == CSeq_id::e_not_set ) {
628  // skip null sub-location
629  continue;
630  }
631  else {
632  // different non-null locations (has Seq-id)
633  break;
634  }
635  }
636  if ( !loc->IsMix() ) {
637  CRef<CSeq_loc> tmp = loc;
638  loc = new CSeq_loc;
639  loc->SetMix().AddSeqLoc(*tmp);
640  }
641  loc->SetMix().AddSeqLoc(const_cast<CSeq_loc&>(*iter.GetRangeAsSeq_loc()));
642  }
643  }
644  if ( loc1 && !loc2 ) {
645  // *this location is longer -> *this > loc
646  return 1;
647  }
648  if ( loc2 && !loc1 ) {
649  // second location is longer -> *this < loc
650  return -1;
651  }
652  if ( !loc1 && !loc2 ) {
653  // both locations ended
654  return 0;
655  }
656  id1 = loc1->GetId();
657  id2 = loc2->GetId();
658  if ( int diff = loc1->x_CompareSingleId(*loc2, id1, id2, flags) ) {
659  // next sub-locs are different
660  return diff;
661  }
662  }
663  if ( iter1 && !iter2 ) {
664  // *this location is longer -> *this > loc
665  return 1;
666  }
667  if ( iter2 && !iter1 ) {
668  // second locatio is longer -> *this < loc
669  return -1;
670  }
671  // same-length locations
672  return 0;
673 }
674 
675 
676 void CSeq_loc::PostRead(void) const
677 {
678  InvalidateCache();
679 }
680 
681 
683 
684 
685 // Transform a CSeq_loc into a CRange< TSeqPos >,
686 // that will be its total range.
687 static inline
689 {
690  try {
691  return loc.GetTotalRange();
692  }
693  catch ( CException& /*ignored*/ ) {
694  // assume empty
695  return CRange<TSeqPos>::GetEmpty();
696  }
697 }
698 
699 
700 // Transform a CSeq_interval into a CRange< TSeqPos >,
701 // that will be its total range.
702 static inline
704 {
705  return CRange<TSeqPos>(interval.GetFrom(), interval.GetTo());
706 };
707 
708 static inline
710  const CSeq_loc::ISubLocFilter *filter )
711 {
712  return !filter || (*filter)( loc.GetId() );
713 }
714 
715 static inline
717  const CSeq_loc::ISubLocFilter *filter )
718 {
719  return !filter || (*filter)( &loc.GetId() );
720 }
721 
722 // Compare two ranges (reversed on minus strand)
723 static inline
725  const COpenRange<TSeqPos> &y_rng,
726  bool minus_strand)
727 {
728  if ( minus_strand ) {
729  // This is backwards for compatibliity with C
730  // Minus strand features should come in revered order
731 
732  // largest right extreme last
733  if ( x_rng.GetToOpen() != y_rng.GetToOpen() ) {
734  return x_rng.GetToOpen() < y_rng.GetToOpen()? -1: 1;
735  }
736  // longest last
737  if ( x_rng.GetFrom() != y_rng.GetFrom() ) {
738  return x_rng.GetFrom() > y_rng.GetFrom()? -1: 1;
739  }
740  }
741  else {
742  // smallest left extreme first
743  if ( x_rng.GetFrom() != y_rng.GetFrom() ) {
744  return x_rng.GetFrom() < y_rng.GetFrom()? -1: 1;
745  }
746  // longest first
747  if ( x_rng.GetToOpen() != y_rng.GetToOpen() ) {
748  return x_rng.GetToOpen() > y_rng.GetToOpen()? -1: 1;
749  }
750  }
751  return 0;
752 }
753 
754 
755 // Compare two containers with intervals (CSeq_loc or CSeq_interval)
756 template< class Container1, class Container2 >
757 int s_CompareIntervals(const Container1& container1,
758  const Container2& container2,
759  bool minus_strand,
760  const CSeq_loc::ISubLocFilter *filter )
761 {
762  typename Container1::const_iterator iter1 = container1.begin();
763  typename Container1::const_iterator iter1end = container1.end();
764  typename Container2::const_iterator iter2 = container2.begin();
765  typename Container2::const_iterator iter2end = container2.end();
766  for( ; iter1 != iter1end && iter2 != iter2end ; ++iter1, ++iter2 ) {
767 
768  // If specified, skip far location pieces
769  if( NULL != filter ) {
770  while( iter1 != iter1end && ! s_CheckIfMatchesBioseq(**iter1, filter) ) {
771  ++iter1;
772  }
773  while( iter2 != iter2end && ! s_CheckIfMatchesBioseq(**iter2, filter) ) {
774  ++iter2;
775  }
776  if( iter1 == iter1end || iter2 == iter2end ) {
777  break;
778  }
779  }
780 
781  if ( int diff = s_CompareRanges(s_LocToRange(**iter1),
782  s_LocToRange(**iter2),
783  minus_strand) ) {
784  return diff;
785  }
786  }
787 
788  // finally, shorter sequence first
789 
790  if( iter1 == iter1end ) {
791  if( iter2 == iter2end ) {
792  return 0;
793  } else {
794  return -1;
795  }
796  } else {
797  return 1;
798  }
799 }
800 
801 
803 
804 
805 int CSeq_loc::CompareSubLoc(const CSeq_loc& loc2, ENa_strand strand,
806  const CSeq_loc::ISubLocFilter *filter) const
807 {
808  bool minus_strand = IsReverse(strand);
809  if ( IsMix() ) {
810  if ( loc2.IsMix() ) {
811  return s_CompareIntervals(GetMix().Get(),
812  loc2.GetMix().Get(),
813  minus_strand,
814  filter );
815  }
816  else if ( loc2.IsPacked_int() ) {
817  return s_CompareIntervals(GetMix().Get(),
818  loc2.GetPacked_int().Get(),
819  minus_strand,
820  filter );
821  }
822  else {
823  // complex loc1 is last on plus strand and first on minus strand
824  return minus_strand? -1: 1;
825  }
826  }
827  else if ( IsPacked_int() ) {
828  if ( loc2.IsMix() ) {
829  return -s_CompareIntervals(loc2.GetMix().Get(),
830  GetPacked_int().Get(),
831  minus_strand,
832  filter );
833  }
834  else if ( loc2.IsPacked_int() ) {
836  loc2.GetPacked_int().Get(),
837  minus_strand,
838  filter );
839  }
840  else {
841  // complex loc1 is last on plus strand and first on minus strand
842  return minus_strand? -1: 1;
843  }
844  }
845  else {
846  if ( loc2.IsMix() || loc2.IsPacked_int() ) {
847  // complex loc2 is last on plus strand and first on minus strand
848  return minus_strand? 1: -1;
849  }
850  else {
851  // two simple locations
852  return 0;
853  }
854  }
855 }
856 
857 
859 {
860  switch ( Which() ) {
861  case e_Int:
862  return GetInt().IsSetStrand();
863  case e_Pnt:
864  return GetPnt().IsSetStrand();
865  case e_Packed_int:
866  return GetPacked_int().IsSetStrand(flag);
867  case e_Packed_pnt:
868  return GetPacked_pnt().IsSetStrand();
869  case e_Mix:
870  return GetMix().IsSetStrand(flag);
871  case e_Bond:
872  return GetBond().IsSetStrand(flag);
873 
874  case e_Equiv:
875  case e_Feat:
876  default:
877  return false;
878  }
879 }
880 
881 
883 {
884  switch ( Which() ) {
885  case e_not_set:
886  case e_Null:
887  case e_Empty:
888  return eNa_strand_unknown;
889  case e_Whole:
890  return eNa_strand_both;
891  case e_Int:
893  case e_Pnt:
895  case e_Packed_int:
896  return GetPacked_int().GetStrand();
897  case e_Packed_pnt:
898  return GetPacked_pnt().IsSetStrand() ?
900  case e_Mix:
901  return GetMix().GetStrand();
902  case e_Bond:
903  return GetBond().GetStrand();
904 
905  case e_Equiv:
906  case e_Feat:
907  default:
908  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
909  "CSeq_loc::GetStrand(): unsupported location type"<<
910  SelectionName(Which()));
911  }
912 }
913 
914 
916 {
917  switch ( Which() ) {
918  case e_not_set:
919  case e_Null:
920  case e_Empty:
921  {
922  return kInvalidSeqPos;
923  }
924  case e_Whole:
925  {
926  return TRange::GetWhole().GetFrom();
927  }
928  case e_Int:
929  {
930  return GetInt().GetStart(ext);
931  }
932  case e_Pnt:
933  {
934  return GetPnt().GetPoint();
935  }
936  case e_Packed_int:
937  {
938  return GetPacked_int().GetStart(ext);
939  }
940  case e_Packed_pnt:
941  {
942  return GetPacked_pnt().GetStart(ext);
943  }
944  case e_Mix:
945  {
946  return GetMix().GetStart(ext);
947  }
948  case e_Bond:
949  {
950  return GetBond().GetStart(ext);
951  }
952 
953  case e_Equiv:
954  case e_Feat:
955  default:
956  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
957  "CSeq_loc::GetStart(): "
958  "unsupported location type: "<<SelectionName(Which()));
959  }
960 }
961 
962 
964 {
965  switch ( Which() ) {
966  case e_not_set:
967  case e_Null:
968  case e_Empty:
969  {
970  return kInvalidSeqPos;
971  }
972  case e_Whole:
973  {
974  return TRange::GetWhole().GetTo();
975  }
976  case e_Int:
977  {
978  return GetInt().GetStop(ext);
979  }
980  case e_Pnt:
981  {
982  return GetPnt().GetPoint();
983  }
984  case e_Packed_int:
985  {
986  return GetPacked_int().GetStop(ext);
987  }
988  case e_Packed_pnt:
989  {
990  return GetPacked_pnt().GetStop(ext);
991  }
992  case e_Mix:
993  {
994  return GetMix().GetStop(ext);
995  }
996  case e_Bond:
997  {
998  return GetBond().GetStop(ext);
999  }
1000 
1001  case e_Equiv:
1002  case e_Feat:
1003  default:
1004  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
1005  "CSeq_loc::GetStop(): "
1006  "unsupported location type: "<<SelectionName(Which()));
1007  }
1008 }
1009 
1010 
1012 {
1013  if (seq_len == kInvalidSeqPos) {
1014  return GetTotalRange().GetLength();
1015  }
1018  bool minus = IsReverseStrand();
1019 
1020  if (start < stop) {
1021  return minus ? (seq_len - stop + start + 1) : (stop - start + 1);
1022  } else {
1023  return minus ? (start - stop + 1) : (seq_len - start + stop + 1);
1024  }
1025 }
1026 
1027 
1029 {
1030  return CSeq_loc_CI(*this);
1031 }
1032 
1033 
1035 {
1036  return CSeq_loc_CI();
1037 }
1038 
1039 
1040 // CSeq_loc_CI implementation
1041 
1043  : m_IsSetStrand(false),
1044  m_Strand(eNa_strand_unknown)
1045 {
1046 }
1047 
1048 
1050 {
1051 }
1052 
1053 
1055 {
1056 public:
1057  CSeq_loc_CI_Impl(void);
1058  CSeq_loc_CI_Impl(const CSeq_loc& loc,
1059  CSeq_loc_CI::EEmptyFlag empty_flag,
1061  virtual ~CSeq_loc_CI_Impl(void) {}
1062 
1064  typedef vector<SSeq_loc_CI_RangeInfo> TRanges;
1065 
1066  struct SEquivSet {
1068 
1069  // parts' end offsets within the equiv set, ordered by position
1070  // must contain at least one element - the only part
1071  // all parts must be not empty - contain at least one element
1072  typedef vector<size_t> TParts;
1073  typedef TParts::const_iterator TPart_CI;
1074  typedef TParts::iterator TPart_I;
1075 
1077 
1078  // return number of Seq-loc element in all equiv parts (always > 0)
1079  size_t GetElementsCount(void) const
1080  {
1081  _ASSERT(!m_Parts.empty());
1082  _ASSERT(m_Parts.back() > 0);
1083  return m_Parts.back();
1084  }
1085  // return index of the first element in the equiv set
1086  size_t GetStartIndex(void) const
1087  {
1088  return m_StartIndex;
1089  }
1090  // return index of element after the equiv set
1091  size_t GetEndIndex(void) const // exclusive
1092  {
1093  return GetStartIndex()+GetElementsCount();
1094  }
1095 
1096  // return true if the equiv set contains element with specified index
1097  bool Contains(size_t idx) const
1098  {
1099  return idx >= GetStartIndex() && idx < GetEndIndex();
1100  }
1101 
1102  // return number of equiv parts (always > 0)
1103  size_t GetPartsCount(void) const
1104  {
1105  _ASSERT(!m_Parts.empty());
1106  return m_Parts.size();
1107  }
1108 
1109  // return offset of the first element in equiv part within equiv set
1110  size_t GetPartStartOffset(TPart_CI part) const
1111  {
1112  _ASSERT(part < m_Parts.end());
1113  return part == m_Parts.begin()? 0: *--part;
1114  }
1115  // return offset of the end element in equiv part within equiv set
1116  size_t GetPartEndOffset(TPart_CI part) const
1117  {
1118  _ASSERT(part < m_Parts.end());
1119  return *part;
1120  }
1121 
1122  // return index of the first element in equiv part within equiv set
1123  size_t GetPartStartIndex(TPart_CI part) const
1124  {
1125  return GetStartIndex()+GetPartStartOffset(part);
1126  }
1127  // return index of the end element in equiv part within equiv set
1128  size_t GetPartEndIndex(TPart_CI part) const
1129  {
1130  return GetStartIndex()+GetPartEndOffset(part);
1131  }
1132 
1133  // return part containing element with specified index
1135  {
1136  _ASSERT(Contains(idx));
1137  return upper_bound(m_Parts.begin(), m_Parts.end(),
1138  idx - GetStartIndex());
1139  }
1140  // return part containing element with specified index
1142  {
1143  _ASSERT(Contains(idx));
1144  return upper_bound(m_Parts.begin(), m_Parts.end(),
1145  idx - GetStartIndex());
1146  }
1147  };
1148  struct PByLevel {
1149  bool operator()(const SEquivSet* e1, const SEquivSet* e2) const
1150  {
1151  size_t s1 = e1->GetElementsCount();
1152  size_t s2 = e2->GetElementsCount();
1153  if ( s1 != s2 ) {
1154  // smallest first
1155  return s1 < s2;
1156  }
1157  s1 = e1->GetPartsCount();
1158  s2 = e2->GetPartsCount();
1159  if ( s1 != s2 ) {
1160  // enclosing set must have single part with the inner set
1161  _ASSERT(s1 == 1 || s2 == 1);
1162  // more parts (inner) first
1163  return s1 > s2;
1164  }
1165  // it's still possible that both equiv sets contain
1166  // one part with the same set of elements
1167  // in this case the sets are equivalent and one set contains
1168  // another, no matter which one, but we still order the sets
1169  // by their creation order
1170  return e1 < e2;
1171  }
1172  };
1173  typedef vector<SEquivSet> TEquivSets;
1174 
1175  TRanges& GetRanges(void) { return m_Ranges; }
1176  const TRanges& GetRanges(void) const { return m_Ranges; }
1177 
1178  bool IsEnd(size_t idx) const { return idx >= m_Ranges.size(); }
1179 
1180  void DeleteRange(size_t idx);
1182 
1183  // Point/Interval support
1184 
1185  // If any part of the location part is changed the embedding location
1186  // becomes invalid.
1187  // This method resets embedding location if it's related to the part only.
1189  {
1190  return info.m_Loc && info.m_Loc->IsPnt();
1191  }
1193  {
1194  if ( !info.m_Loc ) {
1195  return false;
1196  }
1197  switch ( info.m_Loc->Which() ) {
1198  case CSeq_loc::e_Pnt:
1200  case CSeq_loc::e_Bond:
1201  return true;
1202  default:
1203  return false;
1204  }
1205  }
1206  // Update CSeq_point object if any
1207  void UpdatePoint(CSeq_point& pnt,
1208  const SSeq_loc_CI_RangeInfo& info) const;
1209  // Update CSeq_point object if any
1211  // Create CSeq_point object
1213  // Update embedded personal Seq-loc object, making sure it's not a point
1215 
1216  bool CanBePoint(const SSeq_loc_CI_RangeInfo& info) const;
1217 
1218  bool CanBeInterval(const SSeq_loc_CI_RangeInfo& info) const;
1219  bool CanBePoint(size_t idx) const
1220  {
1221  return CanBePoint(m_Ranges[idx]);
1222  }
1223  bool CanBeInterval(size_t idx) const
1224  {
1225  return CanBeInterval(m_Ranges[idx]);
1226  }
1227  bool CanBePacked_pnt(size_t idx_begin, size_t idx_end) const;
1228  bool CanBePacked_int(size_t idx_begin, size_t idx_end) const;
1229 
1230  CRef<CInt_fuzz> MakeFuzz(const CInt_fuzz& fuzz) const;
1233 
1236 
1237  CRef<CSeq_loc> MakeLocPacked_pnt(size_t idx_begin, size_t idx_end) const;
1238  CRef<CSeq_loc> MakeLocPacked_int(size_t idx_begin, size_t idx_end) const;
1239 
1240  // Bond support
1241  bool CanBeBond(size_t idx_begin, size_t idx_end) const;
1242  size_t GetBondBegin(size_t idx) const;
1243  size_t GetBondEnd(size_t idx) const;
1244  pair<size_t, size_t> GetBondRange(size_t idx) const
1245  {
1246  return make_pair(GetBondBegin(idx), GetBondEnd(idx));
1247  }
1249  {
1250  return info.m_Loc && info.m_Loc->IsBond();
1251  }
1252  bool IsInBond(size_t idx) const
1253  {
1254  return IsInBond(m_Ranges[idx]);
1255  }
1256  bool IsBondPartA(size_t idx) const
1257  {
1258  return IsInBond(idx) && idx == GetBondBegin(idx);
1259  }
1260  bool IsBondPartB(size_t idx) const
1261  {
1262  return IsInBond(idx) && idx == GetBondBegin(idx)+1;
1263  }
1264  void x_BreakBond(size_t idx)
1265  {
1266  SetPoint(m_Ranges[idx]);
1267  }
1268  void x_CreateBond(size_t idx)
1269  {
1270  CRef<CSeq_loc> loc(new CSeq_loc);
1271  loc->SetBond();
1272  m_Ranges[idx].m_Loc = loc;
1273  }
1274  void x_AddBondPartB(size_t idx)
1275  {
1276  // add part B be to the bond
1277  m_Ranges[idx+1].m_Loc = m_Ranges[idx].m_Loc;
1278  }
1279  void RemoveBond(size_t idx);
1280  void MakeBondA(size_t idx);
1281  void MakeBondAB(size_t idx);
1282  void MakeBondB(size_t idx);
1283  CRef<CSeq_loc> MakeLocBond(size_t idx_begin, size_t idx_end) const;
1284 
1285  // Equiv support
1286  bool HasEquivSets(void) const
1287  {
1288  return !m_EquivSets.empty();
1289  }
1290  bool IsInEquivSet(size_t idx) const
1291  {
1292  ITERATE ( TEquivSets, it, m_EquivSets ) {
1293  if ( it->Contains(idx) ) {
1294  return true;
1295  }
1296  }
1297  return false;
1298  }
1299  size_t GetEquivSetsCount(size_t idx) const
1300  {
1301  size_t count = 0;
1302  ITERATE ( TEquivSets, it, m_EquivSets ) {
1303  if ( it->Contains(idx) ) {
1304  ++count;
1305  }
1306  }
1307  return count;
1308  }
1309  const SEquivSet& GetEquivSet(size_t idx, size_t level) const
1310  {
1311  vector<const SEquivSet*> sets;
1312  ITERATE ( TEquivSets, it, m_EquivSets ) {
1313  if ( it->Contains(idx) ) {
1314  sets.push_back(&*it);
1315  }
1316  }
1317  if ( level >= sets.size() ) {
1318  NCBI_THROW_FMT(CSeqLocException, eOutOfRange,
1319  "CSeq_loc_CI: bad equiv set level: "<<level);
1320  }
1321  sort(sets.begin(), sets.end(), PByLevel());
1322  return *sets[level];
1323  }
1324  pair<size_t, size_t> GetEquivSetRange(size_t idx, size_t level) const
1325  {
1326  const SEquivSet& s = GetEquivSet(idx, level);
1327  return make_pair(s.GetStartIndex(), s.GetEndIndex());
1328  }
1329  pair<size_t, size_t> GetEquivPartRange(size_t idx, size_t level) const
1330  {
1331  const SEquivSet& s = GetEquivSet(idx, level);
1333  return make_pair(s.GetPartStartIndex(p), s.GetPartEndIndex(p));
1334  }
1335  // Return first equiv part bound point that fall into the range.
1336  // Beginning and ending points are not counted, so 0 is not possible.
1337  // Return 0 if there are no such breaks.
1338  size_t HasEquivBreak(size_t begin, size_t end) const;
1339 
1341  const SEquivSet* FindInnerEquivSet(size_t begin, size_t end,
1342  const TUsedEquivs& used_equivs) const;
1343 
1346  CRef<CSeq_loc> MakeLoc(CSeq_loc_I::EMakeType make_type) const;
1347  CRef<CSeq_loc> MakeLoc(size_t idx_begin,
1348  size_t idx_end,
1349  CSeq_loc_I::EMakeType make_type,
1350  TUsedEquivs& used_equivs) const;
1351 
1352  bool HasChanges(void) const
1353  {
1354  return m_HasChanges;
1355  }
1356 
1357  void SetHasChanges(void)
1358  {
1359  m_HasChanges = true;
1360  }
1361 
1363  {
1364  return m_EquivMode;
1365  }
1367  {
1368  m_EquivMode = mode;
1369  }
1370 
1371 private:
1372  // Never copy this object
1375 
1376  // Process the location, fill the list
1377  void x_ProcessLocation(const CSeq_loc& loc);
1378  void x_ProcessInterval(const CSeq_interval& seq_int,
1379  const CSeq_loc& loc);
1380  void x_ProcessPoint(const CSeq_point& seq_pnt,
1381  const CSeq_loc& loc);
1382 
1383  static void x_SetId(SSeq_loc_CI_RangeInfo& info, const CSeq_id& id);
1384 
1385  // Prevent seq-loc destruction
1387  // List of intervals
1389  // List of equiv parts
1391  // Empty locations processing option
1393  // true if anything was changed in the Seq-loc
1395  // equiv editing mode
1397 };
1398 
1399 
1401  : m_HasChanges(false),
1402  m_EquivMode(CSeq_loc_I::eEquiv_none)
1403 {
1404 }
1405 
1406 
1408  CSeq_loc_CI::EEmptyFlag empty_flag,
1410  : m_Location(&loc),
1411  m_EmptyFlag(empty_flag),
1412  m_HasChanges(false),
1413  m_EquivMode(CSeq_loc_I::eEquiv_none)
1414 {
1415  x_ProcessLocation(loc);
1416  if ( order == CSeq_loc_CI::eOrder_Positional && loc.IsReverseStrand() ) {
1417  reverse(m_Ranges.begin(), m_Ranges.end());
1418  }
1419 }
1420 
1421 
1423  const CSeq_id& id)
1424 {
1425  info.m_Id = &id;
1426  info.m_IdHandle = CSeq_id_Handle::GetHandle(id);
1427 }
1428 
1429 
1430 template<class Container>
1431 static void s_ReserveMore(Container& cont, size_t add_size)
1432 {
1433  if ( cont.size()+add_size > cont.capacity() ) {
1434  cont.reserve(max(cont.size()+add_size, cont.capacity()*2));
1435  }
1436 }
1437 
1438 
1440 {
1441  switch ( loc.Which() ) {
1442  case CSeq_loc::e_not_set:
1443  /*
1444  NCBI_THROW(CSeqLocException, eNotSet,
1445  "CSeq_loc_CI: location is not set");
1446  */
1447  case CSeq_loc::e_Null:
1448  case CSeq_loc::e_Empty:
1449  {
1452  if (loc.Which() == CSeq_loc::e_Empty) {
1453  x_SetId(info, loc.GetEmpty());
1454  }
1455  else {
1456  info.m_Id.Reset(new CSeq_id);
1457  }
1458  info.m_Range = TRange::GetEmpty();
1459  info.m_Loc = &loc;
1460  m_Ranges.push_back(info);
1461  }
1462  return;
1463  }
1464  case CSeq_loc::e_Whole:
1465  {
1467  x_SetId(info, loc.GetWhole());
1468  info.m_Range = TRange::GetWhole();
1469  info.m_Loc = &loc;
1470  m_Ranges.push_back(info);
1471  return;
1472  }
1473  case CSeq_loc::e_Int:
1474  {
1475  x_ProcessInterval(loc.GetInt(), loc);
1476  return;
1477  }
1478  case CSeq_loc::e_Pnt:
1479  {
1480  x_ProcessPoint(loc.GetPnt(), loc);
1481  return;
1482  }
1484  {
1485  const CPacked_seqint::Tdata& data = loc.GetPacked_int().Get();
1486  s_ReserveMore(m_Ranges, data.size());
1488  x_ProcessInterval(**ii, loc);
1489  }
1490  return;
1491  }
1493  {
1494  const CPacked_seqpnt& pack_pnt = loc.GetPacked_pnt();
1495  s_ReserveMore(m_Ranges, pack_pnt.GetPoints().size());
1497  x_SetId(info, pack_pnt.GetId());
1498  if ( pack_pnt.IsSetStrand() ) {
1499  info.SetStrand(pack_pnt.GetStrand());
1500  }
1501  if (pack_pnt.IsSetFuzz()) {
1502  info.m_Fuzz.first = info.m_Fuzz.second = &pack_pnt.GetFuzz();
1503  }
1504  info.m_Loc = &loc;
1505  ITERATE ( CPacked_seqpnt::TPoints, pi, pack_pnt.GetPoints() ) {
1506  info.m_Range.Set(*pi, *pi);
1507  m_Ranges.push_back(info);
1508  }
1509  return;
1510  }
1511  case CSeq_loc::e_Mix:
1512  {
1513  const CSeq_loc_mix::Tdata& data = loc.GetMix().Get();
1514  s_ReserveMore(m_Ranges, data.size());
1516  x_ProcessLocation(**li);
1517  }
1518  return;
1519  }
1520  case CSeq_loc::e_Equiv:
1521  {
1522  const CSeq_loc_equiv::Tdata& data = loc.GetEquiv().Get();
1523  s_ReserveMore(m_Ranges, data.size());
1524  SEquivSet eq_set;
1525  size_t start = m_Ranges.size();
1526  eq_set.m_StartIndex = start;
1528  size_t part_start = m_Ranges.size();
1529  x_ProcessLocation(**li);
1530  size_t part_end = m_Ranges.size();
1531  if ( part_start != part_end ) {
1532  // add only non-empty parts
1533  eq_set.m_Parts.push_back(part_end-start);
1534  }
1535  }
1536  if ( !eq_set.m_Parts.empty() ) {
1537  // add only non-empty equiv sets
1538  m_EquivSets.push_back(eq_set);
1539  }
1540  return;
1541  }
1542  case CSeq_loc::e_Bond:
1543  {
1544  const CSeq_bond& bond = loc.GetBond();
1545  x_ProcessPoint(bond.GetA(), loc);
1546  if ( bond.IsSetB() ) {
1547  x_ProcessPoint(bond.GetB(), loc);
1548  }
1549  return;
1550  }
1551  default:
1552  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
1553  "CSeq_loc_CI: unsupported location type: "<<
1554  loc.SelectionName(loc.Which()));
1555  }
1556 }
1557 
1558 
1560  const CSeq_loc& loc)
1561 {
1562  _ASSERT(loc.Which() == CSeq_loc::e_Int ||
1563  loc.Which() == CSeq_loc::e_Packed_int);
1565  x_SetId(info, seq_int.GetId());
1566  info.m_Range.Set(seq_int.GetFrom(), seq_int.GetTo());
1567  if ( seq_int.IsSetStrand() ) {
1568  info.SetStrand(seq_int.GetStrand());
1569  }
1570  info.m_Loc = &loc;
1571  if (seq_int.IsSetFuzz_from()) {
1572  info.m_Fuzz.first = &seq_int.GetFuzz_from();
1573  }
1574  if (seq_int.IsSetFuzz_to()) {
1575  info.m_Fuzz.second = &seq_int.GetFuzz_to();
1576  }
1577  m_Ranges.push_back(info);
1578 }
1579 
1580 
1582  const CSeq_loc& loc)
1583 {
1584  _ASSERT(loc.Which() == CSeq_loc::e_Pnt ||
1585  loc.Which() == CSeq_loc::e_Bond);
1587  x_SetId(info, seq_pnt.GetId());
1588  info.m_Range.Set(seq_pnt.GetPoint(), seq_pnt.GetPoint());
1589  if ( seq_pnt.IsSetStrand() ) {
1590  info.SetStrand(seq_pnt.GetStrand());
1591  }
1592  info.m_Loc = &loc;
1593  if (seq_pnt.IsSetFuzz()) {
1594  info.m_Fuzz.first = info.m_Fuzz.second = &seq_pnt.GetFuzz();
1595  }
1596  m_Ranges.push_back(info);
1597 }
1598 
1599 
1601  size_t end) const
1602 {
1603  size_t ret = end;
1604  ITERATE ( TEquivSets, it, m_EquivSets ) {
1605  const SEquivSet& eq_set = *it;
1606  size_t eq_begin = eq_set.GetStartIndex();
1607  size_t eq_end = eq_set.GetEndIndex();
1608  if ( eq_end <= begin || eq_begin >= end ) {
1609  // no overlaps
1610  continue;
1611  }
1612  if ( eq_begin > begin && eq_begin < end ) {
1613  // range overlaps with the beginning of the equiv set
1614  ret = min(ret, eq_begin);
1615  continue;
1616  }
1617  // otherwise the equiv starts before the range and ends somewhere
1618  // after beginning of the range.
1619  // so the first part that contains range's begin point is the one,
1620  // end its end point is one of the breaking points we are looking for.
1621  SEquivSet::TPart_CI part = eq_set.FindPartByElementIndex(begin);
1622  ret = min(ret, eq_set.GetPartEndIndex(part));
1623  }
1624  // the first break point may be after the requested range
1625  return ret == end? 0: ret;
1626 }
1627 
1628 
1631  size_t end,
1632  const TUsedEquivs& used_equivs) const
1633 {
1634  const SEquivSet* ret = 0;
1635  ITERATE ( TEquivSets, it, m_EquivSets ) {
1636  const SEquivSet& eq_set = *it;
1637  size_t eq_begin = eq_set.GetStartIndex();
1638  size_t eq_end = eq_set.GetEndIndex();
1639  if ( eq_begin < begin || eq_end > end ) {
1640  continue;
1641  }
1642  if ( used_equivs.find(&eq_set) != used_equivs.end() ) {
1643  // already processed
1644  continue;
1645  }
1646  if ( !ret || PByLevel()(ret, &eq_set) ) {
1647  ret = &eq_set;
1648  }
1649  }
1650  return ret;
1651 }
1652 
1653 
1655 {
1656  SetHasChanges();
1657  m_Ranges.erase(m_Ranges.begin()+idx);
1658  // update equiv sets
1660  SEquivSet& eq_set = *it;
1661  size_t start_index = eq_set.GetStartIndex();
1662  if ( idx < start_index ) {
1663  // shift whole equiv set because an element before is deleted
1664  --eq_set.m_StartIndex;
1665  continue;
1666  }
1667  size_t offset = idx - start_index;
1668  size_t prev_offset = 0;
1669  ERASE_ITERATE ( SEquivSet::TParts, it2, eq_set.m_Parts ) {
1670  if ( offset < *it2 ) {
1671  --*it2;
1672  if ( *it2 == prev_offset ) {
1673  VECTOR_ERASE(it2, eq_set.m_Parts);
1674  }
1675  else {
1676  prev_offset = *it2;
1677  }
1678  }
1679  }
1680  if ( eq_set.GetElementsCount() == 0 ) {
1682  }
1683  }
1684 }
1685 
1686 
1687 static inline bool s_InsertExpands(size_t idx, size_t start, size_t end)
1688 {
1689  return (idx > start && idx <= end) || (idx == start && idx == 0);
1690 }
1691 
1692 
1695 {
1696  SetHasChanges();
1698  *m_Ranges.insert(m_Ranges.begin()+idx, SSeq_loc_CI_RangeInfo());
1699  CConstRef<CSeq_loc> loc;
1700  // connect with previous or next part (if any)
1701  if ( idx > 0 ) {
1702  loc = m_Ranges[idx-1].m_Loc;
1703  }
1704  else if ( idx < m_Ranges.size() ) {
1705  loc = m_Ranges[idx].m_Loc;
1706  }
1707  if ( loc ) {
1708  // if type is incompatible with part it's connected to, do not connect
1709  switch ( loc->Which() ) {
1710  case CSeq_loc::e_Null:
1711  case CSeq_loc::e_Empty:
1712  case CSeq_loc::e_Whole:
1713  case CSeq_loc::e_Pnt:
1714  case CSeq_loc::e_Int:
1715  loc = null;
1716  break;
1717  case CSeq_loc::e_Bond:
1718  if ( type != CSeq_loc::e_Pnt ) {
1719  loc = null;
1720  }
1721  break;
1723  if ( type != CSeq_loc::e_Pnt ) {
1724  loc = null;
1725  }
1726  break;
1728  if ( type != CSeq_loc::e_Pnt && type != CSeq_loc::e_Int ) {
1729  loc = null;
1730  }
1731  break;
1732  default:
1733  break;
1734  }
1735  }
1736  info.m_Loc = loc;
1737 
1738  SEquivSet* add_to_set_beg = 0;
1739  vector<SEquivSet*> add_to_set_mid;
1740  SEquivSet* add_to_set_end = 0;
1741  // update existing equiv sets
1743  SEquivSet& eq_set = *it;
1744  size_t eq_start = eq_set.GetStartIndex();
1745  size_t eq_end = eq_set.GetEndIndex();
1746  if ( idx == eq_start &&
1749  // new element is inserted just before the equiv and will be added
1750  // shift it for now
1751  ++eq_set.m_StartIndex;
1752  if ( !add_to_set_beg || PByLevel()(&eq_set, add_to_set_beg) ) {
1753  add_to_set_beg = &eq_set;
1754  }
1755  }
1756  else if ( idx == eq_end &&
1759  // new element is inserted just after the equiv and will be added
1760  if ( !add_to_set_end || PByLevel()(&eq_set, add_to_set_end) ) {
1761  add_to_set_end = &eq_set;
1762  }
1763  }
1764  else if ( idx > eq_start && idx < eq_end ) {
1765  // new element is completely within eq_set, so it will be added
1766  add_to_set_mid.push_back(&eq_set);
1767  }
1768  else if ( idx <= eq_start ) {
1769  // new element is completely before the equiv - shift right
1770  ++eq_set.m_StartIndex;
1771  }
1772  }
1773  sort(add_to_set_mid.begin(), add_to_set_mid.end(), PByLevel());
1774  if ( add_to_set_beg ) {
1775  // add at the beginning of the set
1776  NON_CONST_ITERATE ( SEquivSet::TParts, it, add_to_set_beg->m_Parts ) {
1777  ++*it;
1778  }
1780  // add as a new part
1781  add_to_set_beg->m_Parts.insert(add_to_set_beg->m_Parts.begin(), 1);
1783  }
1784  }
1785  else if ( add_to_set_end ) {
1786  // add at the end of the set
1788  // add as a new part
1789  add_to_set_end->m_Parts.push_back(add_to_set_end->m_Parts.back()+1);
1791  }
1792  else {
1793  ++add_to_set_end->m_Parts.back();
1794  }
1795  }
1797  !add_to_set_mid.empty() ) {
1798  SEquivSet& eq_set = **add_to_set_mid.begin();
1799  add_to_set_mid.erase(add_to_set_mid.begin());
1800  SEquivSet::TPart_I it = eq_set.FindPartByElementIndex(idx);
1801  it = eq_set.m_Parts.insert(it, idx-eq_set.GetStartIndex()+1)+1;
1802  for ( ; it != eq_set.m_Parts.end(); ++it ) {
1803  ++*it;
1804  }
1806  }
1807  ITERATE ( vector<SEquivSet*>, set_it, add_to_set_mid ) {
1808  SEquivSet& eq_set = **set_it;
1809  SEquivSet::TPart_I it = eq_set.FindPartByElementIndex(idx);
1810  for ( ; it != eq_set.m_Parts.end(); ++it ) {
1811  ++*it;
1812  }
1813  }
1814  // now all existing equivs were updated
1815 
1817  // create new equiv
1818  SEquivSet eq_set;
1819  eq_set.m_StartIndex = idx;
1820  eq_set.m_Parts.push_back(1);
1821  m_EquivSets.push_back(eq_set);
1823  }
1824  return info;
1825 }
1826 
1827 
1829 {
1830  if ( info.m_Range.GetLength() != 1 ) {
1831  return false;
1832  }
1833  if ( info.m_Fuzz.first != info.m_Fuzz.second ) {
1834  return false;
1835  }
1836  if ( !info.m_IdHandle ) {
1837  return false;
1838  }
1839  return true;
1840 }
1841 
1842 
1844 {
1845  if ( info.m_Range.Empty() || info.m_Range.IsWhole() ) {
1846  return false;
1847  }
1848  if ( !info.m_IdHandle ) {
1849  return false;
1850  }
1851  return true;
1852 }
1853 
1854 
1855 bool CSeq_loc_CI_Impl::CanBeBond(size_t idx_begin, size_t idx_end) const
1856 {
1857  size_t count = idx_end - idx_begin;
1858  if ( count != 1 && count != 2 ) {
1859  return false;
1860  }
1861  if ( !IsInBond(idx_begin) ) {
1862  return false;
1863  }
1864  if ( GetBondRange(idx_begin) != make_pair(idx_begin, idx_end) ) {
1865  return false;
1866  }
1867  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
1868  _ASSERT(IsInBond(idx));
1869  const SSeq_loc_CI_RangeInfo& info = m_Ranges[idx];
1870  if ( !CanBePoint(info) ) {
1871  return false;
1872  }
1873  }
1874  if ( HasEquivBreak(idx_begin, idx_end) ) {
1875  return false;
1876  }
1877  return true;
1878 }
1879 
1880 
1881 size_t CSeq_loc_CI_Impl::GetBondBegin(size_t idx) const
1882 {
1883  const CSeq_loc* loc = m_Ranges[idx].m_Loc.GetPointerOrNull();
1884  _ASSERT(loc && loc->IsBond());
1885  while ( idx > 0 && m_Ranges[idx-1].m_Loc == loc ) {
1886  --idx;
1887  }
1888  return idx;
1889 }
1890 
1891 
1892 size_t CSeq_loc_CI_Impl::GetBondEnd(size_t idx) const
1893 {
1894  const CSeq_loc* loc = m_Ranges[idx].m_Loc.GetPointerOrNull();
1895  _ASSERT(loc && loc->IsBond());
1896  while ( idx < m_Ranges.size() && m_Ranges[idx].m_Loc == loc ) {
1897  ++idx;
1898  }
1899  return idx;
1900 }
1901 
1902 
1904 {
1905  if ( !IsInBond(idx) ) {
1906  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
1907  "CSeq_loc_I::RemoveBond(): "
1908  "there is no bond at current position");
1909  }
1910  pair<size_t, size_t> range = GetBondRange(idx);
1911  SetHasChanges();
1912  // unbond all parts
1913  for ( idx = range.first; idx < range.second; ++idx ) {
1914  x_BreakBond(idx);
1915  }
1916 }
1917 
1918 
1920 {
1921  pair<size_t, size_t> range;
1922  if ( IsInBond(idx) ) {
1923  range = GetBondRange(idx);
1924  }
1925  size_t bond_len = range.second-range.first;
1926  if ( bond_len > 0 ) {
1927  // update existing bond
1928  if ( idx != range.first ) {
1929  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
1930  "CSeq_loc_I::MakeBondA(): "
1931  "current position is B part of other bond");
1932  }
1933  if ( bond_len == 1 ) {
1934  // already bond with only part A
1935  return;
1936  }
1937  SetHasChanges();
1938  // unbond other parts
1939  for ( idx = range.first+1; idx < range.second; ++idx ) {
1940  x_BreakBond(idx);
1941  }
1942  }
1943  else {
1944  SetHasChanges();
1945  x_CreateBond(idx);
1946  }
1947 }
1948 
1949 
1951 {
1952  if ( idx+1 >= m_Ranges.size() ) {
1953  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
1954  "CSeq_loc_I::MakeBondAB(): "
1955  "no more parts in the location");
1956  }
1957  pair<size_t, size_t> range;
1958  if ( IsInBond(idx) ) {
1959  range = GetBondRange(idx);
1960  }
1961  size_t bond_len = range.second-range.first;
1962  if ( bond_len > 0 ) {
1963  // update existing bond
1964  if ( idx != range.first ) {
1965  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
1966  "CSeq_loc_I::MakeBondAB(): "
1967  "current position is B part of other bond");
1968  }
1969  if ( bond_len == 2 ) {
1970  // already a bond with both parts A and B
1971  return;
1972  }
1973  SetHasChanges();
1974  if ( bond_len > 2 ) {
1975  // unbond extra parts after B
1976  for ( idx = range.first+2; idx < range.second; ++idx ) {
1977  x_BreakBond(idx);
1978  }
1979  return;
1980  }
1981  x_AddBondPartB(idx);
1982  }
1983  else {
1984  SetHasChanges();
1985  x_CreateBond(idx);
1986  x_AddBondPartB(idx);
1987  }
1988 }
1989 
1990 
1992 {
1993  if ( idx == 0 ) {
1994  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
1995  "CSeq_loc_I::MakeBondB(): "
1996  "no parts before current");
1997  }
1998  pair<size_t, size_t> range;
1999  if ( IsInBond(idx) ) {
2000  range = GetBondRange(idx);
2001  }
2002  else if ( IsInBond(idx-1) ) {
2003  range = GetBondRange(idx-1);
2004  }
2005  size_t bond_len = range.second-range.first;
2006  if ( bond_len > 0 ) {
2007  // update existing bond
2008  if ( range.first != idx + 1 ) {
2009  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
2010  "CSeq_loc_I::MakeBondB(): "
2011  "current position is not a B part of other bond");
2012  }
2013  if ( bond_len == 2 ) {
2014  // already a bond with both parts A and B
2015  return;
2016  }
2017  SetHasChanges();
2018  if ( bond_len > 2 ) {
2019  // unbond extra parts after B
2020  for ( idx = range.first+2; idx < range.second; ++idx ) {
2021  x_BreakBond(idx);
2022  }
2023  return;
2024  }
2025  _ASSERT(bond_len == 1);
2026  x_AddBondPartB(idx);
2027  }
2028  else {
2029  SetHasChanges();
2030  x_CreateBond(idx);
2031  x_AddBondPartB(idx);
2032  }
2033 }
2034 
2035 
2037  size_t idx_end) const
2038 {
2039  CRef<CSeq_loc> loc(new CSeq_loc);
2040  loc->SetBond().SetA(*MakePoint(m_Ranges[idx_begin]));
2041  if ( idx_begin+1 < idx_end ) {
2042  loc->SetBond().SetB(*MakePoint(m_Ranges[idx_begin+1]));
2043  }
2044  return loc;
2045 }
2046 
2047 
2048 static
2050 {
2051  if ( !info.m_IdHandle ) {
2053  "CSeq_loc_I: part id is null");
2054  }
2055  return Ref(&const_cast<CSeq_id&>(*info.m_Id));
2056 }
2057 
2058 
2060 {
2061  return Ref(&const_cast<CInt_fuzz&>(fuzz));
2062 }
2063 
2064 
2066  const SSeq_loc_CI_RangeInfo& info) const
2067 {
2068  pnt.SetId(*MakeId(info));
2069  pnt.SetPoint(info.m_Range.GetFrom());
2070  if ( info.m_IsSetStrand ) {
2071  pnt.SetStrand(info.m_Strand);
2072  }
2073  else {
2074  pnt.ResetStrand();
2075  }
2076  if ( info.m_Fuzz.first ) {
2077  pnt.SetFuzz(*MakeFuzz(*info.m_Fuzz.first));
2078  }
2079  else {
2080  pnt.ResetFuzz();
2081  }
2082 }
2083 
2084 
2086 {
2087  info.m_Loc = MakeLocPoint(info);
2088 }
2089 
2090 
2093 {
2094  CRef<CSeq_point> seq_pnt(new CSeq_point);
2095  UpdatePoint(*seq_pnt, info);
2096  return seq_pnt;
2097 }
2098 
2099 
2102 {
2103  CRef<CSeq_loc> loc(new CSeq_loc);
2104  loc->SetPnt(*MakePoint(info));
2105  return loc;
2106 }
2107 
2108 
2110 {
2111  SetHasChanges();
2112  if ( WasPoint(info) ) {
2113  UpdatePoint(const_cast<CSeq_point&>(info.m_Loc->GetPnt()), info);
2114  }
2115 }
2116 
2117 
2119 {
2120  SetHasChanges();
2121  if ( info.m_Loc ) {
2122  switch ( info.m_Loc->Which() ) {
2123  case CSeq_loc::e_Whole:
2124  case CSeq_loc::e_Empty:
2125  case CSeq_loc::e_Null:
2126  case CSeq_loc::e_Int:
2127  case CSeq_loc::e_Pnt:
2128  info.m_Loc = null;
2129  break;
2130  default:
2131  break;
2132  }
2133  }
2134 }
2135 
2136 
2139 {
2140  CRef<CSeq_interval> seq_int(new CSeq_interval);
2141  seq_int->SetId(*MakeId(info));
2142  seq_int->SetFrom(info.m_Range.GetFrom());
2143  seq_int->SetTo(info.m_Range.GetTo());
2144  if ( info.m_IsSetStrand ) {
2145  seq_int->SetStrand(info.m_Strand);
2146  }
2147  if ( info.m_Fuzz.first ) {
2148  seq_int->SetFuzz_from(*MakeFuzz(*info.m_Fuzz.first));
2149  }
2150  if ( info.m_Fuzz.second ) {
2151  seq_int->SetFuzz_to(*MakeFuzz(*info.m_Fuzz.second));
2152  }
2153  return seq_int;
2154 }
2155 
2156 
2159 {
2160  CRef<CSeq_loc> loc(new CSeq_loc);
2161  loc->SetInt(*MakeInterval(info));
2162  return loc;
2163 }
2164 
2165 
2168 {
2169  CRef<CSeq_loc> loc(new CSeq_loc);
2170  if ( info.m_Range.IsWhole() ) {
2171  loc->SetWhole(*MakeId(info));
2172  }
2173  else {
2174  if ( !info.m_Range.Empty() ) {
2175  NCBI_THROW(CSeqLocException, eOtherError,
2176  "CSeq_loc_I::MakeSeq_loc(): "
2177  "cannot determine type of loc part");
2178  }
2179  if ( info.m_IdHandle ) {
2180  loc->SetEmpty(*MakeId(info));
2181  }
2182  else {
2183  loc->SetNull();
2184  }
2185  }
2186  return loc;
2187 }
2188 
2189 
2192 {
2193  if ( ShouldBePoint(info) && CanBePoint(info) ) {
2194  return MakeLocPoint(info);
2195  }
2196  else if ( info.m_Range.IsWhole() || info.m_Range.Empty() ) {
2197  return MakeLocOther(info);
2198  }
2199  else {
2200  return MakeLocInterval(info);
2201  }
2202 }
2203 
2204 
2206  size_t idx_end) const
2207 {
2208  _ASSERT(idx_end >= idx_begin);
2209  if ( idx_end == idx_begin ) {
2210  return false;
2211  }
2212  const SSeq_loc_CI_RangeInfo& info0 = m_Ranges[idx_begin];
2213  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
2214  if ( IsInBond(idx) ) {
2215  return false;
2216  }
2217  const SSeq_loc_CI_RangeInfo& info = m_Ranges[idx];
2218  if ( !CanBePoint(m_Ranges[idx]) ) {
2219  return false;
2220  }
2221  if ( idx != idx_begin ) {
2222  if ( info.m_IdHandle != info0.m_IdHandle ) {
2223  return false;
2224  }
2225  if ( info.m_IsSetStrand != info0.m_IsSetStrand ) {
2226  return false;
2227  }
2228  if ( info0.m_IsSetStrand && info.m_Strand != info0.m_Strand ) {
2229  return false;
2230  }
2231  if ( info.m_Fuzz.first != info0.m_Fuzz.first ) {
2232  return false;
2233  }
2234  }
2235  }
2236  if ( HasEquivBreak(idx_begin, idx_end) ) {
2237  return false;
2238  }
2239  return true;
2240 }
2241 
2242 
2244  size_t idx_end) const
2245 {
2246  _ASSERT(idx_end >= idx_begin);
2247  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
2248  if ( IsInBond(idx) ) {
2249  return false;
2250  }
2251  if ( !CanBeInterval(idx) ) {
2252  return false;
2253  }
2254  }
2255  if ( HasEquivBreak(idx_begin, idx_end) ) {
2256  return false;
2257  }
2258  return true;
2259 }
2260 
2261 
2263  size_t idx_end) const
2264 {
2265  const SSeq_loc_CI_RangeInfo& info0 = m_Ranges[idx_begin];
2266  CRef<CSeq_loc> loc(new CSeq_loc);
2267  CPacked_seqpnt& pnts = loc->SetPacked_pnt();
2268  pnts.SetId(*MakeId(info0));
2269  if ( info0.m_IsSetStrand ) {
2270  pnts.SetStrand(info0.m_Strand);
2271  }
2272  if ( info0.m_Fuzz.first ) {
2273  pnts.SetFuzz(*MakeFuzz(*info0.m_Fuzz.first));
2274  }
2275  pnts.SetPoints().reserve(idx_end-idx_begin);
2276  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
2277  const SSeq_loc_CI_RangeInfo& info = m_Ranges[idx];
2278  pnts.SetPoints().push_back(info.m_Range.GetFrom());
2279  }
2280  return loc;
2281 }
2282 
2283 
2285  size_t idx_end) const
2286 {
2287  CRef<CSeq_loc> loc(new CSeq_loc);
2288  CPacked_seqint::Tdata& ints = loc->SetPacked_int().Set();
2289  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
2290  ints.push_back(MakeInterval(m_Ranges[idx]));
2291  }
2292  return loc;
2293 }
2294 
2295 
2296 static
2298 {
2299  if ( !loc ) {
2300  loc = loc2;
2301  return;
2302  }
2303  if ( !loc->IsMix() ) {
2304  CRef<CSeq_loc> loc1 = loc;
2305  loc = new CSeq_loc;
2306  loc->SetMix().Set().push_back(loc1);
2307  }
2308  loc->SetMix().Set().push_back(loc2);
2309 }
2310 
2311 
2313  size_t idx_end,
2314  CSeq_loc_I::EMakeType make_type,
2315  TUsedEquivs& used_equivs) const
2316 {
2317  if ( const SEquivSet* eq_set = FindInnerEquivSet(idx_begin, idx_end, used_equivs) ) {
2318  used_equivs.insert(eq_set);
2319  size_t idx = eq_set->GetStartIndex();
2320  CRef<CSeq_loc> loc;
2321  if ( idx > idx_begin ) {
2322  loc = MakeLoc(idx_begin, idx, make_type, used_equivs);
2323  }
2324  CRef<CSeq_loc> loc2(new CSeq_loc);
2325  CSeq_loc_equiv& equiv = loc2->SetEquiv();
2326  ITERATE ( SEquivSet::TParts, it, eq_set->m_Parts ) {
2327  size_t part_end = eq_set->GetPartEndIndex(it);
2328  CRef<CSeq_loc> part_loc =
2329  MakeLoc(idx, part_end, make_type, used_equivs);
2330  equiv.Set().push_back(part_loc);
2331  idx = part_end;
2332  }
2333  AddLoc(loc, loc2);
2334  if ( idx < idx_end ) {
2335  loc2 = MakeLoc(idx, idx_end, make_type, used_equivs);
2336  if ( loc2->IsMix() ) {
2337  ITERATE ( CSeq_loc_mix::Tdata, it, loc2->GetMix().Get() ) {
2338  AddLoc(loc, *it);
2339  }
2340  }
2341  else {
2342  AddLoc(loc, loc2);
2343  }
2344  }
2345  return loc;
2346  }
2347 
2348  if ( HasEquivBreak(idx_begin, idx_end) ) {
2349  NCBI_THROW(CSeqLocException, eBadLocation,
2350  "CSeq_loc_I::MakeSeq_loc: equiv set overlaps with range");
2351  }
2352 
2353  if ( idx_begin == idx_end ) {
2354  CRef<CSeq_loc> loc(new CSeq_loc);
2355  loc->SetMix();
2356  return loc;
2357  }
2358 
2359  // check bonds
2360  const SSeq_loc_CI_RangeInfo& info0 = m_Ranges[idx_begin];
2361  if ( make_type == CSeq_loc_I::eMake_PreserveType && info0.m_Loc ) {
2362  // try to restore original CSeq_loc type
2363  if ( info0.m_Loc->IsPacked_pnt() &&
2364  CanBePacked_pnt(idx_begin, idx_end) ) {
2365  return MakeLocPacked_pnt(idx_begin, idx_end);
2366  }
2367  if ( info0.m_Loc->IsPacked_int() &&
2368  CanBePacked_int(idx_begin, idx_end) ) {
2369  return MakeLocPacked_int(idx_begin, idx_end);
2370  }
2371  }
2372  if ( make_type == CSeq_loc_I::eMake_CompactType &&
2373  idx_end - idx_begin > 1 ) {
2374  // try to make compact variants
2375  if ( CanBePacked_pnt(idx_begin, idx_end) ) {
2376  return MakeLocPacked_pnt(idx_begin, idx_end);
2377  }
2378  if ( CanBePacked_int(idx_begin, idx_end) ) {
2379  return MakeLocPacked_int(idx_begin, idx_end);
2380  }
2381  }
2382 
2383  CRef<CSeq_loc> loc;
2384  for ( size_t idx = idx_begin; idx < idx_end; ++idx ) {
2385  if ( IsInBond(idx) ) {
2386  pair<size_t, size_t> range = GetBondRange(idx);
2387  if ( range.first < idx || range.second > idx_end ||
2388  !CanBeBond(range.first, range.second) ) {
2389  NCBI_THROW(CSeqLocException, eIncomatible,
2390  "CSeq_loc_I::MakeSeq_loc: "
2391  "invalid bond");
2392  }
2393  AddLoc(loc, MakeLocBond(range.first, range.second));
2394  idx = range.second-1;
2395  continue;
2396  }
2397  const SSeq_loc_CI_RangeInfo& info = m_Ranges[idx];
2398  if ( make_type == CSeq_loc_I::eMake_PreserveType ) {
2399  if ( WasPoint(info) && CanBePoint(info) ) {
2400  AddLoc(loc, MakeLocPoint(info));
2401  continue;
2402  }
2403  if ( (!info.m_Loc || info.m_Loc->IsInt()) &&
2404  CanBeInterval(info) ) {
2405  AddLoc(loc, MakeLocInterval(info));
2406  continue;
2407  }
2408  }
2409  if ( CanBePoint(info) ) {
2410  AddLoc(loc, MakeLocPoint(info));
2411  continue;
2412  }
2413  if ( CanBeInterval(info) ) {
2414  AddLoc(loc, MakeLocInterval(info));
2415  continue;
2416  }
2417  AddLoc(loc, MakeLocOther(info));
2418  }
2419  if ( !loc ) {
2420  loc = new CSeq_loc;
2421  }
2422  return loc;
2423 }
2424 
2425 
2427 {
2428  TUsedEquivs used_equivs;
2429  return MakeLoc(0, m_Ranges.size(), make_type, used_equivs);
2430 }
2431 
2432 
2434  : m_Impl(new CSeq_loc_CI_Impl),
2435  m_Index(0)
2436 {
2437 }
2438 
2439 
2441  EEmptyFlag empty_flag,
2442  ESeqLocOrder order)
2443  : m_Impl(new CSeq_loc_CI_Impl(loc, empty_flag, order)),
2444  m_Index(0)
2445 {
2446 }
2447 
2448 
2449 CSeq_loc_CI::CSeq_loc_CI(const CSeq_loc_CI& iter, size_t pos)
2450  : m_Impl(iter.m_Impl),
2451  m_Index(0)
2452 {
2453  SetPos(pos);
2454 }
2455 
2456 
2458 {
2459 }
2460 
2461 
2463  : m_Impl(iter.m_Impl),
2464  m_Index(iter.m_Index)
2465 {
2466 }
2467 
2468 
2470 {
2471  m_Impl = iter.m_Impl;
2472  m_Index = iter.m_Index;
2473  return *this;
2474 }
2475 
2476 
2477 bool CSeq_loc_CI::operator== (const CSeq_loc_CI& iter) const
2478 {
2479  // Check if both are at end.
2480  bool is_end = m_Impl->IsEnd(m_Index);
2481  if ( iter.m_Impl->IsEnd(iter.m_Index) ) {
2482  return is_end;
2483  }
2484  else {
2485  return !is_end && m_Impl == iter.m_Impl && m_Index == iter.m_Index;
2486  }
2487 }
2488 
2489 
2490 bool CSeq_loc_CI::operator!= (const CSeq_loc_CI& iter) const
2491 {
2492  return !(*this == iter);
2493 }
2494 
2495 
2496 bool CSeq_loc_CI::IsInBond(void) const
2497 {
2498  x_CheckValid("IsInBond()");
2499  return m_Impl->IsInBond(m_Index);
2500 }
2501 
2502 
2503 bool CSeq_loc_CI::IsBondA(void) const
2504 {
2505  x_CheckValid("IsBondA()");
2506  return m_Impl->IsBondPartA(m_Index);
2507 }
2508 
2509 
2510 bool CSeq_loc_CI::IsBondB(void) const
2511 {
2512  x_CheckValid("IsBondB()");
2513  return m_Impl->IsBondPartB(m_Index);
2514 }
2515 
2516 
2517 pair<CSeq_loc_CI, CSeq_loc_CI>
2519 {
2520  x_CheckValid("GetBondRange()");
2521  pair<size_t, size_t> indexes = m_Impl->GetBondRange(m_Index);
2522  return make_pair(CSeq_loc_CI(*this, indexes.first),
2523  CSeq_loc_CI(*this, indexes.second));
2524 }
2525 
2526 
2528 {
2529  return m_Impl->HasEquivSets();
2530 }
2531 
2532 
2534 {
2535  x_CheckValid("IsInEquivSet()");
2536  return m_Impl->IsInEquivSet(m_Index);
2537 }
2538 
2539 
2541 {
2542  x_CheckValid("GetEquivSetsCount()");
2543  return m_Impl->GetEquivSetsCount(m_Index);
2544 }
2545 
2546 
2547 pair<CSeq_loc_CI, CSeq_loc_CI>
2549 {
2550  x_CheckValid("GetEquivSetRange()");
2551  pair<size_t, size_t> indexes = m_Impl->GetEquivSetRange(m_Index, level);
2552  return make_pair(CSeq_loc_CI(*this, indexes.first),
2553  CSeq_loc_CI(*this, indexes.second));
2554 }
2555 
2556 
2557 pair<CSeq_loc_CI, CSeq_loc_CI>
2559 {
2560  x_CheckValid("GetEquivPartRange()");
2561  pair<size_t, size_t> indexes = m_Impl->GetEquivPartRange(m_Index, level);
2562  return make_pair(CSeq_loc_CI(*this, indexes.first),
2563  CSeq_loc_CI(*this, indexes.second));
2564 }
2565 
2566 
2568 {
2569  return GetEmbeddingSeq_loc();
2570 }
2571 
2572 
2574 {
2575  x_CheckValid("GetEmbeddingSeq_loc()");
2577  if ( !loc ) {
2579  "CSeq_loc_CI::GetSeq_loc(): NULL seq-loc");
2580  }
2581  return *loc;
2582 }
2583 
2584 
2586 {
2587  x_CheckValid("GetRangeAsSeq_loc()");
2589  if ( info.m_Loc ) {
2590  switch ( info.m_Loc->Which() ) {
2591  // Single-range, empty or whole seq-loc can be used as-is.
2592  case CSeq_loc::e_not_set:
2593  case CSeq_loc::e_Null:
2594  case CSeq_loc::e_Empty:
2595  case CSeq_loc::e_Whole:
2596  case CSeq_loc::e_Int:
2597  case CSeq_loc::e_Pnt:
2598  return info.m_Loc;
2599  default:
2600  break;
2601  }
2602  }
2603  // Create a new seq-loc for the current range.
2605  return ConstRef(loc.Release());
2606 }
2607 
2608 
2609 bool CSeq_loc_CI::x_IsValid(void) const
2610 {
2611  return m_Impl && m_Index < m_Impl->GetRanges().size();
2612 }
2613 
2614 
2615 void CSeq_loc_CI::x_ThrowNotValid(const char* where) const
2616 {
2617  NCBI_THROW_FMT(CSeqLocException, eBadIterator,
2618  x_GetIteratorType() << "::" << where << ": "
2619  "iterator is not valid");
2620 }
2621 
2622 
2623 const char* CSeq_loc_CI::x_GetIteratorType(void) const
2624 {
2625  return "CSeq_loc_CI";
2626 }
2627 
2628 
2630 {
2631  // The index validity must be checked by the caller.
2632  return m_Impl->GetRanges()[m_Index];
2633 }
2634 
2635 
2636 size_t CSeq_loc_CI::GetSize(void) const
2637 {
2638  return m_Impl->GetRanges().size();
2639 }
2640 
2641 
2642 void CSeq_loc_CI::SetPos(size_t pos)
2643 {
2644  if ( pos > GetSize() ) {
2645  NCBI_THROW_FMT(CSeqLocException, eOtherError,
2646  x_GetIteratorType() << "::SetPos(): "
2647  "position is too big: "<<pos<<" > "<<GetSize());
2648  }
2649  m_Index = pos;
2650 }
2651 
2652 
2653 /////////////////////////////////////////////////////////////////////////////
2654 // CSeq_loc_I
2655 
2657 {
2658 }
2659 
2660 
2662  : CSeq_loc_CI(loc, eEmpty_Allow, eOrder_Biological)
2663 {
2664 }
2665 
2666 
2667 CSeq_loc_I::CSeq_loc_I(const CSeq_loc_I& iter, size_t pos)
2668  : CSeq_loc_CI(iter)
2669 {
2670  SetPos(pos);
2671 }
2672 
2673 
2675 {
2676 }
2677 
2678 
2680 {
2681  return m_Impl && m_Index <= m_Impl->GetRanges().size();
2682 }
2683 
2684 
2685 const char* CSeq_loc_I::x_GetIteratorType(void) const
2686 {
2687  return "CSeq_loc_I";
2688 }
2689 
2690 
2692 {
2693  // The index validity must be checked by the caller.
2694  return m_Impl->GetRanges()[m_Index];
2695 }
2696 
2697 
2699  const CSeq_id_Handle& id)
2700 {
2701  info.m_Id = id.GetSeqId();
2702  info.m_IdHandle = id;
2703 }
2704 
2705 
2706 bool CSeq_loc_I::HasChanges(void) const
2707 {
2708  return m_Impl->HasChanges();
2709 }
2710 
2711 
2713 {
2714  return m_Impl->GetEquivMode();
2715 }
2716 
2717 
2719 {
2721 }
2722 
2723 
2725 {
2726  x_CheckValid("Delete()");
2728 }
2729 
2730 
2732 {
2733  x_CheckValidForInsert("InsertNull()");
2735  return CSeq_loc_I(*this, m_Index++);
2736 }
2737 
2738 
2740 {
2741  x_CheckValidForInsert("InsertEmpty()");
2744  x_SetSeq_id_Handle(info, id);
2745  return CSeq_loc_I(*this, m_Index++);
2746 }
2747 
2748 
2750 {
2751  x_CheckValidForInsert("InsertWhole()");
2754  x_SetSeq_id_Handle(info, id);
2755  info.m_Range = TRange::GetWhole();
2756  return CSeq_loc_I(*this, m_Index++);
2757 }
2758 
2759 
2761  TSeqPos pos,
2762  ENa_strand strand)
2763 {
2764  x_CheckValidForInsert("InsertPoint()");
2767  x_SetSeq_id_Handle(info, id);
2768  info.m_Range.SetFrom(pos).SetLength(1);
2769  if ( strand != eNa_strand_unknown ) {
2770  info.SetStrand(strand);
2771  }
2772  m_Impl->SetPoint(info);
2773  return CSeq_loc_I(*this, m_Index++);
2774 }
2775 
2776 
2778  const TRange& range,
2779  ENa_strand strand)
2780 {
2781  x_CheckValidForInsert("InsertInterval()");
2784  x_SetSeq_id_Handle(info, id);
2785  info.m_Range = range;
2786  if ( strand != eNa_strand_unknown ) {
2787  info.SetStrand(strand);
2788  }
2789  if ( !range.IsWhole() && !range.Empty() ) {
2790  info.m_Loc = m_Impl->MakeLocInterval(info);
2791  }
2792  return CSeq_loc_I(*this, m_Index++);
2793 }
2794 
2795 
2797 {
2798  x_CheckValid("SetSeq_id_Handle()");
2800  if ( info.m_IdHandle != id ) {
2801  x_SetSeq_id_Handle(info, id);
2803  }
2804 }
2805 
2806 
2808 {
2809  x_CheckValid("SetRange()");
2811  if ( info.m_Range != range ) {
2812  info.m_Range = range;
2813  m_Impl->UpdateLoc(info);
2814  }
2815 }
2816 
2817 
2819 {
2820  x_CheckValid("SetFrom()");
2822  if ( info.m_Range.GetFrom() != from ) {
2823  info.m_Range.SetFrom(from);
2824  m_Impl->UpdateLoc(info);
2825  }
2826 }
2827 
2828 
2830 {
2831  x_CheckValid("SetTo()");
2833  if ( info.m_Range.GetTo() != to ) {
2834  info.m_Range.SetTo(to);
2835  m_Impl->UpdateLoc(info);
2836  }
2837 }
2838 
2839 
2841 {
2842  x_CheckValid("SetPoint()");
2844  if ( !m_Impl->WasPoint(info) || info.m_Range != TRange(pos, pos) ) {
2845  info.m_Range = TRange(pos, pos);
2846  if ( m_Impl->WasPoint(info) ) {
2848  }
2849  else {
2850  m_Impl->SetPoint(info);
2851  }
2852  }
2853 }
2854 
2855 
2857 {
2858  x_CheckValid("ResetStrand()");
2860  if ( info.m_IsSetStrand ) {
2861  info.m_IsSetStrand = false;
2862  info.m_Strand = eNa_strand_unknown;
2864  }
2865 }
2866 
2867 
2869 {
2870  x_CheckValid("SetStrand()");
2872  if ( !info.m_IsSetStrand || info.m_Strand != strand ) {
2873  info.SetStrand(strand);
2875  }
2876 }
2877 
2878 
2880 {
2881  x_CheckValid("ResetFuzzFrom()");
2883  if ( info.m_Fuzz.first ) {
2884  info.m_Fuzz.first = null;
2885  m_Impl->UpdateLoc(info);
2886  }
2887 }
2888 
2889 
2891 {
2892  x_CheckValid("SetFuzzFrom()");
2894  if ( !info.m_Fuzz.first || !info.m_Fuzz.first->Equals(fuzz) ) {
2895  info.m_Fuzz.first = SerialClone(fuzz);
2896  m_Impl->UpdateLoc(info);
2897  }
2898 }
2899 
2900 
2902 {
2903  x_CheckValid("ResetFuzzTo()");
2905  if ( info.m_Fuzz.second ) {
2906  info.m_Fuzz.second = null;
2907  m_Impl->UpdateLoc(info);
2908  }
2909 }
2910 
2911 
2913 {
2914  x_CheckValid("SetFuzzTo()");
2916  if ( !info.m_Fuzz.second || !info.m_Fuzz.second->Equals(fuzz) ) {
2917  info.m_Fuzz.second = SerialClone(fuzz);
2918  m_Impl->UpdateLoc(info);
2919  }
2920 }
2921 
2922 
2924 {
2925  x_CheckValid("ResetFuzz()");
2927  if ( info.m_Fuzz.first || info.m_Fuzz.second ) {
2928  info.m_Fuzz.first = info.m_Fuzz.second = null;
2930  }
2931 }
2932 
2933 
2935 {
2936  x_CheckValid("SetFuzz()");
2938  if ( !info.m_Fuzz.first || !info.m_Fuzz.first->Equals(fuzz) ||
2939  info.m_Fuzz.first != info.m_Fuzz.second ) {
2940  info.m_Fuzz.first = info.m_Fuzz.second = SerialClone(fuzz);
2942  }
2943 }
2944 
2945 
2947 {
2948  return m_Impl->MakeLoc(make_type);
2949 }
2950 
2951 
2952 pair<CSeq_loc_I, CSeq_loc_I>
2953 CSeq_loc_I::GetEquivSetRange(size_t level) const
2954 {
2955  x_CheckValid("GetEquivSetRange()");
2956  pair<size_t, size_t> indexes = m_Impl->GetEquivSetRange(m_Index, level);
2957  return make_pair(CSeq_loc_I(*this, indexes.first),
2958  CSeq_loc_I(*this, indexes.second));
2959 }
2960 
2961 
2962 pair<CSeq_loc_I, CSeq_loc_I>
2964 {
2965  x_CheckValid("GetEquivPartRange()");
2966  pair<size_t, size_t> indexes = m_Impl->GetEquivPartRange(m_Index, level);
2967  return make_pair(CSeq_loc_I(*this, indexes.first),
2968  CSeq_loc_I(*this, indexes.second));
2969 }
2970 
2971 
2973 {
2974  x_CheckValid("RemoveBond()");
2976 }
2977 
2978 
2980 {
2981  x_CheckValid("MakeBondA()");
2983 }
2984 
2985 
2987 {
2988  x_CheckValid("MakeBondAB()");
2990 }
2991 
2992 
2994 {
2995  x_CheckValid("MakeBondB()");
2997 }
2998 
2999 
3000 // CSeq_loc_I
3001 /////////////////////////////////////////////////////////////////////////////
3002 
3003 
3004 // Append a string representation of a CSeq_id to label
3005 inline
3006 void s_GetLabel(const CSeq_id& id, string* label)
3007 {
3008  CNcbiOstrstream os;
3009  id.WriteAsFasta(os);
3011 }
3012 
3013 
3014 // Append to label info for a CSeq_point
3015 inline
3017 (const CSeq_point& pnt,
3018  const CSeq_id* last_id,
3019  string* label)
3020 {
3021  // If CSeq_id does not match last_id, then append id to label
3022  if ( !last_id || !last_id->Match(pnt.GetId()) ) {
3023  s_GetLabel(pnt.GetId(), label);
3024  *label += ":";
3025  }
3026 
3027  // Add strand info to label
3028  if (pnt.IsSetStrand()) {
3029  *label += GetTypeInfo_enum_ENa_strand()
3030  ->FindName(pnt.GetStrand(), true);
3031  }
3032 
3033  if (pnt.IsSetFuzz()) {
3034  // Append Fuzz info to label
3035  pnt.GetFuzz().GetLabel(label, pnt.GetPoint());
3036  } else {
3037  // Append 1 based point to label
3038  *label += NStr::IntToString(pnt.GetPoint()+1);
3039  }
3040 
3041  // update last_id
3042  last_id = &pnt.GetId();
3043  return last_id;
3044 }
3045 
3046 
3047 // Append to label info for CSeq_interval
3048 inline
3050 (const CSeq_interval& itval,
3051  const CSeq_id* last_id,
3052  string* label)
3053 {
3054  if (!last_id || !last_id->Match(itval.GetId())) {
3055  s_GetLabel(itval.GetId(), label);
3056  *label += ":";
3057  }
3058  last_id = &itval.GetId();
3059  //if (itval.IsSetStrand() && itval.GetStrand() != eNa_strand_unknown) {
3060  if (itval.IsSetStrand() && (itval.GetStrand() == eNa_strand_minus || itval.GetStrand() == eNa_strand_both_rev)) {
3061  //*label += GetTypeInfo_enum_ENa_strand()->FindName(itval.GetStrand(), true);
3062  *label += "c";
3063  }
3064  if (itval.IsSetStrand() &&
3065  (itval.GetStrand() == eNa_strand_minus ||
3066  itval.GetStrand() == eNa_strand_both_rev)) {
3067  if (itval.IsSetFuzz_to()) {
3068  itval.GetFuzz_to().GetLabel(label, itval.GetTo(), false);
3069  } else {
3070  *label += NStr::IntToString(itval.GetTo()+1);
3071  }
3072  *label += "-";
3073  if (itval.IsSetFuzz_from()) {
3074  itval.GetFuzz_from().GetLabel(label, itval.GetFrom());
3075  } else {
3076  *label += NStr::IntToString(itval.GetFrom()+1);
3077  }
3078  } else {
3079  if (itval.IsSetFuzz_from()) {
3080  itval.GetFuzz_from().GetLabel
3081  (label, itval.GetFrom(), false);
3082  } else {
3083  *label += NStr::IntToString(itval.GetFrom()+1);
3084  }
3085  *label += "-";
3086  if (itval.IsSetFuzz_to()) {
3087  itval.GetFuzz_to().GetLabel(label, itval.GetTo());
3088  } else {
3089  *label += NStr::IntToString(itval.GetTo()+1);
3090  }
3091  }
3092  return last_id;
3093 }
3094 
3095 
3096 // Forward declaration
3097 const CSeq_id* s_GetLabel
3098 (const CSeq_loc& loc,
3099  const CSeq_id* last_id,
3100  string* label,
3101  bool first = false);
3102 
3103 
3104 // Appends to label info for each CSeq_loc in a list of CSeq_locs
3105 inline
3107 (const list<CRef<CSeq_loc> >& loc_list,
3108  const CSeq_id* last_id,
3109  string* label)
3110 {
3111  bool first = true;
3112  ITERATE (list<CRef<CSeq_loc> >, it, loc_list) {
3113 
3114  // Append to label for each CSeq_loc in list
3115  last_id = s_GetLabel(**it, last_id, label, first);
3116  first = false;
3117  }
3118 
3119  return last_id;
3120 }
3121 
3122 
3123 // Builds a label based upon a CSeq_loc and all embedded CSeq_locs
3125 (const CSeq_loc& loc,
3126  const CSeq_id* last_id,
3127  string* label,
3128  bool first)
3129 {
3130  // Ensure label is not null
3131  if (!label) {
3132  return last_id;
3133  }
3134 
3135  // Put a comma separator if necessary
3136  if (!first) {
3137  *label += ", ";
3138  }
3139 
3140  // Loop through embedded CSeq_locs and create a label, depending on
3141  // type of CSeq_loc
3142  switch (loc.Which()) {
3143  case CSeq_loc::e_Null:
3144  *label += "~";
3145  break;
3146  case CSeq_loc::e_Empty:
3147  *label += "{";
3148  s_GetLabel(loc.GetEmpty(), label);
3149  last_id = &loc.GetEmpty();
3150  *label += "}";
3151  break;
3152  case CSeq_loc::e_Whole:
3153  s_GetLabel(loc.GetWhole(), label);
3154  last_id = &loc.GetWhole();
3155  break;
3156  case CSeq_loc::e_Int:
3157  last_id = s_GetLabel(loc.GetInt(), last_id, label);
3158  break;
3160  {
3161  *label += "(";
3162  bool frst = true;
3164  if (!frst) {
3165  *label += ", ";
3166  }
3167  frst = false;
3168  last_id = s_GetLabel(**it, last_id, label);
3169  }
3170  *label += ")";
3171  break;
3172  }
3173  case CSeq_loc::e_Pnt:
3174  last_id = s_GetLabel(loc.GetPnt(), last_id, label);
3175  break;
3177  *label += "(" + loc.GetPacked_pnt().GetId().AsFastaString() + ":";
3178  {{
3179  string str;
3181  loc.GetPacked_pnt().GetPoints()) {
3182  if ( !str.empty() ) {
3183  str += ", ";
3184  }
3185  str += NStr::IntToString(*iter);
3186  }
3187  *label += str;
3188  }}
3189  *label += ")";
3190  last_id = &loc.GetPacked_pnt().GetId();
3191  break;
3192  case CSeq_loc::e_Mix:
3193  *label += "[";
3194  last_id = s_GetLabel(loc.GetMix().Get(), last_id, label);
3195  *label += "]";
3196  break;
3197  case CSeq_loc::e_Equiv:
3198  *label += "[";
3199  last_id = s_GetLabel(loc.GetEquiv().Get(), last_id, label);
3200  *label += "]";
3201  break;
3202  case CSeq_loc::e_Bond:
3203  last_id = s_GetLabel(loc.GetBond().GetA(), last_id, label);
3204  *label += "=";
3205  if (loc.GetBond().IsSetB()) {
3206  last_id = s_GetLabel(loc.GetBond().GetB(), last_id, label);
3207  } else {
3208  *label += "?";
3209  }
3210  break;
3211  case CSeq_loc::e_Feat:
3212  *label += "(feat)";
3213  break;
3214  default:
3215  *label += "(?\?)";
3216  break;
3217  }
3218  return last_id;
3219 }
3220 
3221 
3223 {
3224  switch (Which ()) {
3225  case e_Null :
3226  return true;
3227 
3228  case e_Int :
3229  return GetInt().IsPartialStart(ext);
3230 
3231  case e_Packed_int :
3232  return GetPacked_int().IsPartialStart(ext);
3233 
3234  case e_Pnt :
3235  return GetPnt().IsPartialStart(ext);
3236 
3237  case e_Packed_pnt :
3238  return GetPacked_pnt().IsPartialStart(ext);
3239 
3240  case e_Mix :
3241  return GetMix().IsPartialStart(ext);
3242 
3243  default :
3244  break;
3245  }
3246 
3247  return false;
3248 }
3249 
3250 
3252 {
3253  switch (Which ()) {
3254  case e_Null :
3255  return true;
3256 
3257  case e_Int :
3258  return GetInt().IsPartialStop(ext);
3259 
3260  case e_Packed_int :
3261  return GetPacked_int().IsPartialStop(ext);
3262 
3263  case e_Pnt :
3264  return GetPnt().IsPartialStop(ext);
3265 
3266  case e_Packed_pnt :
3267  return GetPacked_pnt().IsPartialStop(ext);
3268 
3269  case e_Mix :
3270  return GetMix().IsPartialStop(ext);
3271 
3272  default :
3273  break;
3274  }
3275 
3276  return false;
3277 }
3278 
3279 
3281 {
3282  if (val == IsPartialStart(ext)) {
3283  return;
3284  }
3285 
3286  switch (Which()) {
3287  case e_Int:
3288  SetInt().SetPartialStart(val, ext);
3289  break;
3290 
3291  case e_Packed_int :
3293  break;
3294 
3295  case e_Pnt:
3296  SetPnt().SetPartialStart(val, ext);
3297  break;
3298 
3299  case e_Packed_pnt:
3301  break;
3302 
3303  case e_Mix :
3304  SetMix().SetPartialStart(val, ext);
3305  break;
3306 
3307  default :
3308  break;
3309  }
3310 }
3311 
3312 
3314 {
3315  if (val == IsPartialStop(ext)) {
3316  return;
3317  }
3318 
3319  switch (Which()) {
3320  case e_Int:
3321  SetInt().SetPartialStop(val, ext);
3322  break;
3323 
3324  case e_Packed_int :
3326  break;
3327 
3328  case e_Pnt:
3329  SetPnt().SetPartialStop(val, ext);
3330  break;
3331 
3332  case e_Packed_pnt:
3334  break;
3335 
3336  case e_Mix:
3337  SetMix().SetPartialStop(val, ext);
3338  break;
3339 
3340  default :
3341  break;
3342  }
3343 }
3344 
3345 
3347 {
3348  switch (Which ()) {
3349  case e_Int :
3350  return GetInt().IsTruncatedStart(ext);
3351 
3352  case e_Packed_int :
3353  return GetPacked_int().IsTruncatedStart(ext);
3354 
3355  case e_Pnt :
3356  return GetPnt().IsTruncatedStart(ext);
3357 
3358  case e_Packed_pnt :
3359  return GetPacked_pnt().IsTruncatedStart(ext);
3360 
3361  case e_Mix :
3362  return GetMix().IsTruncatedStart(ext);
3363 
3364  default :
3365  break;
3366  }
3367 
3368  return false;
3369 }
3370 
3371 
3373 {
3374  switch (Which ()) {
3375  case e_Int :
3376  return GetInt().IsTruncatedStop(ext);
3377 
3378  case e_Packed_int :
3379  return GetPacked_int().IsTruncatedStop(ext);
3380 
3381  case e_Pnt :
3382  return GetPnt().IsTruncatedStop(ext);
3383 
3384  case e_Packed_pnt :
3385  return GetPacked_pnt().IsTruncatedStop(ext);
3386 
3387  case e_Mix :
3388  return GetMix().IsTruncatedStop(ext);
3389 
3390  default :
3391  break;
3392  }
3393 
3394  return false;
3395 }
3396 
3397 
3399 {
3400  if (val == IsTruncatedStart(ext)) {
3401  return;
3402  }
3403 
3404  switch (Which()) {
3405  case e_Int:
3406  SetInt().SetTruncatedStart(val, ext);
3407  break;
3408 
3409  case e_Packed_int :
3411  break;
3412 
3413  case e_Pnt:
3414  SetPnt().SetTruncatedStart(val, ext);
3415  break;
3416 
3417  case e_Packed_pnt:
3419  break;
3420 
3421  case e_Mix :
3422  SetMix().SetTruncatedStart(val, ext);
3423  break;
3424 
3425  default :
3426  break;
3427  }
3428 }
3429 
3430 
3432 {
3433  if (val == IsTruncatedStop(ext)) {
3434  return;
3435  }
3436 
3437  switch (Which()) {
3438  case e_Int:
3439  SetInt().SetTruncatedStop(val, ext);
3440  break;
3441 
3442  case e_Packed_int :
3444  break;
3445 
3446  case e_Pnt:
3447  SetPnt().SetTruncatedStop(val, ext);
3448  break;
3449 
3450  case e_Packed_pnt:
3452  break;
3453 
3454  case e_Mix:
3455  SetMix().SetTruncatedStop(val, ext);
3456  break;
3457 
3458  default :
3459  break;
3460  }
3461 }
3462 
3463 
3464 // Appends a label suitable for display (e.g., error messages)
3465 // label must point to an existing string object
3466 // Method just returns if label is null
3467 void CSeq_loc::GetLabel(string* label) const
3468 {
3469  s_GetLabel(*this, 0, label, true);
3470 }
3471 
3472 
3473 // assign the 'id' field of each sub-interval to the supplied id
3475 {
3476  InvalidateCache();
3477  switch (Which()) {
3478  case e_Null:
3479  break;
3480 
3481  case e_Int:
3482  SetInt().SetId(id);
3483  break;
3484 
3485  case e_Pnt:
3486  SetPnt().SetId(id);
3487  break;
3488 
3489  case e_Packed_int:
3491  (*iter)->SetId(id);
3492  }
3493  break;
3494 
3495  case e_Packed_pnt:
3496  SetPacked_pnt().SetId(id);
3497  break;
3498 
3499  case e_Mix:
3500  NON_CONST_ITERATE (CSeq_loc_mix::Tdata, iter, SetMix().Set()) {
3501  (*iter)->SetId(id);
3502  }
3503  break;
3504 
3505  case e_Whole:
3506  SetWhole(id);
3507  break;
3508 
3509  case e_Empty:
3510  SetEmpty(id);
3511  break;
3512 
3513  case e_Equiv:
3515  (*iter)->SetId(id);
3516  }
3517  break;
3518 
3519  case e_Bond:
3520  if (GetBond().IsSetA()) {
3521  SetBond().SetA().SetId(id);
3522  }
3523  if (GetBond().IsSetB()) {
3524  SetBond().SetB().SetId(id);
3525  }
3526  break;
3527 
3528  case e_Feat:
3529  ERR_POST_X(1, Error
3530  << "unhandled loc type in CSeq_loc::SetId(): e_Feat");
3531  break;
3532 
3533  default:
3534  ERR_POST_X(2, Error << "unhandled loc type in CSeq_loc::SetId(): "
3535  << Which());
3536  break;
3537  }
3538 }
3539 
3540 
3541 bool CSeq_loc::x_CheckId(const CSeq_id*& id, bool may_throw) const
3542 {
3543  switch ( Which() ) {
3544  case e_not_set:
3545  case e_Null:
3546  {
3547  // no Seq-id
3548  return true;
3549  }
3550  case e_Empty:
3551  {
3552  return x_UpdateId(id, &GetEmpty(), may_throw);
3553  }
3554  case e_Whole:
3555  {
3556  return x_UpdateId(id, &GetWhole(), may_throw);
3557  }
3558  case e_Int:
3559  {
3560  const CSeq_interval& loc = GetInt();
3561  return x_UpdateId(id, &loc.GetId(), may_throw);
3562  }
3563  case e_Pnt:
3564  {
3565  const CSeq_point& pnt = GetPnt();
3566  return x_UpdateId(id, &pnt.GetId(), may_throw);
3567  }
3568  case e_Packed_int:
3569  {
3570  // Check ID of each interval
3571  const CPacked_seqint& ints = GetPacked_int();
3572  ITERATE ( CPacked_seqint::Tdata, ii, ints.Get() ) {
3573  const CSeq_interval& loc = **ii;
3574  if ( !x_UpdateId(id, &loc.GetId(), may_throw) ) {
3575  return false;
3576  }
3577  }
3578  return true;
3579  }
3580  case e_Packed_pnt:
3581  {
3582  const CPacked_seqpnt& pnts = GetPacked_pnt();
3583  return x_UpdateId(id, &pnts.GetId(), may_throw);
3584  break;
3585  }
3586  case e_Mix:
3587  {
3588  // Check ID of each sub-location.
3589  const CSeq_loc_mix& mix = GetMix();
3590  ITERATE( CSeq_loc_mix::Tdata, li, mix.Get() ) {
3591  if ( !(*li)->CheckId(id, may_throw) ) {
3592  return false;
3593  }
3594  }
3595  return true;
3596  }
3597  case e_Bond:
3598  {
3599  const CSeq_bond& bond = GetBond();
3600  if ( bond.CanGetA() ) {
3601  if ( !x_UpdateId(id, &bond.GetA().GetId(), may_throw) ) {
3602  return false;
3603  }
3604  }
3605  if ( bond.CanGetB() ) {
3606  return x_UpdateId(id, &bond.GetB().GetId(), may_throw);
3607  }
3608  return true;
3609  }
3610  case e_Equiv:
3611  {
3612  // Doesn't make much sense to test equiv, but ...
3614  if ( !(*li)->CheckId(id, may_throw) ) {
3615  return false;
3616  }
3617  }
3618  return true;
3619  }
3620  case e_Feat:
3621  default:
3622  if (may_throw) {
3623  NCBI_THROW_FMT(CSeqLocException, eUnsupported,
3624  "CSeq_loc::CheckId(): "
3625  "unsupported location type: "<<
3626  SelectionName(Which()));
3627  }
3628  return false;
3629  }
3630 }
3631 
3632 
3634 {
3635  switch ( Which() ) {
3636  case e_not_set:
3637  {
3638  SetMix();
3639  break;
3640  }
3641  case e_Mix:
3642  {
3643  break;
3644  }
3645  case e_Packed_int:
3646  {
3647  // unpack
3648  CRef<CSeq_loc> self(new CSeq_loc);
3649  self->Assign(*this, eShallow);
3650 
3651  CSeq_loc_mix& mix = SetMix();
3652  NON_CONST_ITERATE (CPacked_seqint::Tdata, it, self->SetPacked_int().Set()) {
3653  CRef<CSeq_loc> ival(new CSeq_loc);
3654  ival->SetInt(**it);
3655  mix.Set().push_back(ival);
3656  }
3657  break;
3658  }
3659  default:
3660  {
3661  CRef<CSeq_loc> self(new CSeq_loc);
3662  self->Assign(*this, eShallow);
3663  CSeq_loc_mix& mix = SetMix();
3664  mix.AddSeqLoc(*self);
3665  }
3666  }
3667 }
3668 
3669 
3671 {
3672  switch ( Which() ) {
3673  case e_not_set:
3674  case e_Null:
3675  {
3676  SetPacked_int();
3677  return;
3678  }
3679  case e_Packed_int:
3680  {
3681  return;
3682  }
3683  case e_Int:
3684  {
3686  SetPacked_int().AddInterval(*self);
3687  return;
3688  }
3689  case e_Pnt:
3690  {
3691  // Make an interval of length 1
3692  CRef<CSeq_interval> new_int(new CSeq_interval);
3693  new_int->SetId().Assign(GetPnt().GetId());
3694  new_int->SetFrom(GetPnt().GetPoint());
3695  new_int->SetTo(GetPnt().GetPoint());
3696  if (GetPnt().IsSetStrand()) {
3697  new_int->SetStrand(GetPnt().GetStrand());
3698  }
3699  if (GetPnt().IsSetFuzz()) {
3700  const CInt_fuzz& fuzz = GetPnt().GetFuzz();
3701  if (!fuzz.IsLim() || fuzz.GetLim() != CInt_fuzz::eLim_gt) {
3702  new_int->SetFuzz_from().Assign(fuzz);
3703  }
3704  if (!fuzz.IsLim() || fuzz.GetLim() != CInt_fuzz::eLim_lt) {
3705  new_int->SetFuzz_to().Assign(fuzz);
3706  }
3707  }
3708  SetPacked_int().AddInterval(*new_int);
3709  return;
3710  }
3711  case e_Mix:
3712  {
3713  // Recursively convert each sub-location to packed-int, then merge.
3714  // Work with copies of sub-locs so that if an exception is thrown
3715  // the original location remains unchanged.
3716  vector<CRef<CSeq_loc> > sub_locs;
3717  sub_locs.reserve(GetMix().Get().size());
3718  ITERATE (CSeq_loc_mix::Tdata, orig_sub_loc, GetMix().Get()) {
3719  CRef<CSeq_loc> new_sub_loc(new CSeq_loc);
3720  new_sub_loc->Assign(**orig_sub_loc);
3721  new_sub_loc->ChangeToPackedInt();
3722  sub_locs.push_back(new_sub_loc);
3723  }
3724  SetPacked_int(); // in case there are zero intervals
3725  ITERATE (vector<CRef<CSeq_loc> >, sub_loc, sub_locs) {
3726  copy((*sub_loc)->GetPacked_int().Get().begin(),
3727  (*sub_loc)->GetPacked_int().Get().end(),
3728  back_inserter(SetPacked_int().Set()));
3729  }
3730  return;
3731  }
3732  default:
3733  NCBI_THROW_FMT(CSeqLocException, eIncomatible,
3734  "CSeq_loc::ChangeToPackedInt(): "
3735  "Can not convert location to packed-int: "<<
3736  SelectionName(Which()));
3737  }
3738 }
3739 
3740 
3742 {
3743  ChangeToMix();
3744  SetMix().AddSeqLoc(other);
3745 }
3746 
3747 
3749 {
3750  _ASSERT(IsInt());
3751 
3753  SetPacked_int().AddInterval(other);
3754 }
3755 
3756 
3758 {
3759  _ASSERT(IsInt());
3760  _ASSERT(other.IsInt() || other.IsPacked_int());
3761 
3763 
3764  if ( other.IsInt() ) {
3765  SetPacked_int().AddInterval(other.GetInt());
3766  } else { // other is packed int
3768  }
3769 }
3770 
3771 
3773 {
3774  _ASSERT(IsPnt());
3775  _ASSERT(other.IsPnt() || other.IsPacked_pnt());
3776 
3777  CRef<CSeq_point> pnt(&SetPnt());
3778  CPacked_seqpnt& ppnt = SetPacked_pnt();
3779  if ( pnt->IsSetStrand() ) {
3780  ppnt.SetStrand(pnt->GetStrand());
3781  }
3782  if ( pnt->IsSetId() ) {
3783  ppnt.SetId(pnt->SetId());
3784  }
3785  if ( pnt->IsSetFuzz() ) {
3786  ppnt.SetFuzz(pnt->SetFuzz());
3787  }
3788  ppnt.AddPoint(pnt->GetPoint());
3789 
3790  if ( other.IsPnt() ) {
3791  ppnt.AddPoint(other.GetPnt().GetPoint());
3792  } else { // other is packed point
3793  ppnt.AddPoints(other.GetPacked_pnt().GetPoints());
3794  }
3795 }
3796 
3797 
3798 template<typename T1, typename T2>
3799 bool s_CanAdd(const T1& obj1, const T2& obj2)
3800 {
3801  // test strands
3802  {{
3803  ENa_strand s1 = obj1.CanGetStrand() ? obj1.GetStrand() : eNa_strand_unknown;
3804  ENa_strand s2 = obj2.CanGetStrand() ? obj2.GetStrand() : eNa_strand_unknown;
3805  if ( s1 != s2 ) {
3806  return false;
3807  }
3808  }}
3809 
3810  // test ids
3811  {{
3812  const CSeq_id* id1 = obj1.CanGetId() ? &obj1.GetId() : 0;
3813  const CSeq_id* id2 = obj2.CanGetId() ? &obj2.GetId() : 0;
3814  // both null - ok to add (this will probably never happen)
3815  if (id1 == 0 && id2 == 0) return true;
3816  // ids are different (one may be null)
3817  if (id1 == 0 || id2 == 0 || !id1->Match(*id2) ) {
3818  return false;
3819  }
3820  }}
3821 
3822  // test fuzz
3823  {{
3824  const CInt_fuzz* f1 = obj1.CanGetFuzz() ? &obj1.GetFuzz() : 0;
3825  const CInt_fuzz* f2 = obj2.CanGetFuzz() ? &obj2.GetFuzz() : 0;
3826  // both null - ok to add
3827  if (f1 == 0 && f2 == 0) return true;
3828  // fuzzes are different (one may be null)
3829  if (f1 == 0 || f2 == 0 || !f1->Equals(*f2)) {
3830  return false;
3831  }
3832  }}
3833 
3834  return true;
3835 }
3836 
3837 
3838 bool s_CanAdd(const CSeq_loc& loc1, const CSeq_loc& loc2)
3839 {
3840  switch ( loc1.Which() ) {
3841  case CSeq_loc::e_Pnt:
3842  {
3843  switch ( loc2.Which() ) {
3844  case CSeq_loc::e_Pnt:
3845  return s_CanAdd(loc1.GetPnt(), loc2.GetPnt());
3847  return s_CanAdd(loc1.GetPnt(), loc2.GetPacked_pnt());
3848  default:
3849  break;
3850  }
3851  break;
3852  }
3854  {
3855  switch ( loc2.Which() ) {
3856  case CSeq_loc::e_Pnt:
3857  return s_CanAdd(loc1.GetPacked_pnt(), loc2.GetPnt());
3859  return s_CanAdd(loc1.GetPacked_pnt(), loc2.GetPacked_pnt());
3860  default:
3861  break;
3862  }
3863  break;
3864  }
3865  default:
3866  {
3867  return false;
3868  }
3869  }
3870 
3871  return false;
3872 }
3873 
3874 
3875 void CSeq_loc::Add(const CSeq_loc& other)
3876 {
3877  InvalidateCache();
3878  switch ( Which() ) {
3879  case e_not_set:
3880  {
3881  Assign(other);
3882  break;
3883  }
3884  case e_Null:
3885  {
3886  // ??? skip if other is null?
3887  x_ChangeToMix(other);
3888  break;
3889  }
3890  case e_Empty:
3891  {
3892  // ??? skip if other is empty and ids match?
3893  x_ChangeToMix(other);
3894  break;
3895  }
3896 
3897  case e_Whole:
3898  {
3899  x_ChangeToMix(other);
3900  break;
3901  }
3902  case e_Int:
3903  {
3904  if ( other.IsInt() || other.IsPacked_int() ) {
3905  x_ChangeToPackedInt(other);
3906  } else {
3907  x_ChangeToMix(other);
3908  }
3909  }
3910  break;
3911  case e_Pnt:
3912  {
3913  if ( s_CanAdd(*this, other) ) {
3914  x_ChangeToPackedPnt(other);
3915  } else {
3916  x_ChangeToMix(other);
3917  }
3918  break;
3919  }
3920  case e_Packed_int:
3921  {
3922  if ( other.IsInt() ) {
3923  SetPacked_int().AddInterval(other.GetInt());
3924  } else if ( other.IsPacked_int() ) {
3926  } else {
3927  x_ChangeToMix(other);
3928  }
3929  break;
3930  }
3931  case e_Packed_pnt:
3932  {
3933  if ( s_CanAdd(*this, other) ) {
3934  if ( other.IsPnt() ) {
3935  SetPacked_pnt().AddPoint(other.GetPnt().GetPoint());
3936  } else if ( other.IsPacked_pnt() ) {
3938  }
3939  } else {
3940  x_ChangeToMix(other);
3941  }
3942  break;
3943  }
3944  case e_Mix:
3945  {
3946  SetMix().AddSeqLoc(other);
3947  break;
3948  }
3949  case e_Equiv:
3950  {
3951  SetEquiv().Add(other);
3952  break;
3953  }
3954  case e_Bond:
3955  {
3956  x_ChangeToMix(other);
3957  break;
3958  }
3959  case e_Feat:
3960  default:
3961  NCBI_THROW_FMT(CSeqLocException, eIncomatible,
3962  "CSeq_loc::Add(): "
3963  "cannot add sub-location to location of type: "<<
3964  SelectionName(Which()));
3965  }
3966 }
3967 
3968 
3970 {
3971  switch ( Which() ) {
3972  case e_Int:
3973  SetInt().FlipStrand();
3974  break;
3975  case e_Pnt:
3976  SetPnt().FlipStrand();
3977  break;
3978  case e_Packed_int:
3980  break;
3981  case e_Packed_pnt:
3983  break;
3984  case e_Mix:
3985  SetMix().FlipStrand();
3986  break;
3987 
3988  default:
3989  break;
3990  }
3991 }
3992 
3993 
3994 // Types used in operations with seq-locs
3995 
3996 class CRangeWithFuzz : public CSeq_loc::TRange
3997 {
3998 public:
4001 
4004  {
4005  }
4007  : TParent(it.GetRange()),
4008  m_Fuzz_from(it.GetFuzzFrom()),
4009  m_Fuzz_to(it.GetFuzzTo()),
4010  m_Strand(it.GetStrand())
4011  {
4012  }
4013 
4014  void ResetFuzzFrom(void) { m_Fuzz_from.Reset(); }
4015  void ResetFuzzTo(void) { m_Fuzz_to.Reset(); }
4016  bool IsSetFuzzFrom(void) const { return m_Fuzz_from; }
4017  bool IsSetFuzzTo(void) const { return m_Fuzz_to; }
4018  const CInt_fuzz& GetFuzzFrom(void) const { return *m_Fuzz_from; }
4019  const CInt_fuzz& GetFuzzTo(void) const { return *m_Fuzz_to; }
4020 
4021  // Add fuzzes assuming that both ranges had the same 'from'
4022  void AddFuzzFrom(const CRangeWithFuzz& rg)
4023  {
4024  x_AddFuzz(m_Fuzz_from, rg.m_Fuzz_from, rg.m_Strand);
4025  }
4026 
4027  // Add fuzzes assuming that both ranges had the same 'to'
4028  void AddFuzzTo(const CRangeWithFuzz& rg)
4029  {
4030  x_AddFuzz(m_Fuzz_to, rg.m_Fuzz_to, rg.m_Strand);
4031  }
4032 
4033  void AddFuzzFrom(const CInt_fuzz& fuzz, ENa_strand strand)
4034  {
4035  x_AddFuzz(m_Fuzz_from, ConstRef(&fuzz), strand);
4036  }
4037 
4038  void AddFuzzTo(const CInt_fuzz& fuzz, ENa_strand strand)
4039  {
4040  x_AddFuzz(m_Fuzz_to, ConstRef(&fuzz), strand);
4041  }
4042 
4043  void CopyFrom(const CRangeWithFuzz& rg)
4044  {
4045  SetFrom(rg.GetFrom());
4046  m_Fuzz_from = rg.m_Fuzz_from;
4047  }
4048 
4049  void CopyTo(const CRangeWithFuzz& rg)
4050  {
4051  SetTo(rg.GetTo());
4052  m_Fuzz_to = rg.m_Fuzz_to;
4053  }
4054 
4055  CRangeWithFuzz& operator +=(const CRangeWithFuzz& rg)
4056  {
4057  TParent::position_type old_from = GetFrom();
4058  TParent::position_type old_to = GetTo();
4059  TParent::operator+=(rg);
4060  if (old_from != GetFrom()) {
4061  m_Fuzz_from.Reset(rg.m_Fuzz_from);
4062  }
4063  else if (old_from == rg.GetFrom()) {
4064  // Reset fuzz if it's not the same for both ranges
4065  AddFuzzFrom(rg);
4066  }
4067  if (old_to != GetTo()) {
4068  m_Fuzz_to.Reset(rg.m_Fuzz_to);
4069  }
4070  else if (old_to == rg.GetTo()) {
4071  AddFuzzTo(rg);
4072  }
4073  return *this;
4074  }
4075 
4077  {
4078  TParent::position_type old_from = GetFrom();
4079  TParent::position_type old_to = GetTo();
4080  TParent::operator+=(rg);
4081  // Reset fuzz if the corresponding extreme changes
4082  if (old_from != GetFrom()) {
4083  ResetFuzzFrom();
4084  }
4085  if (old_to != GetTo()) {
4086  ResetFuzzTo();
4087  }
4088  return *this;
4089  }
4090 
4091 private:
4093  const CInt_fuzz* copy_from)
4094  {
4095  TFuzz copy_from_cref;
4096  if (copy_from == fuzz) copy_from_cref.Reset(copy_from);
4097  // Since TFuzz is a const-ref, setting fuzz requires creating
4098  // a new object
4099  CRef<CInt_fuzz> new_fuzz(new CInt_fuzz);
4100  // The new value is optional
4101  if ( copy_from ) {
4102  new_fuzz->Assign(*copy_from);
4103  }
4104  fuzz.Reset(new_fuzz);
4105  return new_fuzz;
4106  }
4107 
4108  void x_AddFuzz(TFuzz& fuzz,
4109  const TFuzz& other,
4110  ENa_strand other_strand)
4111  {
4112  if ( !fuzz ) {
4113  // Use fuzz from the other range if available
4114  if ( other ) {
4115  x_SetFuzz(fuzz, other.GetPointerOrNull());
4116  }
4117  return;
4118  }
4119  if ( !other ) {
4120  // The other range has no fuzz, keep the current one
4121  return;
4122  }
4123  if (fuzz->Which() != other->Which()) {
4124  // Fuzzes have different types, reset to lim-unk.
4125  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, NULL);
4126  new_fuzz->SetLim(CInt_fuzz::eLim_unk);
4127  return;
4128  }
4129 
4130  const CInt_fuzz& fz = *fuzz;
4131  const CInt_fuzz& ofz = *other;
4132  // Both fuzzes are set and have the same type, try to merge them
4133  switch ( fz.Which() ) {
4134  case CInt_fuzz::e_Lim:
4135  {
4136  CInt_fuzz::ELim this_lim = fz.GetLim();
4137  CInt_fuzz::ELim other_lim = ofz.GetLim();
4138  bool this_rev = IsReverse(m_Strand);
4139  bool other_rev = IsReverse(other_strand);
4140  bool other_lt = other_lim == CInt_fuzz::eLim_lt ||
4141  (!other_rev && other_lim == CInt_fuzz::eLim_tl) ||
4142  (other_rev && other_lim == CInt_fuzz::eLim_tr);
4143  bool other_gt = other_lim == CInt_fuzz::eLim_gt ||
4144  (!other_rev && other_lim == CInt_fuzz::eLim_tr) ||
4145  (other_rev && other_lim == CInt_fuzz::eLim_tl);
4146  switch ( fz.GetLim() ) {
4147  case CInt_fuzz::eLim_lt:
4148  if ( other_lt ) {
4149  return; // the same
4150  }
4151  break;
4152  case CInt_fuzz::eLim_gt:
4153  if ( other_gt ) {
4154  return; // the same
4155  }
4156  break;
4157  case CInt_fuzz::eLim_tl:
4158  if ((!this_rev && other_lt) ||
4159  (this_rev && other_gt)) {
4160  return; // the same
4161  }
4162  break;
4163  case CInt_fuzz::eLim_tr:
4164  if ((!this_rev && other_gt) ||
4165  (this_rev && other_lt)) {
4166  return; // the same
4167  }
4168  break;
4169  default:
4170  if (other_lim == this_lim) {
4171  return;
4172  }
4173  break;
4174  }
4175  // Different limits - reset to lim-unk.
4176  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, NULL);
4177  new_fuzz->SetLim(CInt_fuzz::eLim_unk);
4178  break;
4179  }
4180  case CInt_fuzz::e_Alt:
4181  {
4182  // Use union
4183  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, fuzz);
4184  new_fuzz->SetAlt().insert(
4185  new_fuzz->SetAlt().end(),
4186  ofz.GetAlt().begin(),
4187  ofz.GetAlt().end());
4188  break;
4189  }
4190  case CInt_fuzz::e_Range:
4191  {
4192  // Use union
4194  CInt_fuzz::C_Range::TMin min2 = ofz.GetRange().GetMin();
4196  CInt_fuzz::C_Range::TMax max2 = ofz.GetRange().GetMax();
4197  if (min1 > min2 || max1 < max2) {
4198  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, NULL);
4199  new_fuzz->SetRange().SetMin(min1 < min2 ? min1 : min2);
4200  new_fuzz->SetRange().SetMax(max1 > max2 ? max1 : max2);
4201  }
4202  break;
4203  }
4204  case CInt_fuzz::e_P_m:
4205  {
4206  // Use max value
4207  CInt_fuzz::TP_m pm = ofz.GetP_m();
4208  if (fz.GetP_m() < pm) {
4209  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, NULL);
4210  new_fuzz->SetP_m(pm);
4211  }
4212  break;
4213  }
4214  case CInt_fuzz::e_Pct:
4215  {
4216  // Use max value
4217  CInt_fuzz::TPct pct = ofz.GetPct();
4218  if (fz.GetPct() < pct) {
4219  CRef<CInt_fuzz> new_fuzz = x_SetFuzz(fuzz, NULL);
4220  new_fuzz->SetPct(pct);
4221  }
4222  break;
4223  }
4224  default:
4225  // Failed to merge fuzzes
4226  fuzz.Reset();
4227  break;
4228  }
4229  }
4230 
4234 };
4235 
4236 
4237 class CSeq_id_Handle_Wrapper
4238 {
4239 public:
4241 
4243  : m_Handle(idh)
4244  {
4245  if (id.IsLocal() && id.GetLocal().IsStr()) {
4246  m_Id.Reset(&id);
4247  }
4248  }
4249 
4250  CConstRef<CSeq_id> GetSeqId(void) const { return m_Id ? m_Id : m_Handle.GetSeqId(); }
4251 
4252  const CSeq_id_Handle& GetHandle(void) const { return m_Handle; }
4253 
4254  bool operator== (const CSeq_id_Handle_Wrapper& handle) const
4255  {
4256  return m_Handle == handle.m_Handle;
4257  }
4258 
4259  bool operator!= (const CSeq_id_Handle_Wrapper& handle) const
4260  {
4261  return m_Handle != handle.m_Handle;
4262  }
4263  bool operator< (const CSeq_id_Handle_Wrapper& handle) const
4264  {
4265  return m_Handle < handle.m_Handle;
4266  }
4267 
4269 
4270 private:
4273 };
4274 
4275 
4276 typedef CRangeWithFuzz TRangeWithFuzz;
4277 typedef vector<TRangeWithFuzz> TRanges;
4281 
4282 
4284 {
4285 public:
4286  CRange_Less(void) {}
4287 
4288  bool operator() (const TRangeWithFuzz& rg1, const TRangeWithFuzz& rg2) const
4289  {
4290  if ( rg1.IsWhole() ) {
4291  return !rg2.IsWhole();
4292  }
4293  if ( rg1.Empty() ) {
4294  return !rg2.Empty() && !rg2.IsWhole();
4295  }
4296  return !rg2.IsWhole() && !rg2.Empty() && rg1 < rg2;
4297  }
4298 };
4299 
4300 
4302 {
4303 public:
4305 
4306  bool operator() (const TRangeWithFuzz& rg1, const TRangeWithFuzz& rg2) const
4307  {
4308  if ( rg1.IsWhole() ) {
4309  return !rg2.IsWhole();
4310  }
4311  if ( rg1.Empty() ) {
4312  return !rg2.Empty() && !rg2.IsWhole();
4313  }
4314  if ( rg2.IsWhole() || rg2.Empty() ) {
4315  return false;
4316  }
4317  if (rg1.GetTo() != rg2.GetTo()) {
4318  return rg1.GetTo() > rg2.GetTo();
4319  }
4320  return rg1.GetFrom() < rg2.GetFrom();
4321  }
4322 };
4323 
4324 
4325 static inline
4327 {
4328  return (flags & CSeq_loc::fStrand_Ignore) != 0 ||
4329  IsReverse(str1) == IsReverse(str2);
4330 }
4331 
4332 
4333 static
4335  const TRangeWithFuzz& rg2, ENa_strand str2,
4337 {
4338  if ( !x_MatchStrand(str1, str2, flags) ) {
4339  return false;
4340  }
4341  // Check contained
4342  if ( (flags & CSeq_loc::fMerge_Contained) != 0 ) {
4343  if (rg1.GetFrom() <= rg2.GetFrom() && rg1.GetTo() >= rg2.GetTo()) {
4344  // rg2 already contained in rg1
4345  if (rg1.GetFrom() == rg2.GetFrom()) {
4346  rg1.AddFuzzFrom(rg2);
4347  }
4348  if (rg1.GetTo() == rg2.GetTo()) {
4349  rg1.AddFuzzTo(rg2);
4350  }
4351  return true;
4352  }
4353  if (rg1.GetFrom() >= rg2.GetFrom() && rg1.GetTo() <= rg2.GetTo()) {
4354  // rg1 contained in rg2
4355  bool same_from = rg1.GetFrom() == rg2.GetFrom();
4356  bool same_to = rg1.GetTo() == rg2.GetTo();
4357  rg1 = rg2;
4358  if (same_from) {
4359  rg1.AddFuzzFrom(rg2);
4360  }
4361  if (same_to) {
4362  rg1.AddFuzzTo(rg2);
4363  }
4364  return true;
4365  }
4366  }
4367  // Check overlapping
4368  if ( (flags & CSeq_loc::fMerge_OverlappingOnly) != 0 &&
4369  rg1.IntersectingWith(rg2) ) {
4370  rg1 += rg2;
4371  return true;
4372  }
4373  // Check abutting
4374  if ((flags & CSeq_loc::fMerge_AbuttingOnly) != 0) {
4375  if ( !IsReverse(str1) ) {
4376  if ( rg1.GetToOpen() == rg2.GetFrom() ) {
4377  rg1.CopyTo(rg2);
4378  return true;
4379  }
4380  }
4381  else {
4382  if (rg1.GetFrom() == rg2.GetToOpen()) {
4383  rg1.CopyFrom(rg2);
4384  return true;
4385  }
4386  }
4387  }
4388  return false;
4389 }
4390 
4391 
4392 static
4394  const CSeq_id_Handle_Wrapper& idh,
4395  const TRangeWithFuzz& rg,
4396  ENa_strand strand)
4397 {
4398  if (dst.Which() != CSeq_loc::e_not_set) {
4399  if ( !dst.IsMix() ) {
4400  dst.ChangeToMix();
4401  }
4402  }
4403  if ( !idh ) {
4404  // NULL
4405  if (dst.IsMix()) {
4406  dst.SetMix().Set().push_back(Ref(new CSeq_loc(CSeq_loc::e_Null)));
4407  }
4408  else {
4409  dst.SetNull();
4410  }
4411  return;
4412  }
4413  CRef<CSeq_id> id(new CSeq_id());
4414  id->Assign(*idh.GetSeqId());
4415  if ( rg.IsWhole() ) {
4416  if (dst.IsMix()) {
4418  whole->SetWhole(*id);
4419  dst.SetMix().Set().push_back(whole);
4420  }
4421  else {
4422  dst.SetWhole(*id);
4423  }
4424  }
4425  else if ( rg.Empty() ) {
4426  if (dst.IsMix()) {
4428  empty->SetEmpty(*id);
4429  dst.SetMix().Set().push_back(empty);
4430  }
4431  else {
4432  dst.SetEmpty(*id);
4433  }
4434  }
4435  else if ( rg.GetLength() == 1 &&
4436  rg.IsSetFuzzFrom() == rg.IsSetFuzzTo() &&
4437  ( !rg.IsSetFuzzFrom() ||
4438  rg.GetFuzzFrom().Equals(rg.GetFuzzTo()) ) )
4439  {
4440  // Preserve points
4441  CRef<CSeq_point> pnt(new CSeq_point);
4442  pnt->SetId(*id);
4443  pnt->SetPoint(rg.GetFrom());
4444  if (strand != eNa_strand_unknown) {
4445  pnt->SetStrand(strand);
4446  }
4447  if ( rg.IsSetFuzzFrom() ) {
4448  pnt->SetFuzz().Assign(rg.GetFuzzFrom());
4449  } else if( rg.IsSetFuzzTo() ) {
4450  pnt->SetFuzz().Assign(rg.GetFuzzTo());
4451  }
4452  if (dst.IsMix()) {
4453  CRef<CSeq_loc> pnt_loc(new CSeq_loc);
4454  pnt_loc->SetPnt(*pnt);
4455  dst.SetMix().Set().push_back(pnt_loc);
4456  }
4457  else {
4458  dst.SetPnt(*pnt);
4459  }
4460  }
4461  else {
4462  if (dst.IsMix()) {
4463  CRef<CSeq_loc> int_loc(new CSeq_loc);
4464  CSeq_interval& ival = int_loc->SetInt();
4465  ival.SetFrom(rg.GetFrom());
4466  ival.SetTo(rg.GetTo());
4467  ival.SetId().Assign(*id);
4468  if (strand != eNa_strand_unknown) {
4469  ival.SetStrand(strand);
4470  }
4471  if ( rg.IsSetFuzzFrom() ) {
4472  ival.SetFuzz_from().Assign(rg.GetFuzzFrom());
4473  }
4474  if ( rg.IsSetFuzzTo() ) {
4475  ival.SetFuzz_to().Assign(rg.GetFuzzTo());
4476  }
4477  dst.SetMix().Set().push_back(int_loc);
4478  }
4479  else {
4480  CRef<CSeq_interval> interval(new CSeq_interval(*id,
4481  rg.GetFrom(),
4482  rg.GetTo(),
4483  strand));
4484  if ( rg.IsSetFuzzFrom() ) {
4485  interval->SetFuzz_from().Assign(rg.GetFuzzFrom());
4486  }
4487  if ( rg.IsSetFuzzTo() ) {
4488  interval->SetFuzz_to().Assign(rg.GetFuzzTo());
4489  }
4490  dst.SetInt(*interval);
4491  }
4492  }
4493 }
4494 
4495 
4496 static
4498  const CSeq_loc& src,
4499  ISynonymMapper& syn_mapper)
4500 {
4501  // Create a single range
4502  TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty());
4503  CSeq_id_Handle_Wrapper first_id;
4504  ENa_strand first_strand = eNa_strand_unknown;
4505  for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4506  CSeq_id_Handle_Wrapper next_id(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4507  if ( !next_id ) {
4508  // Ignore NULLs
4509  continue;
4510  }
4511  if ( first_id ) {
4512  // Seq-id may be missing for NULL seq-loc
4513  if (next_id && first_id != next_id) {
4514  NCBI_THROW(CSeqLocException, eMultipleId,
4515  "Can not merge multi-id seq-loc");
4516  }
4517  }
4518  else {
4519  first_id = next_id;
4520  first_strand = it.GetStrand();
4521  }
4522  total_rg += TRangeWithFuzz(it);
4523  }
4524  if ( first_id ) {
4525  CRef<CSeq_id> id(new CSeq_id);
4526  id->Assign(*first_id.GetSeqId());
4527  CRef<CSeq_interval> interval(new CSeq_interval(*id,
4528  total_rg.GetFrom(),
4529  total_rg.GetTo(),
4530  first_strand));
4531  if ( total_rg.IsSetFuzzFrom() ) {
4532  interval->SetFuzz_from().Assign(total_rg.GetFuzzFrom());
4533  }
4534  if ( total_rg.IsSetFuzzTo() ) {
4535  interval->SetFuzz_to().Assign(total_rg.GetFuzzTo());
4536  }
4537  dst.SetInt(*interval);
4538  }
4539  else {
4540  // Null seq-loc
4541  dst.SetNull();
4542  }
4543 }
4544 
4545 
4546 static
4548  TIdToRangeMap& id_map,
4549  ENa_strand default_strand,
4551 {
4552  // Iterate ids for each strand
4553  NON_CONST_ITERATE(TIdToRangeMap, id_it, id_map) {
4554  if ( !id_it->first ) {
4555  // All NULLs merged
4556  x_PushRange(dst,
4557  id_it->first,
4558  TRangeWithFuzz(TRangeWithFuzz::GetEmpty()),
4560  continue;
4561  }
4562  CRef<CSeq_id> id(new CSeq_id);
4563  id->Assign(*id_it->first.GetSeqId());
4564  TRanges& ranges = id_it->second;
4565  if ( (flags & CSeq_loc::fSort) != 0 ) {
4566  if ( !IsReverse(default_strand) ) {
4567  sort(ranges.begin(), ranges.end(), CRange_Less());
4568  }
4569  else {
4570  sort(ranges.begin(), ranges.end(), CRange_ReverseLess());
4571  }
4572  }
4573  // Merge ranges according to the flags, add to destination
4574  TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
4575  bool have_range = false;
4576  ITERATE(TRanges, rg, ranges) {
4577  if (x_MergeRanges(last_rg, default_strand,
4578  *rg, default_strand,
4579  flags)) {
4580  have_range = true;
4581  continue;
4582  }
4583  // No merging - push current range, reset last values
4584  if (have_range) {
4585  x_PushRange(dst, id_it->first, last_rg, default_strand);
4586  }
4587  last_rg = *rg;
4588  have_range = true;
4589  }
4590  if (have_range) {
4591  x_PushRange(dst, id_it->first, last_rg, default_strand);
4592  }
4593  }
4594 }
4595 
4596 
4597 static
4599  const CSeq_loc& src,
4601  ISynonymMapper& syn_mapper)
4602 {
4603  _ASSERT((flags & CSeq_loc::fSort) == 0);
4604  CSeq_id_Handle_Wrapper last_id;
4605  TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
4606  ENa_strand last_strand = eNa_strand_unknown;
4607  bool have_range = false;
4608  for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4609  CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4610  // ID and strand must match
4611  TRangeWithFuzz it_rg(it);
4612  if ( have_range && last_id == idh ) {
4613  if (x_MergeRanges(last_rg,
4614  last_strand,
4615  it_rg,
4616  it.GetStrand(),
4617  flags)) {
4618  have_range = true;
4619  continue;
4620  }
4621  }
4622  // No merging - push current range, reset last values
4623  if ( have_range ) {
4624  x_PushRange(dst, last_id, last_rg, last_strand);
4625  }
4626  last_id = idh;
4627  last_rg = it_rg;
4628  last_strand = it.GetStrand();
4629  have_range = true;
4630  }
4631  if ( have_range ) {
4632  x_PushRange(dst, last_id, last_rg, last_strand);
4633  }
4634  if (dst.Which() == CSeq_loc::e_not_set) {
4635  dst.SetNull();
4636  }
4637 }
4638 
4639 
4640 static
4642  const CSeq_loc& src,
4644  ISynonymMapper& syn_mapper)
4645 {
4646  bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
4647  // Id -> range map for both strands
4648  unique_ptr<TIdToRangeMap> pid_map_minus(use_strand ?
4649  new TIdToRangeMap : 0);
4650  TIdToRangeMap id_map_plus;
4651  TIdToRangeMap& id_map_minus = use_strand ?
4652  *pid_map_minus.get() : id_map_plus;
4653 
4654  // Prepare default strands
4655  ENa_strand default_plus = eNa_strand_unknown;
4656  ENa_strand default_minus = eNa_strand_unknown;
4657 
4658  // Split location by by id/strand/range
4659  for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4660  CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4661  ENa_strand strand = it.GetStrand();
4662  if ( IsReverse(strand) ) {
4663  id_map_minus[idh].push_back(TRangeWithFuzz(it));
4664  if (use_strand) {
4665  if (default_minus == eNa_strand_unknown) {
4666  default_minus = strand;
4667  }
4668  else if (default_minus != strand) {
4669  default_minus = eNa_strand_minus;
4670  }
4671  }
4672  }
4673  else {
4674  id_map_plus[idh].push_back(TRangeWithFuzz(it));
4675  if (use_strand) {
4676  if (default_plus == eNa_strand_unknown) {
4677  default_plus = strand;
4678  }
4679  else if (default_plus != strand) {
4680  default_plus = eNa_strand_plus;
4681  }
4682  }
4683  }
4684  }
4685 
4686  x_RangesToSeq_loc(dst, id_map_plus, default_plus, flags);
4687  if ( use_strand ) {
4688  x_RangesToSeq_loc(dst, id_map_minus, default_minus, flags);
4689  }
4690  if (dst.Which() == CSeq_loc::e_not_set) {
4691  dst.SetNull();
4692  }
4693 }
4694 
4695 
4697 
4698 static
4700  const CSeq_loc& minuend,
4701  const TFuzzMap& fuzz_from_plus,
4702  const TFuzzMap& fuzz_from_minus,
4703  const TFuzzMap& fuzz_to_plus,
4704  const TFuzzMap& fuzz_to_minus,
4705  TIdToRangeColl& rg_coll_plus,
4706  TIdToRangeColl& rg_coll_minus,
4707  ISynonymMapper& syn_mapper,
4708  ILengthGetter& len_getter)
4709 {
4710  TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty());
4711  CSeq_id_Handle_Wrapper first_id;
4712  ENa_strand first_strand = eNa_strand_unknown;
4713  for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4714  CSeq_id_Handle_Wrapper next_id(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4715  if ( !next_id ) {
4716  // Ignore NULLs
4717  continue;
4718  }
4719  if ( first_id ) {
4720  // Seq-id may be missing for NULL seq-loc
4721  if (next_id && first_id != next_id) {
4722  NCBI_THROW(CSeqLocException, eMultipleId,
4723  "Can not merge multi-id seq-loc");
4724  }
4725  }
4726  else {
4727  first_id = next_id;
4728  first_strand = it.GetStrand();
4729  }
4730  TRangeWithFuzz it_range = TRangeWithFuzz(it);
4731  if (it_range.GetFrom() >= total_rg.GetFrom() &&
4732  it_range.GetTo() <= total_rg.GetTo()) {
4733  // Nothing new can be added from this interval
4734  continue;
4735  }
4736  if ( it_range.IsWhole() ) {
4737  it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
4738  it_range.ResetFuzzFrom();
4739  it_range.ResetFuzzTo();
4740  }
4741  TRangeColl it_rg_coll(it_range);
4742  TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
4743  rg_coll_minus : rg_coll_plus;
4744  TIdToRangeColl::const_iterator id_it = rg_coll.find(next_id);
4745  if (id_it != rg_coll.end()) {
4746  it_rg_coll -= id_it->second;
4747  }
4748  TRangeWithFuzz curr_rg(it_rg_coll.GetLimits());
4749  if (curr_rg.GetFrom() == it_range.GetFrom()) {
4750  curr_rg.AddFuzzFrom(it_range);
4751  }
4752  if (curr_rg.GetTo() == it_range.GetTo()) {
4753  curr_rg.AddFuzzTo(it_range);
4754  }
4755 
4756  // If range start/stop comes from subtrahend, copy fuzz.
4757  const TFuzzMap& fm_from = IsReverse(it.GetStrand()) ? fuzz_from_minus : fuzz_from_plus;
4758  TFuzzMap::const_iterator subtr_fuzz = fm_from.find(curr_rg.GetToOpen());
4759  if (subtr_fuzz != fm_from.end()) {
4760  curr_rg.AddFuzzTo(*subtr_fuzz->second, it.GetStrand());
4761  }
4762  const TFuzzMap& fm_to = IsReverse(it.GetStrand()) ? fuzz_to_minus : fuzz_to_plus;
4763  subtr_fuzz = fm_to.find(curr_rg.GetFrom());
4764  if (subtr_fuzz != fm_to.end()) {
4765  curr_rg.AddFuzzFrom(*subtr_fuzz->second, it.GetStrand());
4766  }
4767 
4768  total_rg += curr_rg;
4769  }
4770 
4771  if ( first_id ) {
4772  CRef<CSeq_id> id(new CSeq_id);
4773  id->Assign(*first_id.GetSeqId());
4774  CRef<CSeq_interval> interval(new CSeq_interval(*id,
4775  total_rg.GetFrom(),
4776  total_rg.GetTo(),
4777  first_strand));
4778  if ( total_rg.IsSetFuzzFrom() ) {
4779  CRef<CInt_fuzz> fuzz(new CInt_fuzz);
4780  fuzz->Assign(total_rg.GetFuzzFrom());
4781  interval->SetFuzz_from(*fuzz);
4782  }
4783  if ( total_rg.IsSetFuzzTo() ) {
4784  CRef<CInt_fuzz> fuzz(new CInt_fuzz);
4785  fuzz->Assign(total_rg.GetFuzzTo());
4786  interval->SetFuzz_to(*fuzz);
4787  }
4788  dst.SetInt(*interval);
4789  }
4790  else {
4791  // Null seq-loc
4792  dst.SetNull();
4793  }
4794 }
4795 
4796 
4797 static
4799  const CSeq_loc& minuend,
4800  const TFuzzMap& fuzz_from_plus,
4801  const TFuzzMap& fuzz_from_minus,
4802  const TFuzzMap& fuzz_to_plus,
4803  const TFuzzMap& fuzz_to_minus,
4804  TIdToRangeColl& rg_coll_plus,
4805  TIdToRangeColl& rg_coll_minus,
4806  ISynonymMapper& syn_mapper,
4807  ILengthGetter& len_getter,
4809 {
4810  _ASSERT((flags & CSeq_loc::fSort) == 0);
4811  CSeq_id_Handle_Wrapper last_id;
4812  TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty());
4813  ENa_strand last_strand = eNa_strand_unknown;
4814  bool have_range = false;
4815  for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4816  CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4817  bool rev = IsReverse(it.GetStrand());
4818  TRangeWithFuzz it_range = TRangeWithFuzz(it);
4819  if ( it_range.IsWhole() ) {
4820  it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
4821  }
4822  TRangeColl it_rg_coll(it_range);
4823  TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
4824  rg_coll_minus : rg_coll_plus;
4825  TIdToRangeColl::const_iterator id_it = rg_coll.find(idh);
4826  list<TRangeWithFuzz> result_ranges;
4827  bool modified = false;
4828  if (id_it != rg_coll.end()) {
4829  // Check if there's anything to subtract
4830  ITERATE(TRangeColl, check_it, id_it->second) {
4831  if ( it_rg_coll.IntersectingWith(*check_it) ) {
4832  it_rg_coll -= id_it->second;
4833  modified = true;
4834  ITERATE(TRangeColl, result_it, it_rg_coll) {
4835  if ( rev ) {
4836  result_ranges.push_front(*result_it);
4837  }
4838  else {
4839  result_ranges.push_back(*result_it);
4840  }
4841  }
4842  break;
4843  }
4844  }
4845  }
4846  if ( modified ) {
4847  ITERATE(list<TRangeWithFuzz>, rg_it, result_ranges) {
4848  TRangeWithFuzz curr_rg(*rg_it);
4849  if (curr_rg.GetFrom() == it_range.GetFrom()) {
4850  curr_rg.AddFuzzFrom(it_range);
4851  }
4852  if (curr_rg.GetTo() == it_range.GetTo()) {
4853  curr_rg.AddFuzzTo(it_range);
4854  }
4855 
4856  // If range start/stop comes from subtrahend, copy fuzz.
4857  const TFuzzMap& fm_from = IsReverse(it.GetStrand()) ? fuzz_from_minus : fuzz_from_plus;
4858  TFuzzMap::const_iterator subtr_fuzz = fm_from.find(curr_rg.GetToOpen());
4859  if (subtr_fuzz != fm_from.end()) {
4860  curr_rg.AddFuzzTo(*subtr_fuzz->second, it.GetStrand());
4861  }
4862  const TFuzzMap& fm_to = IsReverse(it.GetStrand()) ? fuzz_to_minus : fuzz_to_plus;
4863  subtr_fuzz = fm_to.find(curr_rg.GetFrom());
4864  if (subtr_fuzz != fm_to.end()) {
4865  curr_rg.AddFuzzFrom(*subtr_fuzz->second, it.GetStrand());
4866  }
4867 
4868  if ( have_range && last_id == idh ) {
4869  if (x_MergeRanges(last_rg,
4870  last_strand,
4871  curr_rg,
4872  it.GetStrand(),
4873  flags)) {
4874  have_range = true;
4875  continue;
4876  }
4877  }
4878  // No merging - push current range, reset last values
4879  if ( have_range ) {
4880  x_PushRange(dst, last_id, last_rg, last_strand);
4881  }
4882  last_id = idh;
4883  last_rg = curr_rg;
4884  last_strand = it.GetStrand();
4885  have_range = true;
4886  }
4887  }
4888  else {
4889  if ( have_range ) {
4890  bool merged = false;
4891  if (last_id == idh) {
4892  merged = x_MergeRanges(last_rg,
4893  last_strand,
4894  it_range,
4895  it.GetStrand(),
4896  flags);
4897  }
4898  if ( !merged ) {
4899  x_PushRange(dst, last_id, last_rg, last_strand);
4900  }
4901  }
4902  last_id = idh;
4903  last_rg = it_range;
4904  last_strand = it.GetStrand();
4905  have_range = true;
4906  }
4907  }
4908  if ( have_range ) {
4909  x_PushRange(dst, last_id, last_rg, last_strand);
4910  }
4911  if (dst.Which() == CSeq_loc::e_not_set) {
4912  dst.SetNull();
4913  }
4914 }
4915 
4916 
4917 static
4919  const CSeq_loc& minuend,
4920  const TFuzzMap& fuzz_from_plus,
4921  const TFuzzMap& fuzz_from_minus,
4922  const TFuzzMap& fuzz_to_plus,
4923  const TFuzzMap& fuzz_to_minus,
4924  TIdToRangeColl& rg_coll_plus,
4925  TIdToRangeColl& rg_coll_minus,
4926  ISynonymMapper& syn_mapper,
4927  ILengthGetter& len_getter,
4929 {
4930  bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
4931 
4932  // Id -> range map for both strands
4933  unique_ptr<TIdToRangeMap> p_id_map_minus(use_strand ?
4934  new TIdToRangeMap : 0);
4935  TIdToRangeMap id_map_plus;
4936  TIdToRangeMap& id_map_minus = use_strand ?
4937  *p_id_map_minus.get() : id_map_plus;
4938 
4939  // Prepare default strands
4940  ENa_strand default_plus = use_strand ?
4942  ENa_strand default_minus = use_strand ?
4944 
4945  for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) {
4946  CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
4947  TRangeWithFuzz it_range = TRangeWithFuzz(it);
4948  if ( it_range.IsWhole() ) {
4949  it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id()));
4950  it_range.ResetFuzzFrom();
4951  it_range.ResetFuzzTo();
4952  }
4953  TRangeColl it_rg_coll(it_range);
4954  TRanges& rg_map = IsReverse(it.GetStrand()) ?
4955  id_map_minus[idh] : id_map_plus[idh];
4956  TIdToRangeColl& rg_coll = IsReverse(it.GetStrand()) ?
4957  rg_coll_minus : rg_coll_plus;
4958  TIdToRangeColl::const_iterator id_it = rg_coll.find(idh);
4959  bool modified = false;
4960  if (id_it != rg_coll.end()) {
4961  // Check if there's anything to subtract
4962  ITERATE(TRangeColl, check_it, id_it->second) {
4963  if ( it_rg_coll.IntersectingWith(*check_it) ) {
4964  it_rg_coll -= id_it->second;
4965  modified = true;
4966  break;
4967  }
4968  }
4969  }
4970  if ( modified ) {
4971  ITERATE(TRangeColl, rg_it, it_rg_coll) {
4972  TRangeWithFuzz curr_rg(*rg_it);
4973  // If range start/stop comes from the minuend, preserve strand.
4974  if (curr_rg.GetFrom() == it_range.GetFrom()) {
4975  curr_rg.AddFuzzFrom(it_range);
4976  }
4977  if (curr_rg.GetTo() == it_range.GetTo()) {
4978  curr_rg.AddFuzzTo(it_range);
4979  }
4980 
4981  // If range start/stop comes from subtrahend, copy fuzz.
4982  const TFuzzMap& fm_from = IsReverse(it.GetStrand()) ? fuzz_from_minus : fuzz_from_plus;
4983  TFuzzMap::const_iterator subtr_fuzz = fm_from.find(curr_rg.GetToOpen());
4984  if (subtr_fuzz != fm_from.end()) {
4985  curr_rg.AddFuzzTo(*subtr_fuzz->second, it.GetStrand());
4986  }
4987  const TFuzzMap& fm_to = IsReverse(it.GetStrand()) ? fuzz_to_minus : fuzz_to_plus;
4988  subtr_fuzz = fm_to.find(curr_rg.GetFrom());
4989  if (subtr_fuzz != fm_to.end()) {
4990  curr_rg.AddFuzzFrom(*subtr_fuzz->second, it.GetStrand());
4991  }
4992 
4993  rg_map.push_back(curr_rg);
4994  }
4995  }
4996  else {
4997  rg_map.push_back(it_range);
4998  }
4999  }
5000 
5001  x_RangesToSeq_loc(dst, id_map_plus, default_plus, flags);
5002  if ( use_strand ) {
5003  x_RangesToSeq_loc(dst, id_map_minus, default_minus, flags);
5004  }
5005  if (dst.Which() == CSeq_loc::e_not_set) {
5006  dst.SetNull();
5007  }
5008 }
5009 
5010 
5012 {
5013 public:
5015  virtual ~CDummySynonymMapper(void) {}
5016 
5018  {
5019  return CSeq_id_Handle::GetHandle(id);
5020  }
5021 };
5022 
5023 
5025 {
5026 public:
5028  virtual ~CDummyLengthGetter(void) {}
5029 
5030  virtual TSeqPos GetLength(const CSeq_id&)
5031  {
5033  }
5034 };
5035 
5036 
5038  ISynonymMapper* syn_mapper) const
5039 {
5040  unique_ptr<CDummySynonymMapper> p_mapper;
5041  if ( !syn_mapper ) {
5042  p_mapper.reset(new CDummySynonymMapper);
5043  syn_mapper = p_mapper.get();
5044  }
5045 
5046  CRef<CSeq_loc> ret(new CSeq_loc);
5047  if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
5048  x_SingleRange(*ret, *this, *syn_mapper);
5049  }
5050  else if ( (flags & CSeq_loc::fSort) == 0 ) {
5051  x_MergeNoSort(*ret, *this, flags, *syn_mapper);
5052  }
5053  else {
5054  x_MergeAndSort(*ret, *this, flags, *syn_mapper);
5055  }
5056  return ret;
5057 }
5058 
5059 
5061  TOpFlags flags,
5062  ISynonymMapper* syn_mapper) const
5063 {
5064  unique_ptr<CDummySynonymMapper> p_mapper;
5065  if ( !syn_mapper ) {
5066  p_mapper.reset(new CDummySynonymMapper);
5067  syn_mapper = p_mapper.get();
5068  }
5069 
5070  CRef<CSeq_loc> ret(new CSeq_loc);
5071  CSeq_loc tmp;
5072  tmp.SetMix().AddSeqLoc(const_cast<CSeq_loc&>(*this));
5073  tmp.SetMix().AddSeqLoc(const_cast<CSeq_loc&>(other));
5074  if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
5075  x_SingleRange(*ret, tmp, *syn_mapper);
5076  }
5077  else if ( (flags & CSeq_loc::fSort) == 0 ) {
5078  x_MergeNoSort(*ret, tmp, flags, *syn_mapper);
5079  }
5080  else {
5081  x_MergeAndSort(*ret, tmp, flags, *syn_mapper);
5082  }
5083  return ret;
5084 }
5085 
5086 
5088  TOpFlags flags,
5089  ISynonymMapper* syn_mapper,
5090  ILengthGetter* len_getter) const
5091 {
5092  unique_ptr<CDummySynonymMapper> p_mapper;
5093  if ( !syn_mapper ) {
5094  p_mapper.reset(new CDummySynonymMapper);
5095  syn_mapper = p_mapper.get();
5096  }
5097  unique_ptr<CDummyLengthGetter> p_getter;
5098  if ( !len_getter ) {
5099  p_getter.reset(new CDummyLengthGetter);
5100  len_getter = p_getter.get();
5101  }
5102 
5103  CRef<CSeq_loc> ret(new CSeq_loc);
5104 
5105  bool use_strand = (flags & CSeq_loc::fStrand_Ignore) == 0;
5106 
5107  // Range collection for each strand
5108  unique_ptr<TIdToRangeColl> p_rg_coll_minus(use_strand ?
5109  new TIdToRangeColl : 0);
5110  TIdToRangeColl rg_coll_plus;
5111  TIdToRangeColl& rg_coll_minus = use_strand ?
5112  *p_rg_coll_minus.get() : rg_coll_plus;
5113 
5114  // Collect fuzzes so that they can be copied to the new ranges after subtracting.
5115  // Note: if there are multiple ranges with the same boundaries only the last
5116  // fuzz found will be used.
5117  TFuzzMap fuzz_from_plus, fuzz_from_minus, fuzz_to_plus, fuzz_to_minus;
5118 
5119  // Create range collection(s) for loc2
5120  for (CSeq_loc_CI it(other); it; ++it) {
5121  if ( it.IsEmpty() ) {
5122  continue;
5123  }
5124  CSeq_id_Handle_Wrapper idh(syn_mapper->GetBestSynonym(it.GetSeq_id()), it.GetSeq_id());
5125  TRangeColl& rmap = IsReverse(it.GetStrand()) ?
5126  rg_coll_minus[idh] : rg_coll_plus[idh];
5127  rmap += TRangeWithFuzz(it);
5128 
5129  const CInt_fuzz* fuzz = it.GetFuzzFrom();
5130  if ( fuzz ) {
5131  if (it.IsSetStrand() && IsReverse(it.GetStrand())) {
5132  fuzz_from_minus[it.GetRange().GetFrom()].Reset(fuzz);
5133  }
5134  else {
5135  fuzz_from_plus[it.GetRange().GetFrom()].Reset(fuzz);
5136  }
5137  }
5138  fuzz = it.GetFuzzTo();
5139  if ( fuzz ) {
5140  if (it.IsSetStrand() && IsReverse(it.GetStrand())) {
5141  fuzz_to_minus[it.GetRange().GetToOpen()].Reset(fuzz);
5142  }
5143  else {
5144  fuzz_to_plus[it.GetRange().GetToOpen()].Reset(fuzz);
5145  }
5146  }
5147  }
5148 
5149  if ( (flags & CSeq_loc::fMerge_SingleRange) != 0 ) {
5150  x_SingleRange(*ret,
5151  *this,
5152  fuzz_from_plus, fuzz_from_minus, fuzz_to_plus, fuzz_to_minus,
5153  rg_coll_plus,
5154  rg_coll_minus,
5155  *syn_mapper,
5156  *len_getter);
5157  }
5158  else if ( (flags & CSeq_loc::fSort) == 0 ) {
5159  x_SubNoSort(*ret,
5160  *this,
5161  fuzz_from_plus, fuzz_from_minus, fuzz_to_plus, fuzz_to_minus,
5162  rg_coll_plus,
5163  rg_coll_minus,
5164  *syn_mapper,
5165  *len_getter,
5166  flags);
5167  }
5168  else {
5169  x_SubAndSort(*ret,
5170  *this,
5171  fuzz_from_plus, fuzz_from_minus, fuzz_to_plus, fuzz_to_minus,
5172  rg_coll_plus,
5173  rg_coll_minus,
5174  *syn_mapper,
5175  *len_getter,
5176  flags);
5177  }
5178 
5179  return ret;
5180 }
5181 
5182 
5184  TOpFlags flags,
5185  ISynonymMapper* syn_mapper) const
5186 {
5187  unique_ptr<CDummyLengthGetter> len_getter(new CDummyLengthGetter);
5188  CRef<CSeq_loc> tmp = Subtract(other,
5189  // This flag should be used only in the second subtraction
5191  syn_mapper, len_getter.get());
5192  return Subtract(*tmp, flags, syn_mapper, len_getter.get());
5193 }
5194 
5195 
5197 {
5198  switch ( Which() ) {
5199  case e_Int:
5200  SetInt().SetStrand(strand);
5201  break;
5202  case e_Pnt:
5203  SetPnt().SetStrand(strand);
5204  break;
5205  case e_Packed_int:
5206  SetPacked_int().SetStrand(strand);
5207  break;
5208  case e_Packed_pnt:
5209  SetPacked_pnt().SetStrand(strand);
5210  break;
5211  case e_Mix:
5212  SetMix().SetStrand(strand);
5213  break;
5214 
5215  default:
5216  break;
5217  }
5218 }
5219 
5220 
5222 {
5223  switch ( Which() ) {
5224  case e_Int:
5225